Skip to main content

Quickstart

This walkthrough takes you from an API key to a settled deposit with a webhook in hand, on sandbox, using the Sui direct rail (rcusdp-sui) and an individual account.

Prerequisites: a sandbox key (tbk_test_*), a Sui testnet wallet address for your test user (any WaaS sandbox wallet or sui client new-address ed25519), and test funds.

export BASE="https://rwa-api-sandbox.tbook.com"
export KEY="tbk_test_..."

1. Discover assets

curl -H "Authorization: Bearer $KEY" $BASE/v1/assets

The catalog is already filtered to assets enabled for your organization. Note rcusdpvaults[0].vaultId = "rcusdp-sui", settlement T+1, minDeposit: "1".

2. Create an account for your user

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": "0xYOUR_TEST_WALLET"}],
"compliance": {"kyc": {"attested": true, "provider": "sandbox-kyc", "ref": "kyc_demo"}}
}'

Response: {"accountId": "acct_7f3a…", …}. Export it: export ACCT=acct_7f3a…

externalId is your identifier — TBook never needs your users' PII.

3. Build an unsigned deposit

curl -X POST $BASE/v1/vaults/rcusdp-sui/tx/deposit \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"accountId": "'$ACCT'", "amount": "100.00"}'

Response:

{
"intentId": "txi_01h…",
"vaultId": "rcusdp-sui",
"type": "deposit",
"chain": "sui",
"rail": "direct",
"transaction": { "format": "sui:tx-bytes-base64", "data": "AAAC…" },
"summary": { "amount": "100", "sharePrice": "1.0275", "estimatedShares": "97.323601" },
"message": "Deposit 100 USDC into rcusdp-sui",
"expiresAt": "2026-06-15T08:10:00Z"
}

Nothing has moved yet — transaction.data is unsigned. Sui transactions stay valid for about 10 minutes (expiresAt); if one expires unsigned, rebuild with a new Idempotency-Key.

4. Sign and submit

With a WaaS provider, pass transaction.data to its signing endpoint. With the Sui CLI/SDK for this walkthrough:

import { SuiClient, getFullnodeUrl } from "@mysten/sui/client";
import { Transaction } from "@mysten/sui/transactions";

const client = new SuiClient({ url: getFullnodeUrl("testnet") });
const tx = Transaction.from(Buffer.from(intent.transaction.data, "base64"));
const result = await client.signAndExecuteTransaction({ signer: keypair, transaction: tx });
console.log(result.digest); // e.g. "8vJk…"
curl -X POST $BASE/v1/transactions/txi_01h…/confirm \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"digest": "8vJk…"}'

The response is {"intentId": "txi_01h…", "status": "submitted"}. The indexer flips the intent to confirmed on its next pass (about a minute) even if you skip this step — but reporting the digest lets it match your transaction exactly instead of heuristically.

6. Register a webhook

curl -X POST $BASE/v1/webhooks \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"url": "https://your-server.example/tbook", "events": ["transaction.*", "vault.*"]}'

Save the returned secret (whsec_…) — it is shown once. Verify every delivery; see Webhook signatures.

7. Trigger settlement (sandbox-only)

In production the cycle settles on its own (T+1). On sandbox, settle on demand:

curl -X POST $BASE/v1/sandbox/settle \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"vaultId": "rcusdp-sui"}'

This returns 202 and records a sandbox.settle.requested event — it triggers the operator settlement cycle rather than executing it inline, so poll GET /v1/events to see the request status. Once the cycle runs (typically a few minutes on sandbox), your endpoint receives:

{
"id": "evt_01h…",
"type": "transaction.deposit.settled",
"created": "2026-06-15T08:14:05Z",
"data": {
"accountId": "acct_7f3a…",
"externalId": "user-8492",
"vaultId": "rcusdp-sui",
"intentId": "txi_01h…",
"recordId": "42",
"shares": "97.323601"
}
}

The settled event is emitted when the **operator's settlement transaction** lands — its payload carries the `recordId` and the exact `shares` minted; it does not echo your submission digest.

8. Read back positions and earnings

curl -H "Authorization: Bearer $KEY" $BASE/v1/accounts/$ACCT/positions
curl -H "Authorization: Bearer $KEY" "$BASE/v1/accounts/$ACCT/earnings?assetId=rcusdp"

You now have the full loop: catalog → account → build → sign → confirm → settle → webhook → positions.

Where to go next

  • Redeem: POST /v1/vaults/rcusdp-sui/tx/redeem — on settlement the proceeds are paid straight to the account's wallet (transaction.redeem.settled with amount) — see Transactions.
  • Pick your real account model: Account Models — this quickstart used individual; omnibus and treasury change who signs and who books.
  • Handle every event: Webhook event catalog.
  • Go deeper on conventions: idempotency, errors, pagination.