Concepts

Idempotency

A network can fail after a request arrives but before you hear back. An idempotency key makes the retry safe.

Send idempotency_key on a POST, and a retry of the same request returns the first response instead of acting twice. It works on every endpoint, not only the ones that list it, and it is ignored on GET.

The key is scoped to your API key, the method, the path and the parameters, so the same value on a different request does not collide. Reusing a key with different parameters is 422 idempotency_key_reused_with_different_parameters; retrying while the first request is still running is 409 request_in_progress. A replayed response carries Idempotent-Replay: true. Server errors and 429 answers are never stored, so a retry after one of those runs for real.

Use it on everything that moves money: /api/transaction/create, /api/user/withdraw and /api/user/exchange.

Example

Use one key per logical operation. An order or invoice id works well, because a retry of the same order then reuses it on its own.

Request
curl https://anonpay.org/api/transaction/create \
  -H "Authorization: Bearer $APA_KEY" \
  -d amount=20 \
  -d currency=usd \
  -d allowed_payment_methods=btc,xmr,usdt-erc20 \
  -d webhook=https://seller.example/hooks/apa \
  -d idempotency_key=2c9a4e7b-8d1f-4a6c
import os
import requests

KEY = os.environ["APA_KEY"]

response = requests.post(
    "https://anonpay.org/api/transaction/create",
    headers={"Authorization": f"Bearer {KEY}"},
    data={
        "amount": "20",
        "currency": "usd",
        "allowed_payment_methods": "btc,xmr,usdt-erc20",
        "webhook": "https://seller.example/hooks/apa",
        "idempotency_key": "2c9a4e7b-8d1f-4a6c",
    },
    timeout=30,
)
print(response.json())
const url = "https://anonpay.org/api/transaction/create";

const response = await fetch(url, {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.APA_KEY}` },
  body: new URLSearchParams({
    amount: "20",
    currency: "usd",
    allowed_payment_methods: "btc,xmr,usdt-erc20",
    webhook: "https://seller.example/hooks/apa",
    idempotency_key: "2c9a4e7b-8d1f-4a6c",
  }),
});
console.log(await response.json());
$url = 'https://anonpay.org/api/transaction/create';
$key = getenv("APA_KEY");

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
    CURLOPT_POSTFIELDS => http_build_query([
        "amount" => '20',
        "currency" => 'usd',
        "allowed_payment_methods" => 'btc,xmr,usdt-erc20',
        "webhook" => 'https://seller.example/hooks/apa',
        "idempotency_key" => '2c9a4e7b-8d1f-4a6c',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);
Retry only what is safe to retry

A 409 request_in_progress means the first attempt is still running: wait and retry with the same key. A 422 with a different payload is a bug in the caller, not a reason to pick a new key.