cl_… id. The same popup is where the account holder later approves each payout you book for them.
The window takes nothing from your page but the session URL your server got from HEVN. It shows no HEVN product screens: a sign-in, one consent screen, and, for a payout, the terms being approved.
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 everything about how the popup looks and where it may return. 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.
The card shows a preview of the consent screen as you edit. 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.
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.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 for link.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, 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
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, 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 Google account explicitly, and:
The consent screen names your product — the Title you configured, or your account’s name — and the origin of
redirectUri, and says what you get: 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.
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.