Skip to main content

Accounts

An account is an investment principal under your organization — see Account Models for choosing between individual, omnibus, treasury, and business. All account endpoints require a secret key.

The Account object

FieldTypeNotes
accountIdstringacct_…
externalIdstringYour identifier (user id, merchant id, ledger ref). Unique per organization, ≤128 chars, immutable. Never send PII.
typeenumindividual · omnibus · treasury · businessimmutable after creation
custodyenumwaas · self · org — descriptive (who controls the wallet)
channelstring?Free-form analytics tag, ≤64 chars (e.g. "mobile-app", "merchant-treasury")
wallets[]object[]{chain, address, addedAt} — max one per chain; addresses immutable once set
complianceobject{kyc?: {attested, provider, ref, attestedAt}, kyb?: {…}} — your attestation, see below
statusenumactive · frozen (set by operations; blocks new transaction builds)
createdAttimestamp

Compliance rules: individual and omnibus accounts need compliance.kyc.attested: true before their first deposit (omnibus = aggregate attestation for the pool). business accounts need compliance.kyb. treasury accounts need nothing per-account (your organization's KYB at onboarding covers them).


POST /v1/accounts

Create an account. Supports Idempotency-Key.

Body:

FieldRequiredNotes
externalIdyesunique per organization
typeyesone of the four account types
custodyyeswaas · self · org
wallets[]yes (≥1){chain: "sui"|"solana", address} — address format validated per chain
channelnoanalytics tag
complianceconditionalsee compliance rules above
curl -X POST $BASE/v1/accounts \
-H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"externalId": "user-8492",
"type": "individual",
"custody": "waas",
"wallets": [{"chain": "sui", "address": "0xabc…"}],
"compliance": {"kyc": {"attested": true, "provider": "your-kyc", "ref": "kyc_123"}}
}'

Response 201 — the Account object.

Errors:

CodeWhen
conflict (409)A wallet address is already bound to any account (yours or another organization's), or externalId already used
invalid_requestBad address format for the chain; missing required compliance attestation

GET /v1/accounts/:accountId

Returns the Account object. not_found if it doesn't exist or belongs to another organization.

GET /v1/accounts (list / lookup)

Query: externalId= (exact lookup) · type= · channel= · limit= · cursor=.

curl -H "Authorization: Bearer $KEY" "$BASE/v1/accounts?externalId=user-8492"

Paginated: {data, nextCursor, hasMore}.


PATCH /v1/accounts/:accountId

Supports Idempotency-Key. May:

  • add a wallet for a chain the account doesn't have yet (wallets is append-only per chain; exactly one wallet per PATCH call),
  • update compliance,
  • update channel.

May not change type, externalId, or any existing address — these return invalid_request. Wallet migration is a managed operations flow; contact TBook.

# Attest KYC on an existing account before its first deposit
curl -X PATCH $BASE/v1/accounts/acct_7f3a… \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"compliance": {"kyc": {"attested": true, "provider": "your-kyc", "ref": "kyc_123"}}}'

Webhook

account.created fires on creation with {accountId, externalId, type}.