Get started

Quickstart

Take a payment end to end: create it, send the buyer to the hosted checkout, and confirm it with a signed webhook.

  1. Get your API key

    Sign in, open Developer in the dashboard and copy your key. It identifies your account on every request.

    Keep the key on your server

    Anyone holding it can create transactions, change your settings and withdraw your balance. Never put it in a web page, an app or a repository.

  2. Create a transaction

    Ask for 20 USD and pass the URL that should receive webhooks. Store the private_key from the response with your order: it is returned once, and it is the secret your webhooks are signed with.

    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);
  3. Send the buyer to checkout

    Redirect the buyer to the hosted checkout. They choose a payment method there and get an address, or PayPal details, to pay. Hosted checkout shows what they see and how to style it.

    Checkout URL
    https://anonpay.org/checkout/9c1f0b7a4e2d8f6a3b5c7d9e1f0a2b4c
  4. Receive the webhook

    When the payment confirms we POST a completed event to your URL. Find the order, verify the signature with its private key, mark it paid, and answer with any 2xx. verify is the function from Webhooks.

    Handler
    import json
    
    from flask import Flask, request
    from shop.orders import Order
    from shop.webhooks import verify
    
    app = Flask(__name__)
    
    
    @app.post("/hooks/anonpay")
    def anonpay():
        raw = request.get_data()
        event = json.loads(raw)
        order = Order.by_transaction(event.get("transaction_id"))
        if order is None:
            return "", 404
        signature = request.headers.get("X-Signature", "")
        if not verify(order.private_key, signature, raw):
            return "", 400
        if event["event"] == "completed":
            order.mark_paid()
        return "", 204
    import express from "express";
    import { Order } from "./orders.js";
    import { verify } from "./webhooks.js";
    
    const app = express();
    
    app.post("/hooks/anonpay", express.raw({ type: "application/json" }),
      async (req, res) => {
        const event = JSON.parse(req.body);
        const order = await Order.byTransaction(event.transaction_id);
        if (!order) return res.sendStatus(404);
        const signature = req.get("X-Signature") ?? "";
        if (!verify(order.privateKey, signature, req.body)) {
          return res.sendStatus(400);
        }
        if (event.event === "completed") await order.markPaid();
        res.sendStatus(204);
      });
    $raw = file_get_contents("php://input");
    $event = json_decode($raw, true);
    $order = Order::byTransaction($event["transaction_id"] ?? "");
    
    if ($order === null) {
        http_response_code(404);
        exit;
    }
    $signature = $_SERVER["HTTP_X_SIGNATURE"] ?? "";
    if (!verify($order->privateKey, $signature, $raw)) {
        http_response_code(400);
        exit;
    }
    if ($event["event"] === "completed") {
        $order->markPaid();
    }
    http_response_code(204);
  5. Check before you ship

    A webhook tells you something changed; the API is the record. Fetch the transaction and check that status is completed before you deliver anything valuable.

    Request
    curl https://anonpay.org/api/transaction/info \
      -H "Authorization: Bearer $APA_KEY" \
      -d transaction_id=9c1f0b7a4e2d8f6a3b5c7d9e1f0a2b4c
    import os
    import requests
    
    KEY = os.environ["APA_KEY"]
    
    response = requests.post(
        "https://anonpay.org/api/transaction/info",
        headers={"Authorization": f"Bearer {KEY}"},
        data={
            "transaction_id": "9c1f0b7a4e2d8f6a3b5c7d9e1f0a2b4c",
        },
        timeout=30,
    )
    print(response.json())
    const url = "https://anonpay.org/api/transaction/info";
    
    const response = await fetch(url, {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.APA_KEY}` },
      body: new URLSearchParams({
        transaction_id: "9c1f0b7a4e2d8f6a3b5c7d9e1f0a2b4c",
      }),
    });
    console.log(await response.json());
    $url = 'https://anonpay.org/api/transaction/info';
    $key = getenv("APA_KEY");
    
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
        CURLOPT_POSTFIELDS => http_build_query([
            "transaction_id" => '9c1f0b7a4e2d8f6a3b5c7d9e1f0a2b4c',
        ]),
        CURLOPT_RETURNTRANSFER => true,
    ]);
    $response = json_decode(curl_exec($ch), true);