Skip to main content
Escrow locks one client’s funds in an on-chain contract while another delivers. The buyer’s funds stay in the buyer’s own wallet until you authorize a lock, they then sit in the escrow contract where neither party — and neither HEVN nor you — can spend them outside its rules, and they reach the seller only when you capture. A voided or reclaimed deal can still be refunded, if something was captured before the hold was released. Every transition is one POST /dapi/v1/escrow/{escrowId}/actions that you sign with your developer key. You are the operator of every deal you create; escrow never takes X-Hevn-Account, because the caller is always you. It is one of two self-scoped families — the other is POST /clients and GET /clients — and both refuse the header the same way, with 400 account_scope_conflict and details.reason = "selfScopedRoute". See Sessions.

The states money is in

A deal carries two amounts, and they are what you branch on:
  • capturableAmount — money out of the buyer’s wallet, held in the contract, not yet paid to the seller. capture moves it to the seller, void returns it to the buyer, reclaim returns it after the hold window.
  • refundableAmount — money already paid to the seller that you can still send back. A refund leaves your own wallet, not the seller’s, so keep a working balance in the deal’s token.
status is a label for the last thing that happened, not a decision input. Read availableActions — the server computes it from the amounts, the windows and what already landed on chain — and pick from it. A draft nobody approved in time has an empty availableActions; there is no expired status and nothing sweeps a stale deal. Amounts are decimal strings in the token’s major unit, rendered at the token’s precision: "100.000000" for USDC. token is a symbol — USDC or EURC — never an address. The full status vocabulary is in Escrow actions.

The three parties

All three must be different accounts, and both parties must be clients you created. HEVN binds sender and receiver through the sub-user relationship that POST /clients writes, so only accounts you provisioned through this API qualify; an account you merely referred never does, and a stranger’s account id answers 422 receiver_not_a_client or 404 client_not_found. The addresses are each party’s Base smart wallet at creation time, and the deal is immutable: its terms are hashed into an on-chain payment record.

The three windows

You give three durations and HEVN resolves them once, at creation, each measured from the end of the one before it. A duration is ^\d{1,4}[smhd]$30m, 1h, 14d. You never compute a timestamp, which is what makes a retry safe: repeating POST /dapi/v1/escrow with the same Idempotency-Key returns the same deal with the same absolute windows, no matter how much later it arrives. Different durations under the same key answer 409 idempotency_key_reused with details.escrowId. void is the exception with no clock on it: while anything is capturable, you can always hand it back.

What it costs

feeBps on the deal is your ceiling, an integer in basis points. capture and charge may take any fee up to it; the fee goes to your own Base smart wallet, which HEVN derives — there is no feeReceiver to send. fee = amount × feeBps / 10000, the receiver gets the rest, and a refund returns the gross amount from your wallet without clawing the fee back. Set the ceiling at creation. It is part of the immutable deal, so a deal created with feeBps: 0 can never take a commission. HEVN sponsors the gas for every action and charges nothing on top.

Before you start

  • Both parties are clients of yours and are ready — see Clients.
  • Your account may operate escrow. HEVN enables that, in the sandbox as in production; nothing in the API grants it. Without it every escrow call is refused — see Going live.
  • The buyer’s wallet holds the token when you authorize, not when you create. Creating a deal moves nothing.
  • Call escrow with your own access token and no X-Hevn-Account — the header answers 400 account_scope_conflict on every escrow route.
  • Your developer key registration is active and the call leaves an allowlisted source IP. Both are re-checked on every request, and again immediately before HEVN co-signs an action — see Developer key.
Derive Idempotency-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.
Never generate the key inside the helper that sends the request, and never rotate it on a retry — both turn one payment into two. The format and the replay windows are in Conventions.

A marketplace order, end to end

Every example below uses the client from HTTP client and the sign_payload helper from Signing. Order A-1187: Northwind Trading Ltd (cl_7YQ2Kf3mN8) buys 100 USDC of parts from Ardenne Fabrication SARL (cl_2ABxR9dL4m), and you take 2.5% when it ships.
1

Open the deal and approve the spend permission

One call creates the deal and prepares the buyer’s approval — the on-chain permission that lets you pull the money later. Confirm it with the same key the create carried; the response echoes it as action.idempotencyKey.
Response — 201, Location: /dapi/v1/escrow/esc_5Qb4e17c9d
Nothing has moved. availableActions becomes ["authorize", "charge"] once the approval lands on chain — if the confirm answers 202, poll it to settlement first (Escrow actions).
2

Lock the buyer's funds in the contract

authorize pulls the amount out of the buyer’s wallet into the escrow contract. It happens once per deal: authorize less than maxAmount and the remainder is unusable, so authorize the order total.
Response — 200
The buyer’s balance is down 100 USDC, the seller has nothing yet, and you have 14 days to deliver.
3

Ship it, and capture with your commission

capture pays the seller and takes your fee in the same action. It is repeatable up to capturableAmount, so a partial shipment is a partial capture.
The seller receives 97.50 USDC, 2.50 lands on your wallet, and the deal ends captured with refundableAmount: "100.000000" — the gross is what you can still send back.

When the order does not go to plan

void, refund and reclaim keep working when your relationship with a client is paused or your profile is suspended, so held money is never stranded.
A refund is paid by your own wallet, not out of the deal. If you owe refunds, keep a balance in the deal’s token — an empty operator wallet turns refund into 409 simulation_failed.

Next: Escrow actions

Every action, the window it is legal in, the amount it takes, and the state it leaves behind.