Skip to main content
In about twenty minutes you will have a client company that holds 6 testnet USDC and has sent 5 of them out of its own wallet, signed by your key. Nine steps, all of them in the sandbox.

Before you start

  • Create a sandbox account in a browser. Sign up at https://sandbox.gethevn.com with your work email. Sandbox and production are separate accounts; nothing you do here touches real money.
  • Create a developer key, in the same browser. Open Settings → Partner program → Developer keys and create one. You set two things that can never be changed afterwards: the IP allowlist, which for this quickstart is the egress address of the machine you will run it from, and the scopes, which for this quickstart are payout:sign and recipient:write. Every later call is re-checked against the allowlist — a request from an address you did not list is a 403 however correct the key and the signature are — and a route whose scope the key lacks is a 403 with details.requiredScope.
  • Save the private key into your environment. The browser shows it once. Write it to $HEVN_KEY_PEM with mode 0600; HEVN never holds it and cannot show it again. Walk-through: Developer key.
  • Set the environment and install two dependencies. Everything after that is code.
Every example on these pages reads the same variables:
Three more come out of the first two: HEVN_ACCESS_TOKEN, the one-hour token logging in returns; HEVN_USER_ID, your own account’s cl_… id, which the same response returns as userId and which the /client* routes need in X-Hevn-Account when you read your own account; and HEVN_PUBLIC_KEY, the base64 public half of the PEM, which POST /dapi/v1/payouts takes as publicKey.
Nothing crosses between the two environments: developer keys, clients, tokens and rail ids are per-environment, and a sandbox token is refused in production.
The sandbox is the same API against one emulated partner on Base Sepolia. Its money comes from a shared faucet account: at most 100 tokens per credit, at least 0.10, and 60 money calls per account per hour. GET /dapi/v1/sandbox/treasury reports the live ceiling. Full table in Limits.

Nine steps

1

Log in

Two calls: POST /dapi/v1/auth/challenge returns a payload built by HEVN, and POST /dapi/v1/auth/token exchanges your signature over it for a session. The helpers this uses — load_key, public_key_b64, sign_bytes, sign_payload — are on Developer key and Signing.
Response
Keep both: export HEVN_ACCESS_TOKEN=… and export HEVN_USER_ID=cl_9f2c….
2

Check that your account may create clients

Being an integrator is not something the API grants — HEVN switches it on for your account, in the sandbox as in production. The cheapest confirmation is a list that answers instead of refusing. GET /clients is the collection you own, so it is the one call on this page that must not carry X-Hevn-Account; sending it is 400 account_scope_conflict.
Response
The hevn / api client, key and poll_until in every tab below are the reference client — copy it once and the rest of this page is three lines a step.An empty page means you are an integrator with no clients yet — carry on. If the next step answers 403 integrator_inactive or 403 client_creation_not_enabled, the flag is not on your account yet; ask HEVN before you write any more code. See Going live.
3

Create a client and wait for it to be ready

phone is optional here and required later by every bank rail, so send it now.
The 201 answers status: "provisioning", an id you can already read, and a pollUrl of /dapi/v1/client — a path that names no account by itself. The id goes in X-Hevn-Account instead, which is how every read of one client works. Poll it every two seconds; it becomes ready in about thirty seconds, when the client’s wallet exists.
Response
4

Fund the client's wallet

The sandbox mints emulated money. Without bankId this is a token transfer straight to the client’s wallet; the X-Hevn-Account header that northwind carries is what makes the call act for the client.
A 200 means the tokens landed; a 202 means they are on their way and the same request, with the same key, is safe to repeat.
5

Read the balance you just created

/client/balance names no client in its path either: the header picks the account, and leaving it out is a 422 for a missing header rather than a read of your own wallet.
Response
That balance is read from Base Sepolia, not from a HEVN table.
6

Save a contact

Pay the money to an address you control: your own account’s wallet. Read it with the same balance route, acting as yourself — the userId from step 1 goes in X-Hevn-Account, because that header is the only thing that selects an account on /client*.
Keep the ct_… id from the response: export HEVN_CONTACT_ID=ct_3K9…. user_id is the userId login returned in step 1.
7

Prepare the payout

publicKey says which of your keys will sign this payment.
Response
A contact that is a wallet address makes this an on-chain payout — kind says onchain, there is no conversion, and quote carries no rate and no fee. contact is the snapshot of the saved destination, fixed when the payment was booked. debit is what will actually leave the wallet, decoded from the operation you are about to sign, and for a wallet contact its address is that destination. approval.payload is the bytes to sign, live for 120 seconds.quickstart-payout-1 names this payment. Re-run this step with the same key and you replay the payout you already have, at the same price; change the key and you send twice.
8

Check the debit, sign it, confirm

Check the terms against what you meant to send, then sign the decoded payload and confirm. Nothing here re-prices anything: payout is the record step 7 returned.
A 200 carries status: "settled" and the transactionHash. A 202 carries status: "submitted": the operation is on its way and has no receipt yet, so confirm again with the same body until you get a 200. Confirm is always safe to repeat and never pays twice.
9

Read the ledger

A row carries its amounts as two sides — from is what left the source, to is what arrived — rather than a single amount. On this payout both are 5.000000 USDC.The 5 USDC that left in step 8 is there with its txHash, and the same 5 USDC are now in your own account’s balance — read it with the balance call from step 5, with $HEVN_USER_ID in X-Hevn-Account.

What just happened

  • Your key, not a password. Login was a signature over a payload HEVN built, and the payout was a second signature over an operation HEVN built. Neither exposes a secret you could leak twice. See Signing.
  • The client is a real account. It has its own wallet, its own ledger and its own legal identity — you act for it with one header. See Accounts and control.
  • The money is real testnet money. It moved on Base Sepolia; transactionHash is on chain.
  • Every constant came out of an earlier response. Client id, wallet address, contact id, approval payload — nothing was invented.
  • One key was yours to choose: the Idempotency-Key. It names the payment, so a retry is the same payment. See Conventions.

What this quickstart did not do

It never touched fiat. Getting the client its own account details, and paying a bank account with a currency conversion, needs a client the partner has approved: the KYB document filled and its rail open. That is the next piece of work — Onboard a client, then Virtual accounts and Payouts.

Next: Accounts and control

Who can move a client’s money, and what happens if your key leaks.