Programmatic access uses Ed25519 API keys. The SDK signs each authenticated request.
Credentials
| Value | Where to find it |
|---|---|
| API key id | App โ API โ create or view key |
| API private key | Shown once at creation (64-char hex seed) |
| Account ID | App โ Profile โ Account ID |
Use the Account ID string exactly as shown. Do not use internal numeric ids.
Account-ID authentication is valid even when the account has no username; username is optional
profile metadata, not an authentication requirement or a value that must be set to "-".
Signing (what the SDK does)
For each authenticated unary call the SDK builds a signature over:
timestamp_ms
METHOD
pathname
canonical_query
hex(sha256(body))and sends headers X-API-KEY-ID, X-API-TIMESTAMP, X-API-SIGNATURE.
The client allocates a distinct timestamp for every call, including concurrent identical calls, so
replay protection does not confuse them. You normally never assemble this yourself; pass
credentials via Config. Cloned and independently constructed credentials with the same key id
share a process-wide allocator. The protocol has no cross-process nonce, so use one API key per
process; sharing a key between processes can still produce identical tuples. Automatic timestamps may lead
the local wall clock by at most five seconds, leaving half of the API's 10-second freshness window
for clock and network skew. A burst that exhausts that capacity is backpressured; prolonged
exhaustion returns a retryable rate-limit error instead of reusing an authentication tuple.
polyester::Client services apply the appropriate public or signed call path. Types
under polyester::connect are low-level generated protocol clients; they do not automatically add
Polyester API-key signatures. Do not use a generated client as an authentication shortcut.Public vs private
- Public market-data calls work with no key.
- Private RPCs need a key. Private WebSocket channels also need the root Account ID, supplied
through
Config.default_account_idor the subscribe method'saccount_idargument. - Realtime is always included (the Cargo
realtimefeature flag is a no-op stub). Consume streams withrecv_result().awaitso terminal transport and decode failures are observable. - Hyphenated channel segments (for example
api-keys) must be signed with RFC 3986-preserving query encoding (built into the SDK, unreserved-_.~stay unescaped).
Key lifecycle on this SDK
| Action | Supported |
|---|---|
generate_keypair | Yes (local only) |
list / get / subscribe | Yes (API-key auth) |
| create / update / revoke | No, JWT/session (TypeScript / app) |