Skip to main content
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.

Required headers

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.