Skip to main content
The developer key is a P-256 keypair. It logs your backend in to /dapi/v1 and signs payments from your integrator account. Create it in the HEVN app, then log in with POST /dapi/v1/auth/challenge and POST /dapi/v1/auth/token.

Developer key

Create it in the app

No route creates a key, in /dapi/v1 or in the app’s API (/api/v1).
  1. Sign in to https://sandbox.gethevn.com, or https://app.gethevn.com for production. Go to Settings → Partner program → Developer.
  2. Enter the IP allowlist. It cannot be changed after creation.
  3. Save the private key. The browser generates the keypair and shows the private half once, and HEVN stores the public half. Write the private half to a file with mode 0600 on the machine that uses it.
The app adds the public half to your account’s signer in the same action. An account holds up to five keys. One key covers all your clients, linked or created.

Key format

The curve is P-256, also called secp256r1 or prime256v1. The app shows the key’s dk_… id and its fingerprint, sha256:<hex of sha256(DER)>. The public key is sent as base64 of the DER SubjectPublicKeyInfo, at most 4096 characters. The wire formats of the key and the signature are in Signature format and on Start a developer-key login.

The IP allowlist

Include the addresses an autoscaler adds. Your edge must remove caller-supplied X-Forwarded-For, X-Real-IP and CF-Connecting-IP headers. Otherwise the caller controls the address that is checked.

Load the key

Read the key from the file named in HEVN_KEY_PEM. The loader is in HTTP client. A 200 from POST /dapi/v1/auth/challenge shows that the key exists and the allowlist covers the host.

What a session from the key may do

A session from any of your keys can call any /dapi/v1 route. A key has no scopes. The key signs for your integrator wallet and for your sub accounts. It does not sign for a client’s wallet or for an external account. See Who can spend.
The key has no amount limit. It can spend the full balance of your integrator wallet and of each sub account. See What this means for your product.

Sessions

A session is an access token and a refresh token issued to your developer key.

Log in

Sign this proof string with your developer key:
Send it to POST /dapi/v1/auth/challenge. The field rules are on Start a developer-key login.
Response
Base64-decode payload, sign the bytes as in Signing, and call POST /dapi/v1/auth/token:
Response
userId is the cl_… id of your integrator account. Use it wherever a client id is accepted. The challenge refusals and the one-call login form are on Exchange a signed login challenge.

When a key is refused

At login, 401 invalid_credentials covers any problem with the email, the key, the allowlist, the signer or the signature. It does not name the check that failed. Refusals after login are in Errors:
  • 403 forbidden (key deleted, address outside the allowlist, or details.reason = "developerSessionRequired") is under Developer keys.
  • 403 key_not_registered, 409 signer_not_attached and 400 signature_invalid are under Authentication and signing.
  • 403 account_not_controlled is under Acting as a client.

Tokens

The access token audience is platform, and the refresh token audience is platform-refresh. Lifetimes and token fields are on Exchange a signed login challenge. Both tokens have a developer_key_id claim that names the key behind the session. /dapi/v1 refuses other bearers.
  • No bearer returns 401 unauthenticated.
  • An app token, a refresh token on another route, or a token with no key behind it returns 403 forbidden. details.reason is developerSessionRequired.
/api/v1, the app’s API, refuses a platform token. Refresh with the refresh token as the bearer and an empty body:
Response
Log in once per process and store the refresh token as a secret. Refresh about a minute before the access token expires. Session in HTTP client does this.

Session scope

Production refuses a sandbox token, and the reverse. Log in on each host with a key created in that environment’s app. See rate limits.

Acting as a client

Send X-Hevn-Account: cl_… with your access token to act for a client. One token covers all your clients: those linked through HEVN Connect and those created with POST /dapi/v1/clients for external wallets. The header selects whose data a call reads and writes. It does not let the developer key sign for that client’s wallet.
No path has a {clientId} parameter. Your own cl_… id, the userId from POST /dapi/v1/auth/token, selects your integrator account. Send it on the routes that require the header, for example to open a sub account with POST /dapi/v1/client/accounts. For an access token that acts for one client, send its userId to POST /dapi/v1/auth/refresh.

Rotate a key

Both keys work while both exist.
1

Create the second key

Create it in the app, with an allowlist that covers the hosts that will use it.
2

Switch your servers

Deploy the new key file. Payments now send the new publicKey. An approval is bound to your signer, so one prepared before the switch can be confirmed with either key.
3

Delete the old key

Delete it in the app. The next login or payment that uses it is refused.
Deleting a key ends its sessions. The next call with an access token from that key returns 403, and so does POST /dapi/v1/auth/refresh. Delete the key when a token leaks, too. Test rotation in the sandbox.

Next: Signing