Skip to main content
Each of your users who opts in gets their own Kash account with its own Solana wallet. You create it with your own id for the user, and the API answers with an accountId. Send that id in the Kash-Account header on every call you make for the user. All routes on this page need a partner key with the partner:accounts scope. They name the account in the path, so they refuse a Kash-Account header with 400 ACCOUNT_HEADER_NOT_ALLOWED.

Before you create an account

  • Consent. Create an account only after the user has agreed in your app, for example by tapping a button. That action is their consent to the API acting on the trade and withdrawal instructions you send for them. Send when they agreed and which terms they saw.
  • Country. Send the user’s real country. Kash’s country rules, including the block on sanctioned countries, apply to it at trade and withdrawal time. Account creation itself does not refuse by country. Update it with PATCH if it changes.
  • Destination. Register the user’s own address in your app. Every withdrawal goes there and nowhere else.

Create an account

Unknown fields are refused with 400 VALIDATION_FAILED. The answer is 202 Accepted. The account starts in provisioning, with no deposit address yet:
Every single-resource response carries the resource twice, under its own name (account) and under data. Read either. When the wallet is ready you receive the account.active webhook with the depositAddress. You can also poll GET /v1/partner/accounts/{accountId} until status is active.

Creating the same account twice

  • Same Idempotency-Key (a retry of the same request): the stored 202 is returned unchanged, with the header Idempotent-Replay: true. Nothing runs again.
  • Different Idempotency-Key, same externalId: the existing account is returned with 200 and _meta.idempotent: true. The body you sent is not applied to it: to change its destination or country, use PATCH.
  • After a release the externalId is free again. Creating it makes a new account with a new accountId.
See Idempotency.

Account statuses

An account that is provisioning or provisioning_failed has no wallet, so calls that read the account’s wallet (balance, portfolio, positions, trades) are refused with 409 ACCOUNT_NOT_ACTIVE until it is active.

When provisioning fails

You receive account.provisioning_failed with a reason: Release the account and create it again, which gives it a new accountId. If it recurs, contact ZeroID support with the accountId.

Read and find accounts

GET /v1/partner/accounts returns { data: Account[], pagination: { cursor, hasMore, limit }, _meta }, newest first, with cursor pagination. limit is 1 to 100, default 20. externalId is an exact match and returns an empty page when you have no account for that id. Released accounts are not listed. An account id that is unknown, malformed, released or another organisation’s is answered with the same 404 ACCOUNT_NOT_FOUND, so ids cannot be probed.

Change the destination or country

Send destination, country or both. The answer is 200 with the account. It works in any status except released.
A new destination pauses the account’s withdrawals for 24 hours. A withdrawal in that window is refused with 409 WITHDRAWALS_HELD and a Retry-After header. Every change is announced by the account.destination_changed webhook. If you receive one you did not make, suspend the account, revoke the key and contact ZeroID support.
  • Sending the destination the account already has changes nothing, does not restart the hold and sends no webhook.
  • A country change takes effect for the next trade and withdrawal. It sends no webhook.
  • A destination change answers 503 ROUTE_DISABLED when account changes are switched off, and 503 DEPENDENCY_UNAVAILABLE when that switch cannot be read. Nothing changed; retry.

Suspend and reactivate

  • Suspend moves an active account to suspended. Trades and withdrawals are refused until you reactivate it. The account keeps its funds, can still be read and released, and can still redeem winnings.
  • Reactivate moves a suspended account back to active.
  • Asking for the status the account already has answers 200 with _meta.idempotent: true and changes nothing.
  • Any other status answers 409 ACCOUNT_NOT_ACTIVE, and the detail names the status. A provisioning or provisioning_failed account can be neither suspended nor reactivated.
Suspend is how you stop one account quickly, for example when you suspect fraud on your side or receive a destination change you did not make.

Account resource

Next

Funding and balance

Fund the deposit address and read what is available.

Webhooks

Account, withdrawal, payout and trade events.