cl_… id. Signing in through your session is the consent: there is no separate screen to allow access. The same popup is where the account holder later approves each payout you book for them and, for an individual, verifies their identity.
The window takes nothing from your page but the session URL your server got from HEVN, and optionally the email to sign in with. It shows no HEVN product screens: a sign-in, then, for a payout, the terms being approved, or, for a verification, the identity check.
Before you start
- Your integrator account is active. HEVN switches it on. Until it does,
POST /dapi/v1/connect/sessionsandPOST /dapi/v1/clients/linkanswer403 client_creation_not_enabled— see Going live. - Your site is an allowed origin. In the HEVN app, open Settings → Partner program → Developer and find the Sign-in window card. Add every origin your callback page is served from under Allowed sites. A session for any other
redirectUriis refused. - You have a callback page. One static page on an allowed origin that hands the popup’s result back to the page that opened it. It is shown below.
Configure the window
The Sign-in window card holds one setting: Allowed sites, up to 20 origins the window may return to —https://host, or http://localhost:<port> and http://127.0.0.1:<port> for development, with no path and no query. With none, no session can be created. Removing an allowed site also stops every session already issued for it: the window refuses to open a session whose redirectUri is no longer on the list.
How the window looks — its title, logo, colours and theme — is set by HEVN on request; ask HEVN support. Nothing about the window is configurable from the API or from the session URL: a page that opens the popup cannot restyle it, retitle it or redirect it.
Link an account
1. Open the popup inside the click
Browsers block a popup that is not opened synchronously by a user gesture. Open an empty window first, inside the click handler and before anyawait, then ask your server for the session and point the window at it.
Browser
2. Create a session on your server
POST /dapi/v1/connect/sessions is called with your own access token and no X-Hevn-Account — it is about your integrator account, so the header answers 400 account_scope_conflict.
Response — 201
string
required
link asks the account holder to connect their account. sign asks them to approve one payout — see Approve a payout. verify asks a linked individual to verify their identity — see Verify an individual.string
required
The page the window returns to. An
https:// URL — or http://localhost and http://127.0.0.1 in development — with no fragment, on an origin listed under Allowed sites. Any other origin answers 403 redirect_uri_not_allowed.string
The
po_… to approve. Required for sign, refused otherwise.string
The
cl_… whose holder verifies their identity. Required for verify, refused otherwise.url opens the window and lives for about ten minutes, until expiresAt. HEVN signs it, and it is bound to your integrator account, the action, the payout or client, the redirectUri and a one-time nonce. state is that nonce: the window sends it back on redirectUri with the result, and nothing else ties the result to this session. Give url to the browser and keep state on your side.
3. Bind the session to this browser
Never let the browser tell your server which client it is. Rememberstate in an HttpOnly cookie when you create the session, and accept a code only when the browser returns the same state in that same cookie jar. A code arriving with no cookie, or with another state, came from somewhere else.
Node
Sign in with an email you already know
When your product already knows the customer’s email, add it to the session URL aslogin_hint before you navigate the popup:
Browser
login_hint the window offers Google and email sign-in. login_hint only chooses how the holder signs in — it is not part of the signed session, so never treat it as proof of who signed in. POST /dapi/v1/clients/link answers the account that actually did.
4. Exchange the code
The window returns acode that lives for five minutes and works only for your integrator account. Exchange it server-side, again with no X-Hevn-Account:
Response — 200
id against your own user. From now on your server finds the client from its own session and sends that id in X-Hevn-Account; the browser never carries it, so no page can ask your server to act for somebody else’s account. Exchanging the same code again returns the same client.
The callback page
The window finishes by navigating toredirectUri with the result in the query string: code or error for a link, status, payout and reference or error for a payout, status or error for a verification, and state on every one. The callback page posts that query to the page that opened the popup over a BroadcastChannel, then closes the window.
callback.html
state:
Browser
window.opener. Google’s sign-in cuts the popup off from the page that opened it, so by the time the window returns, window.opener is null. A BroadcastChannel reaches every page of your origin in the same browser, which is why the callback page must live on the same origin as the page that opened the popup.
state on the result is the nonce inside the session token, and it equals the state field POST /dapi/v1/connect/sessions answered. The browser check only routes the result to the right page; the check that matters is your server’s, against its cookie.
The Node reference at hevn-inc/dapi-sdk ships this browser half as
HevnConnect: HevnConnect.open() opens the popup synchronously in the click handler, .link(url), .sign(url) and .run(url) navigate it and resolve with the result, and HevnConnect.complete() is the whole callback page. Like the rest of that repository, it is a working reference to read, not a supported package.Who can be linked
Only an account created in the sign-in window can be linked. The window signs out any HEVN session in that browser before everylink sign-in, so the holder always chooses the account explicitly, and:
The window names your product and says what signing in gives you: you can see balances, open accounts and prepare transfers, and the holder approves every transfer themselves in this window.
Approve a payout
A payout you book for a linked client answersauthorization: "client" and carries no approval for your key. The holder signs it. Create a sign session for that payout and open the popup exactly as for a link:
awaitingSignature. Otherwise the session is refused with 404 payout_not_found or 409 payout_not_awaiting_signature.
In the window the holder signs in — a HEVN session already open in that browser is reused for sign — sees the amount, the contact’s name and who requested it, and their own wallet signs the debit. The callback receives status=submitted, payout=po_… and, when the debit was sent, reference. A payout that was no longer waiting by the time the window opened comes back with its current status and nothing signed.
The redirect is a hint, never the record. Read GET /dapi/v1/payouts/{payoutId} with the client in X-Hevn-Account and follow it to settled like any other payout — see Payouts.
Verify an individual
A linked individual verifies their own identity, in this window, after signing in to their own account. You never receive a verification link: whoever opens one submits documents onto that account, so it stays with the holder. A business client verifies through Onboarding instead. You need it when a virtual account the client requested waits onverification_required (Virtual accounts). Create a verify session for the client and open the popup exactly as for a link:
404 client_not_found — the same answer for an id that does not exist. A business client answers 409 verification_not_applicable. A client that is already verified is not refused: the window says so and returns status=approved.
In the window the holder signs in, and must sign in to that same account — any other answers account_mismatch. The identity check runs inside the window. When the holder finishes or closes it, the callback receives status:
The redirect is a hint, never the record. Read
GET /dapi/v1/client with the client in X-Hevn-Account: verifiedAt is set once the identity is verified, and stays absent until then. A review can take a while after the window closes, so poll the client or GET /dapi/v1/banks/{product} — the verification_required blocker goes away and the virtual account moves on by itself.
In the sandbox the window runs against a test verification provider, so the whole flow works with test documents. For automated tests,
POST /dapi/v1/sandbox/kyb/status with {"status": "approved"} verifies an individual client directly — see Sandbox.Errors
Refusals come from two places. Your server sees the API’s; your callback page sees the window’s, aserror on the redirect.
A session that is invalid or already expired when the window opens never reaches your callback: the window shows This link has expired or is invalid and sends nothing back. Give up on the opener side once
expiresAt has passed, and close the popup.
Next: Clients
Read the linked client, wait for it to be ready, and keep the one id that identifies it.