@ensc/sdk) applies all of them automatically; this page explains what they are so you know what you are relying on.
Your credentials
When you generate keys in the dashboard you receive three secrets, with their identifiers, for each environment (Sandbox, Live):
Plus your merchant id (
mrc_…), which is not secret.
The secrets are shown once, at generation. ENSC keeps only a hash of the API key and only the public half of your signing key; it stores your encryption key wrapped under its own key so it can decrypt your requests. Nobody at ENSC can recover a lost secret: rotate instead. See Generating keys.
Authorization: the API key
Every request carries your API key. Every write also carries an Ed25519 signature.@ensc/sdk adds both automatically.
- The key’s prefix encodes the environment (
ensc_test_/ensc_live_) and type (sksecret,rkrestricted,pkpublishable). A test key cannot touch live resources and vice versa (ENSC_TEST_LIVE_MISMATCH). X-ENSC-API-Versionpins the contract you were built against. The current version is2026-09-15. See API versioning.X-ENSC-Key-Idnames your signing key. On writes it is the key ENSC verifies your signature with; on reads it is the key ENSC seals the response to. Send it on every request.- Live keys are accepted only from allowlisted IPs (
ENSC_IP_NOT_ALLOWEDotherwise), and a live key whose allowlist is empty is refused on every request (ENSC_IP_ALLOWLIST_REQUIRED). See IP allowlist.
Permissions (scopes)
Each key carries a fixed list of scopes, chosen when it is generated. An endpoint refuses a key without the scope it needs (403 ENSC_INSUFFICIENT_SCOPE).
The keys the dashboard generates carry all four by default. A secret key also manages webhook endpoints and reads the event log without a dedicated scope. A restricted key needs
webhooks:read to list endpoints and read events, and webhooks:manage to create, change, test or delete endpoints. api-keys:read and api-keys:manage are reserved and not yet required by any route.
Publishable keys can hold only balances:read: they can read balances and nothing else, their responses are not sealed, and they are refused on every management route (credential lists, webhook endpoints, events and test data). Issuing, rotating and revoking any key, and editing IP allowlists or CORS origins, are dashboard actions and are refused from API keys (403 ENSC_DASHBOARD_ONLY).
Layer 1: encrypted requests
The body of every write (creating a conversion, reporting its transaction, requesting a voucher or payout, resolving a bank account, building a transfer, webhook endpoint management) is encrypted with AES-256-GCM under your encryption key and sent as an envelope:Layer 2: signed requests
Every write also carries an Ed25519 signature over the method, path, query, a hash of the (encrypted) body, a timestamp, a single-use nonce, your merchant id and your idempotency key. ENSC verifies it against your registered public key, rejects timestamps more than five minutes off, and rejects any nonce it has seen before. A request cannot be altered in transit or replayed.Layer 3: sealed and signed responses
Every successful response is encrypted to your signing key using HPKE (RFC 9180: X25519, HKDF-SHA256, ChaCha20-Poly1305) and signed by ENSC:X-ENSC-Signature, X-ENSC-Key-Id, X-ENSC-Timestamp, X-ENSC-Request-Id. The SDK checks ENSC’s signature against the public keys published at GET /v1/.well-known/ensc-public-keys.json before it opens anything, so a forged or substituted response is never parsed. Only your signing private key can open the body: someone holding just your API key learns nothing from the responses.
Error responses are not sealed, so a 4xx or 5xx is always readable.
The exact formats of all three layers are in Encrypting and signing requests.
What each stolen credential buys an attacker
If you suspect any credential has leaked, rotate it from the dashboard. Rotation keeps the old key working for 24 hours so you can roll your deployment; revocation is immediate.
Your wallet key stays yours
ENSC never holds or asks for a wallet private key. Every on-chain action (a conversion, a transfer) is returned as unsigned calldata,{ from, to, data, value: "0", chainId }, that your own wallet signs and broadcasts. Conversions are additionally gated by a voucher that ENSC signs for the exact wallet, amounts and deadline you asked for; the converter contract refuses a voucher presented by any other wallet, reused, or presented after its deadline. See Conversions.
Bank account details you give for a payout are stored encrypted; ENSC’s responses and webhooks show only the last four digits. A payout is sent only to the account your conversion committed to on chain.
Webhooks
Webhooks ENSC sends to you are signed with the same Ed25519 key that signs responses, over the webhook id, the timestamp and the SHA-256 of the raw body (ENSC-WH-V1). There is no shared secret to store or rotate. Verify them with EnscClient.constructEvent() and the keys from /v1/.well-known/ensc-public-keys.json (EnscClient.fetchPublicKeys() loads them; the verifier picks the one named by X-ENSC-Key-Id) before acting on a delivery, and de-duplicate on the event id. Webhook payloads never carry bank account numbers. The receiver guide is Webhooks.