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 you drive is one POST /dapi/v1/escrow/{escrowId}/actions that you sign with your developer key, on your own wallet. You are the operator of every deal you create; escrow never takes X-Hevn-Account, because the caller is always you. Like /clients* and /connect/sessions, it refuses the header with 400 account_scope_conflict and details.reason = "selfScopedRoute". See Sessions.
The buyer approves a deal with their own key: the spend permission that lets you pull the money later lives on the buyer’s wallet, and your key never signs there. The sign-in window does not offer escrow approvals yet, so POST /dapi/v1/escrow with a client linked through Sign in with HEVN as the buyer answers 403 account_not_controlled. Talk to HEVN before you build on escrow. The rest of this page describes the deal and the operator actions as they work once the buyer has approved.

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, and the buyer’s own 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 linked to you. HEVN binds sender and receiver through the relationship Sign in with HEVN writes; an account you merely referred never qualifies, 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 linked to you 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 still exists 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 let the buyer approve it

One call creates the deal and prepares the buyer’s approval — the on-chain permission that lets you pull the money later. The response echoes the create’s key as action.idempotencyKey. The approval is the buyer’s to sign with their own key, not yours.
Response — 201, Location: /dapi/v1/escrow/esc_5Qb4e17c9d
Nothing has moved. availableActions becomes ["authorize", "charge"] once the buyer’s approval lands on chain; read the deal until it does.
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 and refund keep working when your relationship with a client is paused or your profile is suspended, and so does the buyer’s reclaim, 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.