Skip to main content
POST
Create API key
The response body shown here is a static example, not live data. After you click Send, your live result appears in a separate panel headed 200 OK. The panel under the status-code tabs is a fixed sample from the spec — its field values (fees, prices, sizes, IDs, timestamps) are placeholders. Use Send, or call the endpoint, for current values.
Create an API key for the ethereum address. No address or account parameter is required; all keys are associated with the master account.

Signing the request

The request is authenticated by a secp256k1 EIP-712 typed-data signature (eth_signTypedData_v4) produced by the wallet that owns address, so wallets render each field and institutional / MPC signers can whitelist on the domain. Sign the typed data below, then split the 65-byte result into {r, s, v} for the signature field. The gateway recovers the signer and rejects the request with HTTP 401 if the recovered address does not equal address. Domain API keys are pure off-chain authentication, so the domain has no verifyingContract (the field is optional per EIP-712):
Types To scope the key to a subaccount, sign the accountIndex-bearing type. Use 0–9 for a single subaccount, or 255 to scope the key to all of the address’s subaccounts (the default for web/mobile trading keys):
For accountIndex 0 you may instead sign the original index-less type (backward compatibility, no deadline); a non-zero accountIndex (including the 255 all-subaccounts sentinel) MUST use the type above:
Replay protection (recommended) When including a nonce in the request body, sign the combined type that binds both replay protection and subaccount scope:
The nonce and accountIndex in the message must match the request body. For accountIndex 0 the server also accepts the nonce-only type without accountIndex in the signed payload (backward compatibility). Message
apiWalletPublicKey is the request’s publicKey field (64 hex chars, no 0x); validUntil is epoch ms, the same value as the request field. Always send validUntil explicitly and sign that value — if the body omits it, the server verifies against its own default (now + 14 days), which will not match what you signed. accountIndex is the key’s subaccount scope — 0–9 for a single subaccount, or 255 for all subaccounts — and must match the request field; omit it from the message only when signing the index-less type for index 0. The legacy EIP-191 personal_sign fallback is index-0 only. Per-environment domain parameters Complete eth_signTypedData_v4 call (ethers v6 / viem)

Legacy EIP-191 signatures (deprecated)

This endpoint previously accepted an EIP-191 personal_sign signature over the canonical JSON message
(keys in this exact order, no whitespace, no trailing newline). During the migration window the server accepts either scheme: it verifies the EIP-712 signature first and falls back to legacy EIP-191. EIP-191 is deprecated and will be rejected once the migration window closes — migrate existing integrations to EIP-712 typed data; new integrations must use EIP-712 only.

Public-key ownership

A public key is a globally unique credential: auth resolves the owning account from api_keys_by_key. createApiKey rejects registering a public key already owned by a different account with HTTP 409 — including keys that have expired but were never revoked. Re-registering a key the caller already owns (renew / rewrite validUntil) is allowed.

Body

application/json
address
string
required

Ethereum address to associate with the account.

Pattern: ^(0x|0X)?[0-9a-fA-F]{40}$
Example:

"0x742d35cc6634c0532925a3b844bc9e7595f2bd18"

publicKey
string
required

Hex-encoded Ed25519 public key. Becomes the API key.

Required string length: 64
Pattern: ^[0-9a-fA-F]{64}$
Example:

"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"

apiWalletName
string
required

Name of the API wallet (included in the signing message).

Required string length: 1 - 64
Example:

"Arcus"

signature
object
required

secp256k1 EIP-712 typed-data signature (r, s, v) over the CreateApiKey payload (eth_signTypedData_v4), produced by the wallet that owns address. See the POST /v1/createApiKey endpoint description for the exact domain, types, and message. During the migration window the deprecated legacy EIP-191 personal_sign scheme is also accepted. Requests where the recovered signer does not equal address are rejected with HTTP 401.

accountIndex
enum<integer>

Subaccount scope for this key. 0–9 locks the key to that single subaccount; 255 scopes it to all of the address's subaccounts (the default for web/mobile trading keys). Defaults to 0 when omitted. The value is bound into the signed payload: any non-zero value (including 255) MUST use the accountIndex-bearing EIP-712 CreateApiKey type (see the endpoint description); index 0 additionally accepts the legacy index-less type/signature for backward compatibility.

Available options:
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
255
validUntil
integer<int64>

Expiration timestamp (epoch ms). Must be between 1 day and 180 days from the server's current time (inclusive). If omitted, defaults to 14 days from now. Explicit values outside the [now+1d, now+180d] window are rejected with HTTP 400.

Required range: x >= 1
nonce
string

Optional replay-protection nonce, single-use per (address, accountIndex) when included in the signed EIP-712 payload. Send the current time as nanoseconds since the Unix epoch (a plain base-10 integer); the server accepts a timestamp up to 48 hours in the past and 24 hours in the future by default. A legacy opaque nonce (e.g. a UUID) is also accepted. Omitting nonce (or signing without it) skips replay protection during the migration window.

Maximum string length: 64
Example:

"a1b2c3d4-5f60-7182-93a4-b5c6d7e8f901"

Response

API key creation accepted. The request has been accepted but the key is not yet usable for authenticated requests; the caller must wait briefly for it to be ingested before the returned api_key resolves.

apiKey
string
required

Newly generated API key (hex string).

address
string
required

20-byte EVM address as hex: optional 0x or 0X prefix and exactly 40 hexadecimal digits. API responses normalize to lowercase a–f after 0x.

Pattern: ^(0x|0X)?[0-9a-fA-F]{40}$
createdAt
integer<int64>
required

Creation timestamp (epoch microseconds).

allSubaccounts
boolean

True when the key trades every subaccount of address rather than a single one. Populated on every response; use it as the scope discriminator (optional in schema for deploy-order compatibility).

accountIndex
integer

The single subaccount (0–9) the key trades. Present only when allSubaccounts is false; omitted for an all-subaccounts key.

Required range: 0 <= x <= 9
validUntil
integer<int64>

Expiration timestamp (epoch ms). Echoes the client-supplied expiry, so it stays in milliseconds. Absent if no expiry.