> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kash.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# Partner quickstart

> End to end on staging: create an account for a user, fund it, trade, receive webhooks and withdraw.

This walks through one user's journey on staging, first with `curl` and then with `@kashdao/sdk`. You need a partner test key with a webhook URL, which ZeroID issues on request: see [Keys](https://docs.kash.bot/developer-docs/partner-integration/keys.md#ask-for-a-test-key).

```bash theme={null}
export KASH_API=https://api-staging.kash.bot/v1
export KASH_PARTNER_KEY=kash_test_...   # from your secret store
```

## 1. Create the user's account

When a user of Harbour Sports Picks opts in, create their account with your own id for them, their own address in your app, their country and their consent:

```bash theme={null}
curl -X POST "$KASH_API/partner/accounts" \
  -H "X-API-Key: $KASH_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-hsp-user-8841" \
  -d '{
    "externalId": "hsp-user-8841",
    "destination": { "network": "solana", "address": "8yYpcE7Jx9NmXNMGR6NGumBUu4UBpMTVQW44P9hwikyh" },
    "country": "GB",
    "consent": { "acceptedAt": "2026-11-06T10:15:00Z", "termsVersion": "hsp-kash-terms-2026-11" }
  }'
```

The answer is `202` with `account.accountId` and `status: "provisioning"`. Keep the `accountId` with your user:

```bash theme={null}
export ACCOUNT_ID=7a1c2e3d-4b5f-4a6e-8d7c-1b2a3c4d5e6f
```

## 2. Wait for `account.active`

Your webhook endpoint receives `account.active` with the account's Solana `depositAddress`. Or poll until `status` is `active`:

```bash theme={null}
curl "$KASH_API/partner/accounts/$ACCOUNT_ID" -H "X-API-Key: $KASH_PARTNER_KEY"
```

## 3. Fund it and read the balance

Ask ZeroID to fund the account with staging test USDC, and send the `accountId` (or the `depositAddress`) and the amount. You cannot mint test USDC yourself; see [Sandbox](https://docs.kash.bot/developer-docs/partner-integration/sandbox.md#test-usdc). Once ZeroID confirms, read the balance:

```bash theme={null}
curl "$KASH_API/balance" \
  -H "X-API-Key: $KASH_PARTNER_KEY" \
  -H "Kash-Account: $ACCOUNT_ID"
```

`balance.availableAtomic` is what the account can spend, in atomic USDC: `"25000000"` is 25 USDC.

## 4. Find a market and quote it

Markets and quotes act for no account, so send no `Kash-Account` header:

```bash theme={null}
curl "$KASH_API/markets?status=ACTIVE&category=sports&limit=5" \
  -H "X-API-Key: $KASH_PARTNER_KEY"

export MARKET_ID=...   # a market with "tradeable": true

curl "$KASH_API/markets/$MARKET_ID/quote?outcomeIndex=0&action=buy&amount=10000000" \
  -H "X-API-Key: $KASH_PARTNER_KEY"
```

## 5. Trade

```bash theme={null}
curl -X POST "$KASH_API/trades" \
  -H "X-API-Key: $KASH_PARTNER_KEY" \
  -H "Kash-Account: $ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "marketId": "'"$MARKET_ID"'",
    "outcomeIndex": 0,
    "amount": "10",
    "side": "buy",
    "metadata": { "externalId": "hsp-user-8841" }
  }'
```

The trade `amount` is decimal USDC (`"10"` is 10 USDC). The answer is `201` with the trade in `pending`, and your endpoint receives `trade.completed`, `trade.failed` or `trade.rejected` when it ends.

## 6. Withdraw

Quote first, then withdraw. `Idempotency-Key` is required:

```bash theme={null}
curl "$KASH_API/partner/accounts/$ACCOUNT_ID/withdrawals/quote?amountAtomic=5000000" \
  -H "X-API-Key: $KASH_PARTNER_KEY"

curl -X POST "$KASH_API/partner/accounts/$ACCOUNT_ID/withdrawals" \
  -H "X-API-Key: $KASH_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: hsp-withdrawal-90311" \
  -d '{ "amountAtomic": "5000000" }'
```

The answer is `202` with the withdrawal in `pending`. You receive `withdrawal.submitted`, then `withdrawal.completed` when the USDC reaches the user's destination.

## The same with the SDK

This uses `@kashdao/sdk` 0.4.0 (see [SDK](https://docs.kash.bot/developer-docs/partner-integration/overview.md#sdk)). Pass the user's `accountId` as `account` on the calls made for them; the SDK sends it as the `Kash-Account` header. The `partnerAccounts` methods name the account in the path instead.

```ts theme={null}
import { randomUUID } from 'node:crypto';
import { KashClient } from '@kashdao/sdk';

const kash = new KashClient({ apiKey: process.env.KASH_PARTNER_KEY! }); // a kash_test_ key goes to staging

// 1. Create the account when the user opts in. Keep the key with the pending
//    onboarding and reuse it on every retry.
const { account } = await kash.partnerAccounts.create(
  {
    externalId: 'hsp-user-8841',
    destination: { network: 'solana', address: '8yYpcE7Jx9NmXNMGR6NGumBUu4UBpMTVQW44P9hwikyh' },
    country: 'GB',
    consent: { acceptedAt: new Date().toISOString(), termsVersion: 'hsp-kash-terms-2026-11' },
  },
  { idempotencyKey: 'create-hsp-user-8841' },
);
const accountId = account.accountId;

// 2. Wait until it is active (or handle the account.active webhook).
const active = await kash.partnerAccounts.waitUntilActive(accountId);
console.log('fund', active.depositAddress);

// 3. Once funded, read what the account can spend (atomic USDC).
const { availableAtomic } = await kash.balance.get({ account: accountId });
if (BigInt(availableAtomic) < 10_000_000n) throw new Error('fund the account first');

// 4. Markets and quotes act for no account.
const page = await kash.markets.list({ status: 'ACTIVE', category: 'sports', limit: 20 });
const market = page.data.find((m) => m.tradeable);
if (!market) throw new Error('no tradeable market');
const quote = await kash.quotes.buy({ marketId: market.id, outcomeIndex: 0, amountUsdcAtomic: '10000000' });
console.log('10 USDC buys', quote.tokensOut, 'outcome tokens');

// 5. Trade for the account. The trade amount is decimal USDC.
const trade = await kash.trades.create(
  { marketId: market.id, outcomeIndex: 0, amount: '10', side: 'buy', metadata: { externalId: 'hsp-user-8841' } },
  { account: accountId },
);
console.log('trade', trade.id, trade.status); // the outcome arrives by webhook

// 6. Quote a withdrawal to the registered destination, then send it.
const withdrawalQuote = await kash.partnerAccounts.withdrawals.quote(accountId, { amountAtomic: '5000000' });
console.log('at least', withdrawalQuote.receiveAtomic, 'arrives');
const withdrawalKey = randomUUID(); // keep it with the request on your side, and reuse it on retry
const { withdrawal } = await kash.partnerAccounts.withdrawals.create(
  accountId,
  { amountAtomic: '5000000' },
  { idempotencyKey: withdrawalKey },
);
console.log('withdrawal', withdrawal.withdrawalId, withdrawal.status);
```

To receive and verify the webhooks, see the receiver on [Webhooks](https://docs.kash.bot/developer-docs/partner-integration/webhooks.md#with-the-sdk).

## Next

> [card] [Accounts](https://docs.kash.bot/developer-docs/partner-integration/accounts.md)
>
> The full account lifecycle.

> [card] [Go-live checklist](https://docs.kash.bot/developer-docs/partner-integration/go-live.md)
>
> Before production.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.