@capxul/sdk 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1147 @@
1
+ import { Account as Account$1 } from 'viem';
2
+ import { AnyStateMachine } from 'xstate';
3
+ import { AccountId, SafeId, KycProfileId, ExternalAccountId, SubAccountId, OrganizationId, ApiKeyId, TimestampIso, DocumentId, OperationId, PaymentId, TransferId, WithdrawalId, WebhookEndpointId, WebhookEventId, MemberId, KybProfileId, VirtualAccountId, VirtualCardId } from '@repo/platform-kernel';
4
+ import { CapxulResult, CapxulError } from './errors.js';
5
+ import { A as Account, U as UserIdentifier, a as AccountLookupResult, S as Safe, i as KycProfile, E as ExternalAccount, L as List, v as SubAccount, B as BalanceLedgerEntry, b as ApiKey, D as Document, O as Operation, l as OperationStatus, k as Money, C as CreatePaymentResult, o as Payment, F as TransferEndpoint, f as CreateTransferResult, y as Transfer, g as CreateWithdrawalResult, _ as Withdrawal, Y as WebhookEndpoint, Z as WebhookEvent, n as Organization, J as Treasury, M as Member, K as KybProfile, V as VirtualAccount, Q as VirtualCard } from './types-Cokyqgwm.js';
6
+ import * as types from '@repo/api-contract/gen/types';
7
+
8
+ /**
9
+ * Accounts domain — individual user accounts per sdk-surface.md §1a.
10
+ *
11
+ * Nested namespaces under `accounts.*` follow Pattern A per CANON.md
12
+ * §4.30: `accounts.safes.retrieve(safeId)`, `accounts.subAccounts.list()`,
13
+ * etc. — no ambient account context; the argument carries the scope.
14
+ */
15
+
16
+ type AccountLookupInput = UserIdentifier;
17
+ type AccountUpdateInput = Partial<{
18
+ readonly name: string;
19
+ readonly username: string;
20
+ readonly countryCode: string;
21
+ }>;
22
+ type LocalPrivateKeySignerProvider = {
23
+ readonly kind: "local-private-key";
24
+ readonly signerAddress: string;
25
+ readonly safeAddress: string;
26
+ };
27
+ type AccountProvisionPersonalInput = {
28
+ readonly displayName?: string;
29
+ readonly username?: string;
30
+ readonly countryCode?: string;
31
+ readonly signerProvider: LocalPrivateKeySignerProvider;
32
+ };
33
+ type AccountCreateKycProfileInput = {
34
+ readonly accountId: AccountId;
35
+ };
36
+ type AccountListInput = {
37
+ readonly limit?: number;
38
+ readonly cursor?: string;
39
+ };
40
+ type AccountCreateSubAccountInput = {
41
+ readonly accountId: AccountId;
42
+ readonly name: string;
43
+ };
44
+ type AccountCreateExternalAccountInput = {
45
+ readonly accountId: AccountId;
46
+ readonly kind: "bank" | "evm" | "solana" | "starknet" | "card_payout";
47
+ readonly label?: string;
48
+ readonly address?: string;
49
+ readonly iban?: string;
50
+ readonly bic?: string;
51
+ readonly accountHolder?: string;
52
+ readonly network?: "visa" | "mastercard";
53
+ readonly panToken?: string;
54
+ readonly last4?: string;
55
+ };
56
+ type RetrieveCodes$d = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
57
+ type LookupCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
58
+ type UpdateCodes$1 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "INVALID_INPUT";
59
+ type ListCodes$a = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
60
+ type SafeRetrieveCodes$1 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "SAFE_NOT_READY";
61
+ type RemoveCodes$5 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
62
+ type AccountSafesClient = {
63
+ readonly retrieve: (safeId: SafeId) => Promise<CapxulResult<Safe, SafeRetrieveCodes$1>>;
64
+ };
65
+ type AccountKycProfilesClient = {
66
+ readonly create: (input: AccountCreateKycProfileInput) => Promise<CapxulResult<KycProfile, UpdateCodes$1>>;
67
+ readonly retrieve: (kycProfileId: KycProfileId) => Promise<CapxulResult<KycProfile, RetrieveCodes$d>>;
68
+ };
69
+ type AccountExternalAccountsClient = {
70
+ readonly create: (input: AccountCreateExternalAccountInput) => Promise<CapxulResult<ExternalAccount, UpdateCodes$1>>;
71
+ readonly list: (input: {
72
+ readonly accountId: AccountId;
73
+ } & AccountListInput) => Promise<CapxulResult<List<ExternalAccount>, ListCodes$a>>;
74
+ readonly retrieve: (externalAccountId: ExternalAccountId) => Promise<CapxulResult<ExternalAccount, RetrieveCodes$d>>;
75
+ readonly remove: (externalAccountId: ExternalAccountId) => Promise<CapxulResult<void, RemoveCodes$5>>;
76
+ };
77
+ type AccountSubAccountsClient = {
78
+ readonly create: (input: AccountCreateSubAccountInput) => Promise<CapxulResult<SubAccount, UpdateCodes$1>>;
79
+ readonly list: (input: {
80
+ readonly accountId: AccountId;
81
+ } & AccountListInput) => Promise<CapxulResult<List<SubAccount>, ListCodes$a>>;
82
+ readonly retrieve: (subAccountId: SubAccountId) => Promise<CapxulResult<SubAccount, RetrieveCodes$d>>;
83
+ readonly remove: (subAccountId: SubAccountId) => Promise<CapxulResult<void, RemoveCodes$5>>;
84
+ };
85
+ type AccountBalanceLedgerClient = {
86
+ readonly list: (input: {
87
+ readonly accountId: AccountId;
88
+ } & AccountListInput) => Promise<CapxulResult<List<BalanceLedgerEntry>, ListCodes$a>>;
89
+ readonly retrieve: (entryId: string) => Promise<CapxulResult<BalanceLedgerEntry, RetrieveCodes$d>>;
90
+ };
91
+ type AccountsClient = {
92
+ readonly retrieve: (accountId: AccountId) => Promise<CapxulResult<Account, RetrieveCodes$d>>;
93
+ readonly lookup: (input: AccountLookupInput) => Promise<CapxulResult<AccountLookupResult, LookupCodes>>;
94
+ readonly update: (input: {
95
+ readonly accountId: AccountId;
96
+ } & AccountUpdateInput) => Promise<CapxulResult<Account, UpdateCodes$1>>;
97
+ readonly provisionPersonal: (input: AccountProvisionPersonalInput) => Promise<CapxulResult<Account, UpdateCodes$1 | "NETWORK_ERROR">>;
98
+ readonly safes: AccountSafesClient;
99
+ readonly kycProfiles: AccountKycProfilesClient;
100
+ readonly externalAccounts: AccountExternalAccountsClient;
101
+ readonly subAccounts: AccountSubAccountsClient;
102
+ readonly balanceLedger: AccountBalanceLedgerClient;
103
+ };
104
+
105
+ /**
106
+ * API keys domain — org-issued credentials per sdk-surface.md §1b +
107
+ * §4.21 + §4.57. Key types: `cap_test_` / `cap_live_` (secret) and
108
+ * `cap_pk_test_` / `cap_pk_live_` (publishable).
109
+ *
110
+ * All methods are org-nested. The one-time `secret` value is returned
111
+ * on `create` only; subsequent reads omit it.
112
+ */
113
+
114
+ type ApiKeysCreateInput = types.CreateApiKeyRequest & {
115
+ readonly organizationId: OrganizationId;
116
+ };
117
+ type ApiKeysRetrieveInput = {
118
+ readonly organizationId: OrganizationId;
119
+ readonly apiKeyId: ApiKeyId;
120
+ };
121
+ type ApiKeysListInput = {
122
+ readonly organizationId: OrganizationId;
123
+ readonly limit?: number;
124
+ readonly cursor?: string;
125
+ };
126
+ type ApiKeysRevokeInput = ApiKeysRetrieveInput;
127
+ type CreateCodes$8 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "RATE_LIMITED" | "NETWORK_ERROR";
128
+ type RetrieveCodes$c = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
129
+ type ListCodes$9 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
130
+ type RevokeCodes = RetrieveCodes$c;
131
+ /**
132
+ * Shape returned by `organizations.apiKeys.create` — the one-time
133
+ * secret `value` is included here and omitted from every subsequent
134
+ * read.
135
+ */
136
+ type ApiKeyCreateResult = ApiKey & {
137
+ readonly value: string;
138
+ };
139
+ type ApiKeysClient = {
140
+ readonly create: (input: ApiKeysCreateInput) => Promise<CapxulResult<ApiKeyCreateResult, CreateCodes$8>>;
141
+ readonly retrieve: (input: ApiKeysRetrieveInput) => Promise<CapxulResult<ApiKey, RetrieveCodes$c>>;
142
+ readonly list: (input: ApiKeysListInput) => Promise<CapxulResult<List<ApiKey>, ListCodes$9>>;
143
+ readonly revoke: (input: ApiKeysRevokeInput) => Promise<CapxulResult<ApiKey, RevokeCodes>>;
144
+ };
145
+
146
+ interface CapxulDataClient {
147
+ query(name: any, args: any): Promise<any>;
148
+ mutation(name: any, args: any): Promise<any>;
149
+ action?(name: any, args: any): Promise<any>;
150
+ }
151
+
152
+ /**
153
+ * Authentication domain.
154
+ *
155
+ * Maps 1:1 to `/v1/auth/*` HTTP endpoints. Human sign-in via email OTP;
156
+ * partner servers mint short-lived service tokens from a long-lived
157
+ * API key per sdk-surface.md §3.2.
158
+ *
159
+ * Stack-1 update: outbound HTTP routes through `makeHttpTransport`
160
+ * (`packages/sdk/src/transport.ts`) so that `core/auth.ts` no longer
161
+ * owns base-URL validation or `fetch` indirection. The BetterAuth
162
+ * `/api/auth` path-mangling stays here — it is auth-protocol-specific
163
+ * and the transport layer is auth-protocol-agnostic by design.
164
+ *
165
+ * Lazy transport construction: when `config.auth.baseUrl` is absent the
166
+ * SDK is in scaffold/CLI mode and `sendOtp` / `verifyOtp` return the
167
+ * `NOT_IMPLEMENTED` `stub` tuple (preserving the prior behavior). Only
168
+ * when `baseUrl` is configured do we construct the transport — at
169
+ * which point the build-time-urls variant of `BrowserCapxulConfig`
170
+ * runs its own `Errors.invalidInput` validation.
171
+ */
172
+
173
+ type Session = {
174
+ readonly authUserId: string;
175
+ readonly accountId?: AccountId;
176
+ readonly email: string;
177
+ readonly token: string;
178
+ readonly convexJwt?: string;
179
+ readonly expiresAt: TimestampIso;
180
+ };
181
+ type AuthSessionStore = {
182
+ get(): Session | null;
183
+ set(session: Session): void;
184
+ clear(): void;
185
+ };
186
+ type AuthSendOtpInput = {
187
+ readonly email: string;
188
+ };
189
+ type AuthVerifyOtpInput = {
190
+ readonly email: string;
191
+ readonly otp: string;
192
+ };
193
+ type AuthServiceTokenMintInput = {
194
+ readonly apiKey: string;
195
+ readonly audience?: string;
196
+ };
197
+ /**
198
+ * Options bag for auth methods that perform outbound `fetch` work.
199
+ *
200
+ * Accepts an `AbortSignal` so XState v5 actors (and any other caller
201
+ * that wants cancellation) can cancel the in-flight HTTP request when
202
+ * the actor stops. The signal flows through `transport.fetch`'s
203
+ * `RequestInit.signal` and into the underlying `fetch` impl, so
204
+ * `signal.aborted === true` propagates to the network layer per the
205
+ * Web Platform `fetch` contract. See PR #406 S5.
206
+ */
207
+ type AuthMethodOptions = {
208
+ readonly signal?: AbortSignal;
209
+ };
210
+ type ServiceToken = {
211
+ readonly token: string;
212
+ readonly expiresAt: TimestampIso;
213
+ };
214
+ type SendOtpCodes = "EMAIL_DELIVERY_FAILED" | "INVALID_INPUT" | "RATE_LIMITED" | "NETWORK_ERROR";
215
+ type VerifyOtpCodes = "INVALID_INPUT" | "NOT_AUTHENTICATED" | "RATE_LIMITED" | "NETWORK_ERROR";
216
+ type GetSessionCodes = "NETWORK_ERROR";
217
+ type SignOutCodes = "NOT_AUTHENTICATED" | "NETWORK_ERROR";
218
+ type ServiceTokenMintCodes = "API_KEY_INVALID" | "API_KEY_EXPIRED" | "INVALID_INPUT" | "RATE_LIMITED" | "NETWORK_ERROR";
219
+ type AuthClient = {
220
+ readonly sendOtp: (input: AuthSendOtpInput, options?: AuthMethodOptions) => Promise<CapxulResult<void, SendOtpCodes>>;
221
+ readonly verifyOtp: (input: AuthVerifyOtpInput, options?: AuthMethodOptions) => Promise<CapxulResult<Session, VerifyOtpCodes>>;
222
+ readonly getSession: () => Promise<CapxulResult<Session | null, GetSessionCodes>>;
223
+ readonly signOut: () => Promise<CapxulResult<void, SignOutCodes>>;
224
+ readonly serviceTokenMint: (input: AuthServiceTokenMintInput) => Promise<CapxulResult<ServiceToken, ServiceTokenMintCodes>>;
225
+ /** Internal bridge for flow hooks that need the authenticated Convex data client. */
226
+ readonly getDataClient: () => CapxulDataClient | null;
227
+ };
228
+
229
+ /**
230
+ * Documents domain — unified artifact primitive per sdk-surface.md §1a
231
+ * + §4.50.
232
+ *
233
+ * Subsumes the former `invoice` and `org_payroll_entry` top-level
234
+ * primitives. The `Document` union discriminates on `type`:
235
+ * `invoice | payroll_run | payroll_schedule | receipt | kyc_upload |
236
+ * bank_statement | tax_form`.
237
+ */
238
+
239
+ type DocumentsCreateInput = types.CreateDocumentRequest;
240
+ type DocumentsListInput = {
241
+ readonly limit?: number;
242
+ readonly cursor?: string;
243
+ readonly type?: Document["type"];
244
+ };
245
+ type OrgDocumentsCreateInput = DocumentsCreateInput & {
246
+ readonly organizationId: OrganizationId;
247
+ };
248
+ type OrgDocumentsRetrieveInput = {
249
+ readonly organizationId: OrganizationId;
250
+ readonly documentId: DocumentId;
251
+ };
252
+ type OrgDocumentsListInput = {
253
+ readonly organizationId: OrganizationId;
254
+ readonly limit?: number;
255
+ readonly cursor?: string;
256
+ readonly type?: Document["type"];
257
+ };
258
+ type OrgDocumentsCancelInput = {
259
+ readonly organizationId: OrganizationId;
260
+ readonly documentId: DocumentId;
261
+ };
262
+ type CreateCodes$7 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "IDEMPOTENCY_CONFLICT" | "RATE_LIMITED" | "NETWORK_ERROR";
263
+ type RetrieveCodes$b = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
264
+ type ListCodes$8 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
265
+ type CancelCodes$1 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "OPERATION_CANCELED";
266
+ type DocumentsClient = {
267
+ readonly create: (input: DocumentsCreateInput) => Promise<CapxulResult<Document, CreateCodes$7>>;
268
+ readonly retrieve: (documentId: DocumentId) => Promise<CapxulResult<Document, RetrieveCodes$b>>;
269
+ readonly list: (input?: DocumentsListInput) => Promise<CapxulResult<List<Document>, ListCodes$8>>;
270
+ readonly cancel: (documentId: DocumentId) => Promise<CapxulResult<Document, CancelCodes$1>>;
271
+ };
272
+ type OrgDocumentsClient = {
273
+ readonly create: (input: OrgDocumentsCreateInput) => Promise<CapxulResult<Document, CreateCodes$7>>;
274
+ readonly retrieve: (input: OrgDocumentsRetrieveInput) => Promise<CapxulResult<Document, RetrieveCodes$b>>;
275
+ readonly list: (input: OrgDocumentsListInput) => Promise<CapxulResult<List<Document>, ListCodes$8>>;
276
+ readonly cancel: (input: OrgDocumentsCancelInput) => Promise<CapxulResult<Document, CancelCodes$1>>;
277
+ };
278
+
279
+ /**
280
+ * External-accounts domain — top-level `capxul.externalAccounts.*`.
281
+ *
282
+ * Per sdk-surface.md §1a, `external_account` is a reusable withdrawal
283
+ * destination. `create` + `list` live under the owner's nested
284
+ * namespace (Pattern A — `accounts.externalAccounts.*` or
285
+ * `organizations.externalAccounts.*`). `retrieve` and `remove` work by
286
+ * ID without scoping.
287
+ */
288
+
289
+ type RetrieveCodes$a = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
290
+ type RemoveCodes$4 = RetrieveCodes$a;
291
+ type ExternalAccountsClient = {
292
+ readonly retrieve: (externalAccountId: ExternalAccountId) => Promise<CapxulResult<ExternalAccount, RetrieveCodes$a>>;
293
+ readonly remove: (externalAccountId: ExternalAccountId) => Promise<CapxulResult<void, RemoveCodes$4>>;
294
+ };
295
+
296
+ /**
297
+ * `me` — first-party-only surface for the authenticated user.
298
+ *
299
+ * Partner SDK code (service-key lens) uses `capxul.accounts.retrieve(id)`
300
+ * instead. This namespace exists because the CLI and `useMe()` hook
301
+ * in `@capxul/sdk-react` always know the calling user and shouldn't
302
+ * need to pass the account id.
303
+ *
304
+ * See `/docs/internal/reset/sdk-surface` + `packages/sdk/tests/walkthroughs/me-retrieve.ts`.
305
+ */
306
+
307
+ type MeUpdateInput = Partial<{
308
+ readonly name: string;
309
+ readonly username: string;
310
+ readonly countryCode: string;
311
+ }>;
312
+ type MeGetCodes = "NOT_AUTHENTICATED" | "PROFILE_NOT_FOUND";
313
+ type MeUpdateCodes = "NOT_AUTHENTICATED" | "PROFILE_NOT_FOUND" | "INVALID_INPUT";
314
+ type MeClient = {
315
+ readonly get: () => Promise<CapxulResult<Account, MeGetCodes>>;
316
+ readonly update: (input: MeUpdateInput) => Promise<CapxulResult<Account, MeUpdateCodes>>;
317
+ };
318
+
319
+ /**
320
+ * Operations domain — durable async-work envelope per sdk-surface.md §1b.
321
+ *
322
+ * `retrieve` is a snapshot read (no polling). `wait` is the opt-in
323
+ * polling helper per CANON.md §4.40 — caller explicitly asks to block
324
+ * until a terminal condition or timeout.
325
+ */
326
+
327
+ type OperationsWaitInput = {
328
+ readonly until?: readonly OperationStatus[];
329
+ readonly timeoutSeconds?: number;
330
+ readonly pollIntervalMs?: number;
331
+ };
332
+ type RetrieveCodes$9 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
333
+ type WaitCodes = RetrieveCodes$9 | "OPERATION_TIMEOUT";
334
+ type OperationsClient = {
335
+ readonly retrieve: (operationId: OperationId) => Promise<CapxulResult<Operation, RetrieveCodes$9>>;
336
+ readonly wait: (operationId: OperationId, input?: OperationsWaitInput) => Promise<CapxulResult<Operation, WaitCodes>>;
337
+ };
338
+
339
+ /**
340
+ * Payments domain.
341
+ *
342
+ * Exposes both the personal-scope `PaymentsClient` (under
343
+ * `capxul.payments.*`) and the org-scoped `OrgPaymentsClient` (under
344
+ * `capxul.organizations.payments.*`). The org variant takes
345
+ * `organizationId` explicitly on every call; there is no ambient org
346
+ * context.
347
+ *
348
+ * See `/docs/internal/reset/sdk-surface` and the walkthroughs in
349
+ * `packages/sdk/tests/walkthroughs/`.
350
+ */
351
+
352
+ type PaymentsCreateInput = {
353
+ readonly to: UserIdentifier;
354
+ readonly amount: Money;
355
+ readonly reference?: string;
356
+ readonly idempotencyKey?: string;
357
+ readonly include?: readonly string[];
358
+ /**
359
+ * Funds v1 (#420): tag the payment with the originating sub-account.
360
+ * This personal data-path forwards the field to Convex; broader
361
+ * organization and React hook wiring lands in #421 alongside
362
+ * `include: ["balancesByCustody"]` read paths.
363
+ */
364
+ readonly source?: {
365
+ readonly subAccountId: SubAccountId;
366
+ };
367
+ };
368
+ type PaymentsListInput = {
369
+ readonly limit?: number;
370
+ readonly cursor?: string;
371
+ readonly include?: readonly string[];
372
+ };
373
+ type OrgPaymentsCreateInput = {
374
+ readonly organizationId: OrganizationId;
375
+ readonly source?: {
376
+ readonly subAccountId: SubAccountId;
377
+ };
378
+ readonly to: UserIdentifier;
379
+ readonly amount: Money;
380
+ readonly reference?: string;
381
+ readonly idempotencyKey?: string;
382
+ readonly include?: readonly string[];
383
+ };
384
+ type OrgPaymentsRetrieveInput = {
385
+ readonly organizationId: OrganizationId;
386
+ readonly paymentId: PaymentId;
387
+ };
388
+ type OrgPaymentsListInput = {
389
+ readonly organizationId: OrganizationId;
390
+ readonly limit?: number;
391
+ readonly cursor?: string;
392
+ readonly include?: readonly string[];
393
+ };
394
+ type CreateCodes$6 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "INVALID_RECIPIENT" | "INSUFFICIENT_BALANCE" | "IDEMPOTENCY_CONFLICT" | "RATE_LIMITED" | "NETWORK_ERROR";
395
+ type OrgCreateCodes = CreateCodes$6 | "POLICY_DENIED" | "SAFE_NOT_READY";
396
+ type RetrieveCodes$8 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
397
+ type ListCodes$7 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
398
+ type PaymentsClient = {
399
+ readonly create: (input: PaymentsCreateInput) => Promise<CapxulResult<CreatePaymentResult, CreateCodes$6>>;
400
+ readonly retrieve: (paymentId: PaymentId) => Promise<CapxulResult<Payment, RetrieveCodes$8>>;
401
+ readonly list: (input?: PaymentsListInput) => Promise<CapxulResult<List<Payment>, ListCodes$7>>;
402
+ };
403
+ type OrgPaymentsClient = {
404
+ readonly create: (input: OrgPaymentsCreateInput) => Promise<CapxulResult<CreatePaymentResult, OrgCreateCodes>>;
405
+ readonly retrieve: (input: OrgPaymentsRetrieveInput) => Promise<CapxulResult<Payment, RetrieveCodes$8>>;
406
+ readonly list: (input: OrgPaymentsListInput) => Promise<CapxulResult<List<Payment>, ListCodes$7>>;
407
+ };
408
+
409
+ /**
410
+ * Transfers domain — cross-custody internal moves per CANON.md §4.53.
411
+ *
412
+ * A transfer moves balance between custody sources owned by the same
413
+ * account or organization (e.g. EUR virtual-account → USD stablecoin
414
+ * pool). When currencies differ the wire carries an `fx` block with a
415
+ * quote id the caller confirms via `transfers.confirm(...)` per §4.58.
416
+ */
417
+
418
+ type TransfersCreateInput = {
419
+ readonly source: TransferEndpoint;
420
+ readonly destination: TransferEndpoint;
421
+ readonly amount: Money;
422
+ readonly idempotencyKey?: string;
423
+ readonly include?: readonly string[];
424
+ };
425
+ type TransfersListInput = {
426
+ readonly limit?: number;
427
+ readonly cursor?: string;
428
+ };
429
+ type TransfersConfirmInput = {
430
+ readonly transferId: TransferId;
431
+ readonly quoteId: string;
432
+ };
433
+ type OrgTransfersCreateInput = TransfersCreateInput & {
434
+ readonly organizationId: OrganizationId;
435
+ };
436
+ type OrgTransfersRetrieveInput = {
437
+ readonly organizationId: OrganizationId;
438
+ readonly transferId: TransferId;
439
+ };
440
+ type OrgTransfersListInput = {
441
+ readonly organizationId: OrganizationId;
442
+ readonly limit?: number;
443
+ readonly cursor?: string;
444
+ };
445
+ type OrgTransfersConfirmInput = {
446
+ readonly organizationId: OrganizationId;
447
+ readonly transferId: TransferId;
448
+ readonly quoteId: string;
449
+ };
450
+ type OrgTransfersCancelInput = {
451
+ readonly organizationId: OrganizationId;
452
+ readonly transferId: TransferId;
453
+ };
454
+ type CreateCodes$5 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "INSUFFICIENT_BALANCE" | "IDEMPOTENCY_CONFLICT" | "RATE_LIMITED" | "NETWORK_ERROR";
455
+ type RetrieveCodes$7 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
456
+ type ListCodes$6 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
457
+ type ConfirmCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "QUOTE_EXPIRED" | "QUOTE_NOT_FOUND";
458
+ type CancelCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "OPERATION_CANCELED";
459
+ type TransfersClient = {
460
+ readonly create: (input: TransfersCreateInput) => Promise<CapxulResult<CreateTransferResult, CreateCodes$5>>;
461
+ readonly retrieve: (transferId: TransferId) => Promise<CapxulResult<Transfer, RetrieveCodes$7>>;
462
+ readonly list: (input?: TransfersListInput) => Promise<CapxulResult<List<Transfer>, ListCodes$6>>;
463
+ readonly confirm: (input: TransfersConfirmInput) => Promise<CapxulResult<Transfer, ConfirmCodes>>;
464
+ readonly cancel: (transferId: TransferId) => Promise<CapxulResult<Transfer, CancelCodes>>;
465
+ };
466
+ type OrgTransfersClient = {
467
+ readonly create: (input: OrgTransfersCreateInput) => Promise<CapxulResult<CreateTransferResult, CreateCodes$5>>;
468
+ readonly retrieve: (input: OrgTransfersRetrieveInput) => Promise<CapxulResult<Transfer, RetrieveCodes$7>>;
469
+ readonly list: (input: OrgTransfersListInput) => Promise<CapxulResult<List<Transfer>, ListCodes$6>>;
470
+ readonly confirm: (input: OrgTransfersConfirmInput) => Promise<CapxulResult<Transfer, ConfirmCodes>>;
471
+ readonly cancel: (input: OrgTransfersCancelInput) => Promise<CapxulResult<Transfer, CancelCodes>>;
472
+ };
473
+
474
+ /**
475
+ * Withdrawals domain — funds exit Capxul via an `external_account` per
476
+ * sdk-surface.md §1a + §4.52 + withdrawal-orchestration.mdx (slice 1
477
+ * of Withdrawals v1, #440).
478
+ *
479
+ * Slice 1 NOTE — transitional input shape:
480
+ * Until the `external_accounts` resource lands (slice 1.x or v2), the
481
+ * destination input includes a `kind` field so the backend + SDK can
482
+ * route to the chain_wallet rail without a real external_accounts
483
+ * lookup. When the resource lands, `kind` becomes optional / ignored
484
+ * and the kind is inferred from the resolved row.
485
+ *
486
+ * Slice 1 NOTE — chain_wallet rail integration:
487
+ * For evm destinations, the `externalAccountId` is treated as the
488
+ * destination address (must start with `0x`) so the chain_wallet rail
489
+ * can call `transferAsOwner` directly. For solana / starknet the SDK
490
+ * accepts the create call but does NOT execute the rail submission —
491
+ * the row stays in `processing` until external_accounts lands. The
492
+ * caller can transition it via `markFailed` if needed.
493
+ */
494
+
495
+ type WithdrawalsCreateInput = {
496
+ readonly amount: Money;
497
+ readonly destination: {
498
+ readonly externalAccountId: ExternalAccountId;
499
+ /**
500
+ * Slice 1 transitional field. Required until the
501
+ * `external_accounts` resource lands; will become optional / ignored
502
+ * when the resource is the source of truth for kind.
503
+ */
504
+ readonly kind: "evm" | "solana" | "starknet" | "bank" | "momo" | "card_payout";
505
+ };
506
+ readonly source?: {
507
+ readonly subAccountId: SubAccountId;
508
+ };
509
+ readonly reference?: string;
510
+ readonly idempotencyKey?: string;
511
+ readonly include?: readonly string[];
512
+ };
513
+ type WithdrawalsListInput = {
514
+ readonly limit?: number;
515
+ readonly cursor?: string;
516
+ };
517
+ type OrgWithdrawalsCreateInput = WithdrawalsCreateInput & {
518
+ readonly organizationId: OrganizationId;
519
+ };
520
+ type OrgWithdrawalsRetrieveInput = {
521
+ readonly organizationId: OrganizationId;
522
+ readonly withdrawalId: WithdrawalId;
523
+ };
524
+ type OrgWithdrawalsListInput = {
525
+ readonly organizationId: OrganizationId;
526
+ readonly limit?: number;
527
+ readonly cursor?: string;
528
+ };
529
+ type CreateCodes$4 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "INSUFFICIENT_BALANCE" | "IDEMPOTENCY_CONFLICT" | "KYC_REQUIRED" | "POLICY_DENIED" | "RATE_LIMITED" | "NETWORK_ERROR";
530
+ type RetrieveCodes$6 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
531
+ type ListCodes$5 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
532
+ type WithdrawalsClient = {
533
+ readonly create: (input: WithdrawalsCreateInput) => Promise<CapxulResult<CreateWithdrawalResult, CreateCodes$4>>;
534
+ readonly retrieve: (withdrawalId: WithdrawalId) => Promise<CapxulResult<Withdrawal, RetrieveCodes$6>>;
535
+ readonly list: (input?: WithdrawalsListInput) => Promise<CapxulResult<List<Withdrawal>, ListCodes$5>>;
536
+ };
537
+ type OrgWithdrawalsClient = {
538
+ readonly create: (input: OrgWithdrawalsCreateInput) => Promise<CapxulResult<CreateWithdrawalResult, CreateCodes$4>>;
539
+ readonly retrieve: (input: OrgWithdrawalsRetrieveInput) => Promise<CapxulResult<Withdrawal, RetrieveCodes$6>>;
540
+ readonly list: (input: OrgWithdrawalsListInput) => Promise<CapxulResult<List<Withdrawal>, ListCodes$5>>;
541
+ };
542
+
543
+ /**
544
+ * Webhook endpoints domain — developer-registered receivers per
545
+ * sdk-surface.md §1b. All methods are org-nested (accessed via
546
+ * `capxul.organizations.webhookEndpoints.*` per CANON.md §4.30).
547
+ * The top-level `webhookEndpoints` surface on `CapxulClient` is kept
548
+ * as an alias for discoverability; its methods proxy to the org
549
+ * variant at call time and require `organizationId` explicitly.
550
+ */
551
+
552
+ type WebhookEndpointsCreateInput = types.CreateWebhookEndpointRequest & {
553
+ readonly organizationId: OrganizationId;
554
+ };
555
+ type WebhookEndpointsRetrieveInput = {
556
+ readonly organizationId: OrganizationId;
557
+ readonly webhookEndpointId: WebhookEndpointId;
558
+ };
559
+ type WebhookEndpointsListInput = {
560
+ readonly organizationId: OrganizationId;
561
+ readonly limit?: number;
562
+ readonly cursor?: string;
563
+ };
564
+ type WebhookEndpointsRemoveInput = WebhookEndpointsRetrieveInput;
565
+ type CreateCodes$3 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "RATE_LIMITED" | "NETWORK_ERROR";
566
+ type RetrieveCodes$5 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
567
+ type ListCodes$4 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
568
+ type RemoveCodes$3 = RetrieveCodes$5;
569
+ /**
570
+ * Shape returned by `organizations.webhookEndpoints.create` — the
571
+ * one-time `signingSecret` is included here and omitted from every
572
+ * subsequent read (per sdk-surface.md §1b).
573
+ */
574
+ type WebhookEndpointCreateResult = WebhookEndpoint & {
575
+ readonly signingSecret: string;
576
+ };
577
+ type WebhookEndpointsClient = {
578
+ readonly create: (input: WebhookEndpointsCreateInput) => Promise<CapxulResult<WebhookEndpointCreateResult, CreateCodes$3>>;
579
+ readonly retrieve: (input: WebhookEndpointsRetrieveInput) => Promise<CapxulResult<WebhookEndpoint, RetrieveCodes$5>>;
580
+ readonly list: (input: WebhookEndpointsListInput) => Promise<CapxulResult<List<WebhookEndpoint>, ListCodes$4>>;
581
+ readonly remove: (input: WebhookEndpointsRemoveInput) => Promise<CapxulResult<void, RemoveCodes$3>>;
582
+ };
583
+
584
+ /**
585
+ * Webhook events domain — individual delivery attempt + payload per
586
+ * sdk-surface.md §1b. v1 is read-only (partner replay lands in v1.5
587
+ * per §4.20). All methods are org-nested.
588
+ */
589
+
590
+ type WebhookEventsRetrieveInput = {
591
+ readonly organizationId: OrganizationId;
592
+ readonly webhookEventId: WebhookEventId;
593
+ };
594
+ type WebhookEventsListInput = {
595
+ readonly organizationId: OrganizationId;
596
+ readonly limit?: number;
597
+ readonly cursor?: string;
598
+ readonly endpointId?: string;
599
+ readonly type?: string;
600
+ };
601
+ type RetrieveCodes$4 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
602
+ type ListCodes$3 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
603
+ type WebhookEventsClient = {
604
+ readonly retrieve: (input: WebhookEventsRetrieveInput) => Promise<CapxulResult<WebhookEvent, RetrieveCodes$4>>;
605
+ readonly list: (input: WebhookEventsListInput) => Promise<CapxulResult<List<WebhookEvent>, ListCodes$3>>;
606
+ };
607
+
608
+ /**
609
+ * Organizations domain per sdk-surface.md §1a.
610
+ *
611
+ * The org surface is broad because org-scoped flows for every money-
612
+ * movement + identity primitive live under `organizations.*` per
613
+ * CANON.md §4.30 (Shape A). Sub-client factories delegate to the
614
+ * dedicated domain factories in `core/*.ts` so the tuple-return +
615
+ * error-narrowing plumbing is shared.
616
+ */
617
+
618
+ type OrganizationsCreateInput = {
619
+ readonly name: string;
620
+ readonly country: string;
621
+ };
622
+ type OrganizationsListInput = {
623
+ readonly limit?: number;
624
+ readonly cursor?: string;
625
+ };
626
+ type OrganizationsUpdateInput = {
627
+ readonly organizationId: OrganizationId;
628
+ readonly name?: string;
629
+ };
630
+ type OrgSafeRetrieveInput = {
631
+ readonly organizationId: OrganizationId;
632
+ readonly safeId: SafeId;
633
+ };
634
+ type OrgMemberInviteInput = {
635
+ readonly organizationId: OrganizationId;
636
+ readonly email: string;
637
+ readonly role: Member["role"];
638
+ };
639
+ type OrgMemberUpdateRoleInput = {
640
+ readonly organizationId: OrganizationId;
641
+ readonly memberId: MemberId;
642
+ readonly role: Member["role"];
643
+ };
644
+ type OrgMemberRemoveInput = {
645
+ readonly organizationId: OrganizationId;
646
+ readonly memberId: MemberId;
647
+ };
648
+ type OrgMemberRetrieveInput = OrgMemberRemoveInput;
649
+ type OrgListInput = {
650
+ readonly organizationId: OrganizationId;
651
+ readonly limit?: number;
652
+ readonly cursor?: string;
653
+ };
654
+ type OrgKybProfileStartInput = {
655
+ readonly organizationId: OrganizationId;
656
+ };
657
+ type OrgKybProfileRetrieveInput = {
658
+ readonly organizationId: OrganizationId;
659
+ readonly kybProfileId: KybProfileId;
660
+ };
661
+ type OrgCreateSubAccountInput = {
662
+ readonly organizationId: OrganizationId;
663
+ readonly name: string;
664
+ };
665
+ type OrgCreateExternalAccountInput = {
666
+ readonly organizationId: OrganizationId;
667
+ readonly kind: "bank" | "evm" | "solana" | "starknet" | "card_payout";
668
+ readonly label?: string;
669
+ readonly address?: string;
670
+ readonly iban?: string;
671
+ readonly bic?: string;
672
+ readonly accountHolder?: string;
673
+ readonly network?: "visa" | "mastercard";
674
+ readonly panToken?: string;
675
+ readonly last4?: string;
676
+ };
677
+ type CreateCodes$2 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "RATE_LIMITED" | "NETWORK_ERROR";
678
+ type RetrieveCodes$3 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
679
+ type ListCodes$2 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
680
+ type UpdateCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "INVALID_INPUT";
681
+ /**
682
+ * Org safe retrieve does NOT surface `SAFE_NOT_READY` — a co-member
683
+ * who tries to read an in-flight Safe hits `PERMISSION_DENIED` (Safes
684
+ * are admin-lens-only), and an admin gets `processing` via the
685
+ * operation field. The mid-deploy balance view surfaces via
686
+ * `treasury.retrieve` which DOES carry `SAFE_NOT_READY`.
687
+ *
688
+ * Contrast with `accounts.safes.retrieve` which DOES surface
689
+ * `SAFE_NOT_READY` because personal Safes are visible to the owner
690
+ * while deploying.
691
+ */
692
+ type SafeRetrieveCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
693
+ type TreasuryRetrieveCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "SAFE_NOT_READY";
694
+ type RemoveCodes$2 = RetrieveCodes$3;
695
+ type OrgSafesClient = {
696
+ readonly retrieve: (input: OrgSafeRetrieveInput) => Promise<CapxulResult<Safe, SafeRetrieveCodes>>;
697
+ };
698
+ type OrgTreasuryClient = {
699
+ readonly retrieve: (organizationId: OrganizationId) => Promise<CapxulResult<Treasury, TreasuryRetrieveCodes>>;
700
+ };
701
+ type OrgMembersClient = {
702
+ readonly list: (input: OrgListInput) => Promise<CapxulResult<List<Member>, ListCodes$2>>;
703
+ readonly retrieve: (input: OrgMemberRetrieveInput) => Promise<CapxulResult<Member, RetrieveCodes$3>>;
704
+ readonly invite: (input: OrgMemberInviteInput) => Promise<CapxulResult<Member, UpdateCodes>>;
705
+ readonly updateRole: (input: OrgMemberUpdateRoleInput) => Promise<CapxulResult<Member, UpdateCodes>>;
706
+ readonly remove: (input: OrgMemberRemoveInput) => Promise<CapxulResult<void, RemoveCodes$2>>;
707
+ };
708
+ type OrgKybProfileClient = {
709
+ readonly start: (input: OrgKybProfileStartInput) => Promise<CapxulResult<KybProfile, CreateCodes$2>>;
710
+ readonly retrieve: (input: OrgKybProfileRetrieveInput) => Promise<CapxulResult<KybProfile, RetrieveCodes$3>>;
711
+ };
712
+ type OrgSubAccountsClient = {
713
+ readonly create: (input: OrgCreateSubAccountInput) => Promise<CapxulResult<SubAccount, UpdateCodes>>;
714
+ readonly list: (input: OrgListInput) => Promise<CapxulResult<List<SubAccount>, ListCodes$2>>;
715
+ readonly retrieve: (input: {
716
+ readonly organizationId: OrganizationId;
717
+ readonly subAccountId: SubAccountId;
718
+ }) => Promise<CapxulResult<SubAccount, RetrieveCodes$3>>;
719
+ readonly remove: (input: {
720
+ readonly organizationId: OrganizationId;
721
+ readonly subAccountId: SubAccountId;
722
+ }) => Promise<CapxulResult<void, RemoveCodes$2>>;
723
+ };
724
+ type OrgExternalAccountsClient = {
725
+ readonly create: (input: OrgCreateExternalAccountInput) => Promise<CapxulResult<ExternalAccount, UpdateCodes>>;
726
+ readonly list: (input: OrgListInput) => Promise<CapxulResult<List<ExternalAccount>, ListCodes$2>>;
727
+ readonly retrieve: (input: {
728
+ readonly organizationId: OrganizationId;
729
+ readonly externalAccountId: ExternalAccountId;
730
+ }) => Promise<CapxulResult<ExternalAccount, RetrieveCodes$3>>;
731
+ readonly remove: (input: {
732
+ readonly organizationId: OrganizationId;
733
+ readonly externalAccountId: ExternalAccountId;
734
+ }) => Promise<CapxulResult<void, RemoveCodes$2>>;
735
+ };
736
+ type OrgBalanceLedgerClient = {
737
+ readonly list: (input: OrgListInput) => Promise<CapxulResult<List<BalanceLedgerEntry>, ListCodes$2>>;
738
+ readonly retrieve: (input: {
739
+ readonly organizationId: OrganizationId;
740
+ readonly entryId: string;
741
+ }) => Promise<CapxulResult<BalanceLedgerEntry, RetrieveCodes$3>>;
742
+ };
743
+ type OrgApiKeysClient = ApiKeysClient;
744
+ type OrganizationsClient = {
745
+ readonly create: (input: OrganizationsCreateInput) => Promise<CapxulResult<Organization, CreateCodes$2>>;
746
+ readonly retrieve: (organizationId: OrganizationId) => Promise<CapxulResult<Organization, RetrieveCodes$3>>;
747
+ readonly list: (input?: OrganizationsListInput) => Promise<CapxulResult<List<Organization>, ListCodes$2>>;
748
+ readonly update: (input: OrganizationsUpdateInput) => Promise<CapxulResult<Organization, UpdateCodes>>;
749
+ readonly safes: OrgSafesClient;
750
+ readonly treasury: OrgTreasuryClient;
751
+ readonly members: OrgMembersClient;
752
+ readonly apiKeys: OrgApiKeysClient;
753
+ readonly kybProfile: OrgKybProfileClient;
754
+ readonly subAccounts: OrgSubAccountsClient;
755
+ readonly externalAccounts: OrgExternalAccountsClient;
756
+ readonly balanceLedger: OrgBalanceLedgerClient;
757
+ readonly payments: OrgPaymentsClient;
758
+ readonly transfers: OrgTransfersClient;
759
+ readonly withdrawals: OrgWithdrawalsClient;
760
+ readonly documents: OrgDocumentsClient;
761
+ readonly webhookEndpoints: WebhookEndpointsClient;
762
+ readonly webhookEvents: WebhookEventsClient;
763
+ };
764
+
765
+ /**
766
+ * HTTP transport — the SDK's outbound network seam AND the canonical
767
+ * lifecycle observable for the publishable-key DX path (ADR #14c).
768
+ *
769
+ * The transport plays two roles:
770
+ *
771
+ * 1. **Network seam.** `fetch(path, init?)` resolves a path against
772
+ * `authBaseUrl` (absolute URLs are forwarded unchanged). The
773
+ * `build-time-urls` arm exposes the URLs immediately; the
774
+ * `publishable-key` arm resolves them lazily on first use through
775
+ * `/v1/client/bootstrap`, with singleflight + reset-on-failure.
776
+ *
777
+ * 2. **Lifecycle observable.** A 5-state machine
778
+ * (`idle → bootstrapping → ready → authenticated → error`) drives
779
+ * the React `useCapxulStatus()` hook. The transport is a stable
780
+ * singleton across renders — React subscribes to its lifecycle via
781
+ * `useSyncExternalStore` and re-renders only when the state
782
+ * transitions, never because the provider rebuilt.
783
+ *
784
+ * The transport is auth-protocol-agnostic. Path mangling like
785
+ * BetterAuth's `/api/auth` prefix lives in `core/auth.ts` and stays
786
+ * out of this file.
787
+ */
788
+
789
+ /**
790
+ * Browser-side SDK config — discriminated union per ADR 5.
791
+ *
792
+ * Stack 2 ships the full union:
793
+ * - `mode: "build-time-urls"` for explicit local/dev wiring
794
+ * - `mode: "publishable-key"` for browser-safe lazy bootstrap through
795
+ * `/v1/client/bootstrap`
796
+ */
797
+ type BrowserCapxulConfig = {
798
+ readonly mode: "build-time-urls";
799
+ readonly authBaseUrl: string;
800
+ readonly convexUrl: string;
801
+ /**
802
+ * Inject a `fetch` implementation. Defaults to `globalThis.fetch`.
803
+ * Named `fetchImpl` to avoid shadowing the global.
804
+ */
805
+ readonly fetchImpl?: typeof fetch;
806
+ } | {
807
+ readonly mode: "publishable-key";
808
+ readonly publishableKey: string;
809
+ /**
810
+ * Override the absolute URL used for `/v1/client/bootstrap`.
811
+ *
812
+ * Defaults to `${CAPXUL_API_BASE_URL}/v1/client/bootstrap` from
813
+ * `@repo/config`. Tests and alternative staging deployments set
814
+ * this to point at a local mock server or a non-alpha Convex
815
+ * site. A trailing slash is stripped before joining.
816
+ */
817
+ readonly bootstrapUrl?: string;
818
+ readonly fetchImpl?: typeof fetch;
819
+ };
820
+ /**
821
+ * Transport lifecycle state — the canonical state machine for the
822
+ * publishable-key DX path per ADR #14c.
823
+ *
824
+ * Transitions:
825
+ * - `idle → bootstrapping` on first network call
826
+ * - `bootstrapping → ready` on successful `/v1/client/bootstrap`
827
+ * - `bootstrapping → error` on bootstrap failure
828
+ * - `error → bootstrapping` when a subsequent caller retries (reset-on-failure)
829
+ * - `ready → authenticated` via `markAuthenticated()` after verifyOtp
830
+ * - `authenticated → ready` via `signOut()` / `clearAuth()`
831
+ *
832
+ * The `build-time-urls` arm starts in `ready` immediately because no
833
+ * bootstrap is required.
834
+ */
835
+ type TransportState = {
836
+ readonly status: "idle";
837
+ } | {
838
+ readonly status: "bootstrapping";
839
+ } | {
840
+ readonly status: "ready";
841
+ readonly runtime: TransportRuntime;
842
+ } | {
843
+ readonly status: "authenticated";
844
+ readonly runtime: TransportRuntime;
845
+ } | {
846
+ readonly status: "error";
847
+ readonly error: CapxulError;
848
+ };
849
+ type TransportRuntime = {
850
+ readonly authBaseUrl: string;
851
+ readonly convexUrl: string;
852
+ };
853
+ /**
854
+ * HTTP transport surface consumed by every domain client (auth, me,
855
+ * payments, …) once Stack 1 task 1.5 routes them through here.
856
+ *
857
+ * - `fetch(path, init?)` resolves a relative path against
858
+ * `authBaseUrl` (absolute URLs are forwarded unchanged).
859
+ * - `authBaseUrl` and `convexUrl` are exposed as resolved values so
860
+ * downstream consumers (e.g. Convex client construction) can read
861
+ * them directly. The publishable-key arm populates these lazily
862
+ * after the first bootstrap resolution; before that they are empty
863
+ * strings.
864
+ * - `getState()` / `subscribe()` are the React-friendly observable
865
+ * surface for `useCapxulStatus()`. Use `useSyncExternalStore` on the
866
+ * React side.
867
+ * - `markAuthenticated()` / `clearAuth()` are the post-verifyOtp /
868
+ * post-signOut transition methods (ADR #14c contract item 3 — the
869
+ * provider does NOT setState; it lets the transport's state machine
870
+ * drive React subscriptions).
871
+ */
872
+ type HttpTransport = {
873
+ readonly fetch: (path: string, init?: RequestInit) => Promise<Response>;
874
+ readonly authBaseUrl: string;
875
+ readonly convexUrl: string;
876
+ readonly getState: () => TransportState;
877
+ readonly subscribe: (listener: () => void) => () => void;
878
+ readonly getDataClient: () => CapxulDataClient | null;
879
+ readonly markAuthenticated: (opts: {
880
+ readonly dataClient?: CapxulDataClient;
881
+ }) => void;
882
+ readonly clearAuth: () => void;
883
+ };
884
+ /**
885
+ * Build an `HttpTransport` from a `BrowserCapxulConfig`.
886
+ *
887
+ * Throws `Errors.invalidInput("authBaseUrl" | "convexUrl", reason)`
888
+ * when the build-time-urls variant is missing required URLs.
889
+ */
890
+ declare function makeHttpTransport(config: BrowserCapxulConfig): HttpTransport;
891
+
892
+ /**
893
+ * Sub-accounts domain — the top-level `capxul.subAccounts.*` surface.
894
+ *
895
+ * Per sdk-surface.md §1a, `sub_account` is a named partition under an
896
+ * account or organization that aggregates balance across custody
897
+ * sources (stablecoin pool + virtual accounts + cards). `create` and
898
+ * `list` live on the owner's nested namespace (Pattern A —
899
+ * `accounts.subAccounts.create(...)` or
900
+ * `organizations.subAccounts.create(...)`), so only `retrieve` and
901
+ * `remove` live at the top level.
902
+ */
903
+
904
+ type RetrieveCodes$2 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
905
+ type RemoveCodes$1 = RetrieveCodes$2;
906
+ type SubAccountsClient = {
907
+ readonly retrieve: (subAccountId: SubAccountId) => Promise<CapxulResult<SubAccount, RetrieveCodes$2>>;
908
+ readonly remove: (subAccountId: SubAccountId) => Promise<CapxulResult<void, RemoveCodes$1>>;
909
+ };
910
+
911
+ /**
912
+ * Virtual accounts domain — International Bank Account Number (IBAN)-
913
+ * bearing receive rails per sdk-surface.md §1a + §4.51.
914
+ *
915
+ * Uses Pattern C (ownerKind in body): the caller specifies
916
+ * `owner = { kind: "account" | "sub_account" | "organization", id: ... }`
917
+ * in the create payload rather than nesting the route under the owner.
918
+ */
919
+
920
+ type VirtualAccountsCreateInput = types.CreateVirtualAccountRequest;
921
+ type VirtualAccountsListInput = {
922
+ readonly limit?: number;
923
+ readonly cursor?: string;
924
+ readonly ownerKind?: "account" | "sub_account" | "organization";
925
+ readonly ownerId?: string;
926
+ };
927
+ type CreateCodes$1 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "KYC_REQUIRED" | "PROVIDER_UNAVAILABLE" | "RATE_LIMITED" | "NETWORK_ERROR";
928
+ type RetrieveCodes$1 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
929
+ type ListCodes$1 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
930
+ type RemoveCodes = RetrieveCodes$1;
931
+ type VirtualAccountsClient = {
932
+ readonly create: (input: VirtualAccountsCreateInput) => Promise<CapxulResult<VirtualAccount, CreateCodes$1>>;
933
+ readonly retrieve: (virtualAccountId: VirtualAccountId) => Promise<CapxulResult<VirtualAccount, RetrieveCodes$1>>;
934
+ readonly list: (input?: VirtualAccountsListInput) => Promise<CapxulResult<List<VirtualAccount>, ListCodes$1>>;
935
+ readonly remove: (virtualAccountId: VirtualAccountId) => Promise<CapxulResult<void, RemoveCodes>>;
936
+ };
937
+
938
+ /**
939
+ * Virtual cards domain — issued Visa / Mastercard spending sub-account
940
+ * balance per sdk-surface.md §1a + §4.51.
941
+ *
942
+ * Uses Pattern C (ownerKind in body).
943
+ */
944
+
945
+ type VirtualCardsCreateInput = types.CreateVirtualCardRequest;
946
+ type VirtualCardsListInput = {
947
+ readonly limit?: number;
948
+ readonly cursor?: string;
949
+ readonly ownerKind?: "account" | "sub_account" | "organization";
950
+ readonly ownerId?: string;
951
+ };
952
+ type CreateCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "KYC_REQUIRED" | "PROVIDER_UNAVAILABLE" | "RATE_LIMITED" | "NETWORK_ERROR";
953
+ type RetrieveCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
954
+ type ListCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
955
+ type MutateCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND" | "PROVIDER_UNAVAILABLE";
956
+ type VirtualCardsClient = {
957
+ readonly create: (input: VirtualCardsCreateInput) => Promise<CapxulResult<VirtualCard, CreateCodes>>;
958
+ readonly retrieve: (virtualCardId: VirtualCardId) => Promise<CapxulResult<VirtualCard, RetrieveCodes>>;
959
+ readonly list: (input?: VirtualCardsListInput) => Promise<CapxulResult<List<VirtualCard>, ListCodes>>;
960
+ readonly freeze: (virtualCardId: VirtualCardId) => Promise<CapxulResult<VirtualCard, MutateCodes>>;
961
+ readonly unfreeze: (virtualCardId: VirtualCardId) => Promise<CapxulResult<VirtualCard, MutateCodes>>;
962
+ readonly cancel: (virtualCardId: VirtualCardId) => Promise<CapxulResult<VirtualCard, MutateCodes>>;
963
+ };
964
+
965
+ /**
966
+ * Root `@capxul/sdk` client factory.
967
+ *
968
+ * Canonical construction per sdk-surface.md §3a:
969
+ *
970
+ * ```ts
971
+ * import { createCapxulClient, createLocalSigner } from "@capxul/sdk";
972
+ *
973
+ * const capxul = createCapxulClient({
974
+ * apiKey: process.env.CAPXUL_API_KEY!,
975
+ * signer: createLocalSigner(process.env.CAPXUL_PRIVATE_KEY as `0x${string}`),
976
+ * });
977
+ * ```
978
+ *
979
+ * Three auth modes are mutually exclusive:
980
+ * - `apiKey` — server-to-server partner flows (`cap_live_` / `cap_test_`)
981
+ * - `publishableKey` — installed-app flows with OTP-established human
982
+ * sessions (`cap_pk_live_` / `cap_pk_test_`); sessions persist
983
+ * via the SDK's auth adapter (file / cookie depending on runtime)
984
+ * - neither — unauthenticated only; useful for `auth.sendOtp` +
985
+ * `auth.verifyOtp` bootstrap before a session exists
986
+ *
987
+ * The `signer` (viem `Account`) is required for methods that submit
988
+ * on-chain UserOperations (payments, withdrawals, transfers) per
989
+ * CANON.md §4.28.
990
+ */
991
+
992
+ type CapxulSigningConfig = {
993
+ /** EVM chain ID (currently Base Sepolia). */
994
+ readonly chainId: number;
995
+ /** JSON-RPC URL for UserOperation submission. */
996
+ readonly rpcUrl: string;
997
+ /** Alchemy gas policy ID for UserOperation sponsorship. */
998
+ readonly gasPolicyId: string;
999
+ };
1000
+ type CapxulAuthConfig = {
1001
+ /**
1002
+ * Convex `.site` URL that hosts the BetterAuth endpoints.
1003
+ *
1004
+ * Optional when the client is configured with a publishable key and
1005
+ * lazy bootstrap resolves the runtime URLs instead.
1006
+ */
1007
+ readonly baseUrl?: string;
1008
+ /** Optional explicit Convex token endpoint. Defaults to `${baseUrl}/api/auth/convex/token`. */
1009
+ readonly convexTokenUrl?: string;
1010
+ /** Scenario/browser-local session store shared by auth + onboarding hooks. */
1011
+ readonly sessionStore?: AuthSessionStore;
1012
+ /**
1013
+ * Optional bridge for environments that can build an authenticated data
1014
+ * client after BetterAuth returns a session.
1015
+ */
1016
+ readonly createDataClient?: (session: Session) => Promise<CapxulDataClient>;
1017
+ };
1018
+ type CapxulConfig = {
1019
+ /** Server-to-server partner key. Mutually exclusive with `publishableKey`. */
1020
+ readonly apiKey?: string;
1021
+ /**
1022
+ * Installed-app publishable key. Pairs with an OTP-established human
1023
+ * session persisted by the SDK's auth adapter.
1024
+ */
1025
+ readonly publishableKey?: string;
1026
+ /**
1027
+ * viem `Account` used to sign UserOperations for on-chain methods
1028
+ * (payments, withdrawals, transfers) per CANON.md §4.28.
1029
+ */
1030
+ readonly signer?: Account$1;
1031
+ /**
1032
+ * Inject an authenticated Convex data client.
1033
+ *
1034
+ * Slice F.2 uses this for the restart payment + operation runtime
1035
+ * path while the `/v1/*` service-token bridge remains unfinished.
1036
+ */
1037
+ readonly data?: CapxulDataClient;
1038
+ /**
1039
+ * Chain + bundler configuration for on-chain submission.
1040
+ *
1041
+ * Required alongside `signer` for runtime `payments.create`.
1042
+ */
1043
+ readonly signing?: CapxulSigningConfig;
1044
+ /** Human OTP auth runtime configuration. */
1045
+ readonly auth?: CapxulAuthConfig;
1046
+ /**
1047
+ * Override the API base URL. Defaults to `https://api.capxul.com`
1048
+ * in production builds; point at `http://localhost:<port>/v1` for
1049
+ * local development against Convex's httpAction router.
1050
+ */
1051
+ readonly baseUrl?: string;
1052
+ /**
1053
+ * Inject a `fetch` implementation. Defaults to global `fetch`. Used
1054
+ * for testing or to plug in `undici` / `node-fetch` in older Node
1055
+ * environments.
1056
+ */
1057
+ readonly fetch?: typeof fetch;
1058
+ /**
1059
+ * @internal
1060
+ *
1061
+ * Inject a pre-built `HttpTransport`. The `@capxul/sdk-react`
1062
+ * `CapxulProvider` uses this in the lazy-DX path (ADR #14c) so the
1063
+ * provider's externally-built transport is the SAME singleton used by
1064
+ * the auth client's bootstrap calls. Without injection, the SDK would
1065
+ * build a second transport internally — the `useCapxulStatus()` hook
1066
+ * would observe a different state machine than the one auth methods
1067
+ * actually drive.
1068
+ *
1069
+ * Underscored to mark it as an internal SDK seam, not a partner-facing
1070
+ * config field. Do not document publicly.
1071
+ */
1072
+ readonly _transport?: HttpTransport;
1073
+ };
1074
+ /**
1075
+ * Per-call factories for the three Stack-1 XState v5 flow machines.
1076
+ *
1077
+ * Each factory returns a fresh machine instance bound to this
1078
+ * `CapxulClient`. The consumer is responsible for creating a single
1079
+ * actor (e.g. via `createActor` / React's `useMemo` + `useActor`) and
1080
+ * keeping it alive for the duration of the flow. Calling a factory
1081
+ * twice yields two independent machines — useful for parallel
1082
+ * onboarding sessions in tests, never the desired pattern in app code.
1083
+ *
1084
+ * The return types are intentionally erased to `AnyStateMachine` to
1085
+ * keep this surface stable across XState v5 type-parameter changes;
1086
+ * downstream consumers (`@capxul/sdk-react` hooks, the e2e harness's
1087
+ * `xstateFlowSequence` primitive) re-import the precise types from
1088
+ * `./flows/*` when they need them.
1089
+ */
1090
+ type CapxulFlowFactories = {
1091
+ readonly auth: () => AnyStateMachine;
1092
+ readonly onboarding: () => AnyStateMachine;
1093
+ readonly provisioning: () => AnyStateMachine;
1094
+ };
1095
+ type CapxulClient = {
1096
+ /**
1097
+ * @internal
1098
+ *
1099
+ * Per-client UUID minted at construction. Used as a TanStack Query
1100
+ * cache-key prefix to isolate per-client cache when multiple
1101
+ * `CapxulClient` instances are mounted in the same React tree.
1102
+ *
1103
+ * MUST NOT be passed to `identify()`, `track()`, or any analytics
1104
+ * surface — PostHog has no way to distinguish "namespace UUID" from
1105
+ * "person UUID" and conflating the two creates fake users in
1106
+ * analytics. Treat as opaque cache implementation detail.
1107
+ *
1108
+ * Stable for the lifetime of the client; new on every
1109
+ * `createCapxulClient()` call. See Codex P1 finding on PR #406.
1110
+ */
1111
+ readonly id: string;
1112
+ readonly auth: AuthClient;
1113
+ readonly me: MeClient;
1114
+ readonly accounts: AccountsClient;
1115
+ readonly organizations: OrganizationsClient;
1116
+ readonly payments: PaymentsClient;
1117
+ readonly transfers: TransfersClient;
1118
+ readonly withdrawals: WithdrawalsClient;
1119
+ readonly documents: DocumentsClient;
1120
+ readonly subAccounts: SubAccountsClient;
1121
+ readonly virtualAccounts: VirtualAccountsClient;
1122
+ readonly virtualCards: VirtualCardsClient;
1123
+ readonly externalAccounts: ExternalAccountsClient;
1124
+ readonly operations: OperationsClient;
1125
+ readonly webhookEndpoints: WebhookEndpointsClient;
1126
+ readonly webhookEvents: WebhookEventsClient;
1127
+ readonly apiKeys: ApiKeysClient;
1128
+ readonly flows: CapxulFlowFactories;
1129
+ };
1130
+ /**
1131
+ * Construct a Capxul client. Every method stub in Slice C throws
1132
+ * `NOT_IMPLEMENTED` per CANON.md §2 (types-first scaffold). Slice F.2
1133
+ * wires the restart `payments` + `operations` runtime path through an
1134
+ * injected authenticated Convex client; the broader `/v1/*` surface is
1135
+ * still pending.
1136
+ *
1137
+ * Two-pass construction: the per-domain clients (`auth`, `me`, …) are
1138
+ * built first, then `flows` is assigned with factories that close over
1139
+ * the fully-built `client` so the spawned XState machines can call
1140
+ * back into `client.auth.sendOtp`, `client.accounts.provisionPersonal`,
1141
+ * etc. The intermediate `clientWithoutFlows` value is typed without
1142
+ * `flows`; `Object.assign` mutates a single `flows` field on it before
1143
+ * the returned `CapxulClient` cast — minimal and contained.
1144
+ */
1145
+ declare function createCapxulClient(config?: CapxulConfig): CapxulClient;
1146
+
1147
+ export { type AccountProvisionPersonalInput as A, type BrowserCapxulConfig as B, type CapxulClient as C, type DocumentsClient as D, type ExternalAccountsClient as E, type HttpTransport as H, type LocalPrivateKeySignerProvider as L, type MeClient as M, type OperationsClient as O, type PaymentsClient as P, type Session as S, type TransfersClient as T, type VirtualAccountsClient as V, type WebhookEndpointCreateResult as W, type AccountsClient as a, type ApiKeyCreateResult as b, type ApiKeysClient as c, type AuthClient as d, type AuthSessionStore as e, type CapxulAuthConfig as f, type CapxulConfig as g, type CapxulDataClient as h, type CapxulFlowFactories as i, type CapxulSigningConfig as j, type OrgDocumentsClient as k, type OrgPaymentsClient as l, type OrgSafesClient as m, type OrgTransfersClient as n, type OrgTreasuryClient as o, type OrgWithdrawalsClient as p, type OrganizationsClient as q, type SubAccountsClient as r, type TransportRuntime as s, type TransportState as t, type VirtualCardsClient as u, type WebhookEndpointsClient as v, type WebhookEventsClient as w, type WithdrawalsClient as x, createCapxulClient as y, makeHttpTransport as z };