Requests that move funds require an additional signature. This protects the
HTTP method, exact route, timestamp, request ID, and complete JSON body from
tampering.
The following endpoints require signing:
POST /public/v1/withdrawals/create
POST /public/v1/refunds/refundCrypto
POST /public/v1/refunds/refundFiat
Invoice creation and read-only endpoints continue to use the API key without
these additional signing headers.
The official TypeScript,
Python, and
PHP SDKs calculate these signatures
automatically when you configure the original API secretKey. Use the manual
procedure below for direct HTTP integrations.
The timestamp must be within five minutes of Billions server time. The request
ID provides idempotency and becomes request.id in a successful response.
Signature calculation
Parse the body as JSON and canonicalize it using
RFC 8785 JCS. The exact route
path must include /public/v1 and must not include the hostname or query string.
Use the original secretKey returned once when the API key was created as
UTF-8 text. Although it looks like a 64-character hexadecimal value, do not
hex-decode it. Older API keys that were issued before signed operations were
introduced must be revoked and reissued.
TypeScript / Node.js
Install an RFC 8785 implementation:
PHP
Use an RFC 8785-compatible library to produce $canonicalJson; ordinary
json_encode() with sorted top-level keys is not sufficient.
Safe retries
For a retry caused by a timeout or lost response:
- reuse the same request ID;
- reuse the identical JSON body and endpoint;
- calculate a fresh timestamp and signature if the old timestamp expired.
With an SDK, persist the request ID before the first call and pass that same ID
and payload on retry. The SDK creates a fresh timestamp and signature for each
call.
Retrying an identical completed operation returns the original request without
creating another debit or payout. Reusing a request ID with another body or
endpoint returns 409. If the original request is still running or requires
reconciliation, the retry also returns 409.
Common responses
Never generate a new request ID only because the response was lost. A new ID
authorizes a new financial operation.