Skip to main content

Authentication

Sign every request with the current API key flow and EXN-* headers.

How signed requests work​

The client signs request metadata with an Ed25519 private key. The server validates the API key, timestamp, signed payload fields, path and query, body hash, signature, and access scope.

For API key creation options and the public key registration format, see API key creation options.

Signed request headers​

HeaderRequiredPurpose
EXN-API-KEYYesPublic API key identifier. Must match api_key inside EXN-DATA.
EXN-IDEMPOTENCY-KEYYesEmpty for signed GET requests; non-empty for mutating requests.
EXN-TIMESTAMPYesUnix timestamp in milliseconds. Must match timestamp inside EXN-DATA.
EXN-SIGN-VERSIONYesSignature protocol version. Current value: 1.
EXN-DATAYesBase64url-encoded signed payload without = padding.
EXN-SIGNYesEd25519 signature of the decoded EXN-DATA payload bytes, base64url-encoded without = padding.

Decoded EXN-DATA payload​

FieldDescription
api_keySame value as EXN-API-KEY.
idempotency_keySame value as EXN-IDEMPOTENCY-KEY; empty string for signed GET requests.
timestampSame value as EXN-TIMESTAMP, in Unix milliseconds.
sign_versionSame value as EXN-SIGN-VERSION.
methodUppercase HTTP method, for example GET or POST.
pathRequest path with query string exactly as sent by the client.
body_hashSHA-256 hash of the exact request body, base64url-encoded without padding.

Signing rules​

  • EXN-SIGN signs the decoded EXN-DATA payload bytes, not the base64url string.
  • EXN-DATA and EXN-SIGN must use base64url without = padding.
  • For requests without a body, body_hash is the SHA-256 hash of the empty byte sequence: 47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU.
  • Query strings must be signed exactly as transmitted. Do not reorder, normalize, or re-encode query parameters after signing.
  • Duplicate query parameters are rejected.
  • For signed GET requests, EXN-IDEMPOTENCY-KEY must be present with an empty value.
  • For mutating requests, EXN-IDEMPOTENCY-KEY must be non-empty.
  • Generate a fresh timestamp and signature for every request.

Example​

Use the complete read-only example to import your private key, discover your Access Point and send a signed request. The curl below shows the request shape only; generate fresh signed headers before sending it. Replace the host with the access_point returned by Access Point / Host Discovery. The semicolon sends the required empty header in curl.

curl -X GET "https://ap-4decef67.exness.com/v1/configuration/accounts/123456/account" \
-H "EXN-API-KEY: exnsk-{your_public_api_key}" \
-H "EXN-IDEMPOTENCY-KEY;" \
-H "EXN-TIMESTAMP: 1773656070123" \
-H "EXN-SIGN-VERSION: 1" \
-H "EXN-DATA: <base64url_encoded_payload>" \
-H "EXN-SIGN: <base64url_encoded_signature>"
{
"api_key": "exnsk-{your_public_api_key}",
"idempotency_key": "",
"timestamp": 1773656070123,
"sign_version": 1,
"method": "GET",
"path": "/v1/configuration/accounts/123456/account",
"body_hash": "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"
}

Common auth errors​

Codeerror_messageClient action
1000AUTH_INVALID_API_KEYCheck EXN-API-KEY, key expiry, and api_key inside EXN-DATA.
1001AUTH_INVALID_SIGNATURECheck EXN-DATA, EXN-SIGN, private key, payload serialization, body hash, timestamp, and base64url encoding.
1002AUTH_PERMISSION_DENIEDCheck account access, source IP restrictions, and API key permissions.

Continue your journey​

Now that you know how signing works, put it into practice by sending your first request to the API you are integrating with.