Skip to main content
Production differs in four ways: what HEVN must enable for you, what you re-create per environment, what stops being instant, and what starts being refused. The routes, bodies and error slugs are identical. 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.

What HEVN must enable

Three things are granted by HEVN rather than by the API — in the sandbox exactly as in production — and each one has a refusal that tells you it is missing. Confirm all three the same way you would in the sandbox: link one client, read GET /dapi/v1/banks for it, and check that the rails you expect are listed.

Nothing carries over

Keep both sets of credentials loadable at once and choose by HEVN_API: a deploy that points a production key at the sandbox host fails at login with 401 invalid_credentials, and nothing in that refusal says you swapped a variable. The allowlist is the second variable that fails this way. A key is pinned to the source IPs you gave it and cannot be edited, so a production deploy behind a different NAT answers 403 on every call although the key, the signature and the token are all correct. Enumerate the egress addresses of every host that will call HEVN — including the ones an autoscaler adds — before you create the production key. The allowed sites are the third. A redirectUri the production window does not list is refused before any popup opens, so add the production callback origin before the first customer tries to sign in.

What stops being instant

In the sandbox every row exists by the time the call returns. In production most of these are queues with humans or banks behind them. Every one of those is the same fix: a poller with backoff and a deadline, keyed on your own record. Both of the shapes you need are on the pages that produce them — poll_until in the guides and the full loop in HTTP client.

What production starts refusing

Refusals your sandbox runs never produced, because the emulator never argues:
  • 422 contact_payment_details_invalid — the receiving bank does not recognise the beneficiary. Usually the name. Correct the contact with PATCH /dapi/v1/contacts/{contactId} and book again.
  • 422 rail_requirements_unmet and 422 phone_required — a rail wants something the client has not given yet. GET /dapi/v1/banks/{rail}/requirements lists it.
  • 422 amount_below_minimum and 422 amount_above_maximum — real rail minimums replace the sandbox’s 0.10.
  • attention: {"kind": "rfi"} on a payout — the partner is holding the transfer pending a question. Nothing anyone signs moves it until the question is answered.
  • 503 provider_unavailable — a partner is down. Retry with backoff; do not re-book.
  • 429 rate_limited — the counters are enforced in production. Honour Retry-After. See Limits.

The checklist

1

Point at the production host

Set HEVN_API to https://api.hevn.finance/dapi/v1. Nothing else in your code changes.
2

Get the flags

Integrator profile, escrow if you need it, and the rails for your markets. Verify by listing rails for a real client, not by being told.
3

Create a production developer key

In the production app, with the production egress IPs in its allowlist. Save the private half the browser shows you to a file with mode 0600 on the machine that will hold it. Never copy the sandbox key, and never assume the sandbox allowlist carries over.
4

Configure the production sign-in window

In the production app, under Settings → Partner program → Developer → Sign-in window: your title, logo and colours, and every production origin your callback page is served from under Allowed sites. Check that your server binds each session’s state to the browser and keeps the client id in its own session — Sign in with HEVN.
5

Delete every /dapi/v1/sandbox call

There are four, and all four answer 404 in production. Whatever they drove — a deposit, a payin settling, a payout moving — now happens because a bank did it.
6

Replace instant reads with polling

Client ready, KYB decided, rail active, payin credited, payout settled after its holder approved it. Back off, cap the interval, set a deadline, and record the state on your side before you act on it.
7

Handle 429 and log X-Request-ID

One HTTP helper that sleeps for Retry-After, re-mints once on 401, and logs X-Request-ID on anything 5xx. Support asks for that id first.
8

Re-read your refusal handling

The sign-in window’s results — access_denied, already_registered, already_linked, expired — and, for payouts from your own account, the four funding codes: already_funded is success, funding_in_progress means wait, funding_attempt_expired means re-open with the same key, and payment_slot_consumed means this payout can never move money — book a new one. See Errors.
9

Rehearse losing the key

Create a second key before you need it, log in with it, and book a payout from your own account naming the new publicKey. Rotation is a field on POST /dapi/v1/payouts, not a migration — but only if the second key already exists and its allowlist covers the hosts that will use it. Delete the old key once the new one has carried a request.
10

Fund what production makes you fund

Escrow refunds leave your own wallet, and a payout debits the client’s. The sandbox faucet account covered both; now your balances and your customers’ do.
Run one real payment end to end before you point customers at it: one client linked through the production window, one rail, one small payout to an account you control approved in the window, reconciled from GET /dapi/v1/transactions. Every difference on this page shows up in that one run.

Next: Coverage

The currencies money can arrive in, the markets it can leave for, and what decides availability.