Before you start
- Create a sandbox account in a browser. Sign up at
https://sandbox.gethevn.comwith 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:signandrecipient:write. Every later call is re-checked against the allowlist — a request from an address you did not list is a403however correct the key and the signature are — and a route whose scope the key lacks is a403withdetails.requiredScope. - Save the private key into your environment. The browser shows it once. Write it to
$HEVN_KEY_PEMwith mode0600; 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:
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.
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: Keep both:
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
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. The
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
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.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 A
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.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
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 Keep the
userId from step 1 goes in X-Hevn-Account, because
that header is the only thing that selects an account on /client*.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
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: A
payout is the record step 7 returned.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
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;
transactionHashis 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.