General

The ANONPAY API enables users to process payments privately.
It accepts GET and POST requests, allowing data to be sent through both types of parameters.
We do not log any API requests.

Our API is currently hosted on the following mirrors:



Our Checkout is currently hosted on the following mirrors:


We recommend using the onion-based endpoints for lower latency and to ensure authenticity of API calls.
Note that a TOR SOCKS5 proxy is required to query onion endpoints.

Authentication

Send your API key in the Authorization header:


The "key" parameter still works in GET parameters or POST form data, but it is deprecated - responses that use it carry a "Deprecation: true" header. A key in a URL ends up in proxy logs, browser history and Referer headers, so prefer the header.
If you do not have an API key, you can obtain one here.

Query Params / Form Data

key string deprecated
abcdefghijklmnopqrstuvwxyz0123

Contains your API key. Superseded by the Authorization header.
Get it from here.

Error Handling

All endpoints return a status field that contains either “success” or “error”.
The HTTP status code now matches the outcome instead of always being 200: 400 for a bad parameter, 401 for a bad key, 403 for someone else's resource, 404 for an unknown id, 409 for a state conflict, 422 for a well-formed request we cannot process, 429 when rate limited, 503 when a price feed is stale or a node is down, and 500 for a bug on our side. A successful create answers 201.

429 and 503 are both retryable; 429 carries a "Retry-After" header.
Here is a possible error response:

Response JSON

status string required

Contains the status of the API request.

error string required on error
parameter_missing

Contains an error string depending on your error.
Possible errors include: “parameter_missing”, “parameter_invalid”

code string required on error
abc123

Contains a code used for debugging purposes.

request_id string required on error
abc123

Correlates with our server log line, and is also returned in the "X-Request-Id" header on every response. Quote it in support requests.

Webhook

Webhooks allow you to get live updates about active transactions and payouts.
If a webhook is configured, a POST request with a JSON body is sent to your specified URL from a TOR exit node, so make sure to allow TOR traffic on your selected endpoint.

This replaces the old GET request with query parameters. A receiver written against the query string will not read a JSON body and will stop seeing events.

The request carries these headers:


X-Signature is HMAC-SHA256 over "{timestamp}.{raw_body}", keyed on the private_key we gave you when the transaction or withdrawal was created. Verify it against the bytes you received, not a re-serialisation, and reject timestamps more than 5 minutes old - that is what stops a captured request being replayed. The private_key is still delivered in the body, so an existing check against it keeps working.

Any 2xx means delivered. A 4xx stops the retries; answer 503 or 429 (we honour Retry-After, capped at one hour) if you want us to come back. Delivery is at-least-once, so make your handler idempotent.

JSON Body

event string required

Contains the event that triggered the webhook request, and always matches the X-Event header.
A completed payout is "withdrawal.completed" - it is no longer called "completed", so one handler can no longer confuse it with a completed transaction.

transaction_id string on transaction events
abcdefghijklmnopqrstuvwxyz0123

Contains the transaction ID about which information is sent.
Sent on "payment_change" and "completed".

withdrawal_id string on withdrawal.completed
abcdefghijklmnopqrstuvwxyz0123

Contains the withdrawal ID whose payout was broadcast.

payment object on transaction events
{"address": "...", "topay": "20", "paid": "20"}

The payment object, as returned by /api/transaction/info.
This replaces the old "data" field, which was a JSON string containing JSON and had to be parsed twice.

crypto_transaction_id string on withdrawal.completed
abcdefghijklmnopqrstuvwxyz0123

The on-chain transaction id of the payout.
This replaces the old "data" field on withdrawal events.

private_key string required
abcdefghijklmnopqrstuvwxyz0123

Contains the transaction's or withdrawal's private key.
It proves the sender knew a shared secret, but not that the request is fresh - prefer X-Signature.

timestamp integer required
1753920000

When the event was sent, in Unix seconds. Matches the "t" value in X-Signature.

Idempotency

Use idempotency keys to prevent duplicate operations when retrying failed requests.
Provide a unique key with each request - identical keys will return the original response, marked with an "Idempotent-Replay: true" header.
Keys expire after 1 hour.

Keys are honoured on POST only and are ignored on GET, so a request you want deduplicated has to be a POST.
A key is scoped to your account and to the exact parameters you sent: reusing one with different parameters is a 422, and reusing one that is still executing is a 409. Server errors and rate limits are never cached, so a retry after one really does re-execute.

Query Params / Form Data

idempotency_key string optional
txn-12345-abcde

A unique key to make requests idempotent.
Must contain only letters, numbers, and hyphens. Max 128 characters.
If the same key is reused within 1 hour, the original response is returned.