Credential reference
| Credential | Algorithm / curve | Created by | Presented as | Authorizes | Lifetime |
|---|---|---|---|---|---|
| Master key — Secp256k1 | secp256k1, EIP-712 | You, off-exchange | Signed payload, signature_type = 1 | Account root: mint/revoke sessions, manage keys | Until removed |
| Master key — Passkey | P-256, WebAuthn | You, off-exchange (authenticator) | Signed payload, signature_type = 2 | Same as Secp256k1 master key | Until removed |
| Session key | Ed25519 | Any master key | Signed payload, signature_type = 0; or the X-PUBLIC-KEY / X-SIGNATURE / X-REQUEST-ID triple | Trading, cash, and key-management writes within its scope | valid_until set at mint (max value = never expires); revocable |
| API key | Opaque (base64) | Session-signed call | X-API-KEY header | Reads only | Until deleted |
| Device key | Opaque (base64) | Session-signed login | X-DEVICE-KEY header | Reads, plus minting pairings and WebSocket tickets | Idle 7 days / absolute 30 days, whichever comes first; revocable |
| Device-pairing write token | Opaque bearer | Device-key call | Authorization: Bearer <token> | One write to one pairing mailbox | Single-use; 180 seconds |
| WebSocket ticket | Opaque single-use | Device-key call | Presented when opening the private WebSocket | One private WebSocket connection | Single-use; 30 seconds |
+ / / alphabet, = padding) for every key and header value. URL-safe base64 (- / _) is rejected. The signed-payload envelope documents the byte layout and signature types.
Long-lived credentials
Master keys
Secp256k1 (EIP-712) or Passkey (WebAuthn). The account root. Mint and revoke session keys; manage other keys. An admin master key reaches the whole account; a scoped key is pinned to one subaccount.
Session keys
Ed25519. Minted by a master key. Sign trading, cash, and key-management writes. Pinned to one subaccount, or unpinned. An unpinned session under an admin master key is admin-rooted.
API keys
Opaque bearer string in
X-API-KEY. Read-only programmatic access. Pinned or account-wide.Device keys
Opaque bearer string in
X-DEVICE-KEY. The same reads as an API key, plus minting device pairings and WebSocket tickets.X-API-KEY for headless, programmatic reads. Use X-DEVICE-KEY when the client also needs to open the private WebSocket or pair a device — pairing and WebSocket-ticket calls accept only X-DEVICE-KEY.
One-shot capabilities
Two short-lived, single-use tokens support device linking and the private WebSocket. Each is spent on first use or expires; neither is a long-lived credential.Device-pairing write token
Minted by a device key. Returned once and carried to the second device. That device presents it as
Authorization: Bearer <token> to deposit its public keys. Single-use, 180-second TTL. A reused or expired token is rejected 401; a completed pairing returns 409.WebSocket ticket
Minted by a device key. Returned once with its time-to-live. Present it when opening the private WebSocket. Single-use, 30-second TTL. Logging out does not revoke tickets already minted; they remain valid until they expire.
Secrets are returned once
Every minted secret — API key, device-key secret, device-pairing write token, WebSocket ticket — is returned exactly once, in the body of the minting response. The exchange keeps no recoverable copy, and there is no “show secret again” call.- Store the secret immediately from the mint response.
- Listing returns prefixes only. Listing API keys or device keys returns the first 8 characters of each key plus metadata — never the raw secret.
- If you lose a secret, rotate. Mint a replacement, then delete or revoke the lost credential.
- Master keys never leave you. You generate master-key material off-exchange; the exchange only ever holds the public key. Keep the private key or authenticator safe.
Reading the body
Accepted signed trading and cash writes return aRequestAck — { status, processed_at_ns }. The status is the outcome (for example request_completed, or a rejected_* value); processed_at_ns is the exchange processing time in nanoseconds since the Unix epoch. A 200 can still carry a rejection, so always read the body; see the error model for the rule and error codes for the full status list.