POST /dapi/v1/swaps prices and reserves the move,
POST /dapi/v1/swaps/{swapId}/confirm authorizes it. A client holding euros that owes dollars swaps
before it pays out, and the money never leaves its own name.
acting_as sets the header
that picks whose money moves:
Send X-Hevn-Account: cl_… with your own access token to act for one client. On a resource route
like GET /banks the header is optional: omit it and the call acts on your integrator account
instead. The singular /client* routes require it — the header is the only thing that names the
account — and /clients and /escrow* refuse it.
The accounts
Both sides are named from one vocabulary, the same one the balance reads back and a payout’ssourceAccount takes. USDC and EURC are the stablecoins on the client’s wallet; FDIC_USD is
dollars a partner bank holds for it:
The two sides must differ, and both must be accounts that client actually holds. An account it does
not hold is
422 account_unavailable — a client with no custodial virtual account cannot name
FDIC_USD. A pair nothing can serve right now is 422 swap_route_unavailable.
Price it first
POST /dapi/v1/swaps/preview takes the same accounts and amount without a publicKey, compares
every route that can serve the pair, and answers the best one. It reserves nothing, signs nothing and
returns no swapId, so it is safe to call on every keystroke of a form.
Response — 200
amount is what leaves the source account, amountTo is what has to
arrive on the destination. Sending both, or neither, is 422 validation_failed.
minimumToAmount is the floor a route with slippage guarantees; estimated: true marks a move whose
delivered amount is only known on arrival, and then etaHours says how long that takes. A locked
price carries expiresAt and nothing else has to be read.
Reserve and sign
POST /dapi/v1/swaps prices the move again, fixes it, and returns the approval to sign. The response
tells you what that approval authorizes:
Either way you sign
approval.payload and post it to the same confirm route. The difference is what
HEVN does with the co-signature, not what your code does with the approval.
Response — 201, Location: /dapi/v1/swaps/swp_9f2c1ab84d
authorization is debit, check debit before you sign — it is decoded out of the operation
itself, not echoed from your request, and it is the one cross-check a signer has
(Signing).
200 when settlement landed inside the request and 202 submitted when it did
not; in the second case pollUrl names the read route. Confirm is single use: the same signature a
second time is 409 funding_attempt_expired on a debit swap and 410 approval_expired on an
intent one. Either way the move already happened, and the way to check on it is
GET /dapi/v1/swaps/{swapId}, never another confirm.
Read it back
GET /dapi/v1/swaps/{swapId} carries the lifecycle, the accounts it ran between, the terms it was
fixed at, and transactionId once the move is on the client’s ledger.
Response — 200
GET /dapi/v1/transactions shows the result without reading this route at all
(Balances and transactions).
Retries
DeriveIdempotency-Key from an id your own system already owns, pass it in from the caller, and
keep it identical across every retry of the same payment.
Idempotency-Replayed: true; the same key with different accounts or a different amount is
409 idempotency_key_reused, which is the guarantee that a repeated call is never a second
conversion.
Paying straight out of the custodial balance
A client that holdsFDIC_USD does not have to swap before it pays. POST /dapi/v1/payouts with
"sourceAccount": "FDIC_USD" spends that balance directly: the payout is authorized by an intent
signature instead of a debit, so the response carries authorization: "intent" and no debit, and
confirm is unchanged (Payouts). Use a swap when the client wants the money on
its wallet, and a payout when it wants a beneficiary paid.
In the sandbox
Swaps are the one money route the sandbox does not serve. The emulated chain has no exchange venue behind it and the emulator issues no custodial dollar balance, soPOST /dapi/v1/swaps there answers
a refusal rather than a quote. Build against the contract on this page and exercise it in production
(Sandbox).
Next: Balances and transactions
Read a client’s balance, walk its ledger with a cursor, export a statement.