API Reference

Anonym Gateway API

Accept anonymous crypto payments in your app. No wallet required for your users. Vault-based privacy on Monad.

Quick Start

The Gateway is a plain HTTPS/JSON API — no SDK required. Call it from any language that can make HTTP requests. Every call is authenticated with your secret API key, so it must run on your server, never in browser code your users can read.

  1. Sign in to the merchant dashboard with your wallet and create your merchant account. Your API key (sk_live_…) is shown once — copy it now.
  2. Store the key as a server-side environment variable.
  3. Create a payment intent from your backend (below).
  4. Show your user the amount, collect the on-chain payment, then confirm the intent.
Create a payment intent (curl)
curl -X POST https://anonympay.vercel.app/api/gateway/intents \
  -H "Authorization: Bearer $ANONYM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10,
    "token": "MON",
    "description": "Premium subscription",
    "recipient_address": "0xYourReceivingAddress",
    "metadata": { "user_id": "user-123" }
  }'
Same request in Node.js (server-side)
const res = await fetch("https://anonympay.vercel.app/api/gateway/intents", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANONYM_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: 10,
    token: "MON",
    description: "Premium subscription",
    recipient_address: "0xYourReceivingAddress",
    metadata: { user_id: "user-123" },
  }),
});

const { ok, data } = await res.json();
// data.id, data.status ("created"), data.vault_address, data.expires_at

Authentication

All API requests authenticate via Bearer token in the Authorization header. Your API key is shown once at creation — store it securely.

Request Header
Authorization: Bearer sk_live_your_api_key_here

Security note: API keys are stored as SHA-256 hashes. We cannot recover your key if lost. Use the rotation endpoint to generate a new one.

Base URL

https://anonympay.vercel.app/api/gateway

All endpoints are prefixed with /api/gateway. Rate limit: 100 requests per minute per API key.

Payment Flow

1

Create Payment Intent

Call POST /intents with amount and recipient details. Returns deposit instructions.

2

User Pays

Option A (Hosted): Share the checkout link (/checkout/:id) — the user connects their wallet and pays directly.

Option B (Custom): User sends MON to the vault address (or their managed wallet). Funds route through Anonym vaults — no direct wallet-to-wallet transfer on-chain.

3

Confirm Payment

Hosted checkout: Automatic — the page calls POST /checkout/:id/confirm for you.

Custom flow: Once you observe the on-chain deposit, call POST /intents/:id/confirm with the tx_hash. This marks the intent paid.

4

Webhook Notification

We POST a payment.paid event to your registered webhook URL. Verify the signature to ensure authenticity.

5

Settle

Call POST /settle with the intent_id to mark a paid intent settled and fire a payment.settledwebhook. You can also settle from the merchant dashboard's Payouts tab.

Endpoints

Payment Intents

POST
/intents

Create a payment intent. Returns the intent with vault_address, commitment_hash, and salt.

GET
/intents

List payment intents. Filter by status, paginate with limit/offset.

GET
/intents/:id

Get a single payment intent by ID.

POST
/intents/:id/cancel

Cancel a pending payment intent. Cannot cancel after payment.

POST
/intents/:id/confirm

Mark an intent paid. Body: { tx_hash, deposit_id? }. Fires the payment.paid webhook.

Settlement

POST
/settle

Settle a paid intent. Body: { intent_id }. Fires the payment.settled webhook.

Managed Wallets

POST
/managed-wallets

Create a managed wallet for a user. Deterministic address derived from merchant ID + user identifier.

GET
/managed-wallets

List all managed wallets for your merchant account.

GET
/managed-wallets/:address

Get details for a specific managed wallet.

DELETE
/managed-wallets/:address

Freeze a managed wallet. Prevents further deposits.

Webhooks

POST
/webhooks

Register a webhook endpoint. Specify URL and event types to subscribe to.

GET
/webhooks

List your webhook endpoints.

DELETE
/webhooks/:id

Remove a webhook endpoint.

Merchant

GET
/merchants/me

Get your merchant profile and account details.

PATCH
/merchants/me

Update merchant name and email.

Public Checkout (No Auth)

GET
/checkout/:id

Get public intent details for the hosted checkout page. Returns amount, token, status, merchant name, and expires_at. No API key required.

POST
/checkout/:id/confirm

Confirm a checkout payment. Body: { tx_hash, deposit_id?, salt?, commitment_hash? }. Marks intent as paid and fires payment.paid webhook.

POST
/checkout/:id/cancel

Cancel a pending checkout. Only works on `created` intents — no action after payment. Returns current intent status.

GET
/checkout/lookup?wallet=:address

Look up an Anonym user profile by wallet address. Returns username, display_name, and avatar_url.

Example: Create Intent

FieldTypeNotes
amountnumberRequired. Must be positive.
tokenstringDefaults to "MON".
currencystringDefaults to "MON".
descriptionstringOptional. Shown at checkout.
recipient_addressstringOptional. 20-byte EVM address that receives the payment.
recipient_merchant_idstringOptional. Route to another Anonym merchant instead of an address.
use_managed_walletbooleanOptional. Use the payer's managed wallet as source.
payer_labelstringOptional. Your identifier for the payer.
metadataobjectOptional. Arbitrary key/values echoed back to you.
idempotency_keystringOptional. Reuse to safely retry without duplicating.
expires_in_secondsnumberOptional. Defaults to 3600 (1 hour).
POST /api/gateway/intents
{
  "amount": 25,
  "token": "MON",
  "description": "Annual subscription",
  "recipient_address": "0xYourReceivingAddress",
  "metadata": {
    "order_id": "ord_abc123",
    "plan": "annual"
  },
  "idempotency_key": "order_abc123_1",
  "expires_in_seconds": 1800
}
Response
{
  "ok": true,
  "data": {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "status": "created",
    "amount": 25,
    "token": "MON",
    "currency": "MON",
    "recipient_address": "0xYourReceivingAddress",
    "commitment_hash": "0x8a3f...",
    "salt": "0xb74e...",
    "vault_address": "0x53A617438fCd546fF7af234e832Ce270b12B3c1C",
    "expires_at": "2026-07-18T15:30:00Z",
    "created_at": "2026-07-18T14:30:00Z"
  }
}

Show your user the amount and vault_address. After they send MON on Monad and you see the transaction, confirm the intent:

POST /api/gateway/intents/:id/confirm
{
  "tx_hash": "0x9c2f…the on-chain transfer hash",
  "deposit_id": 42
}

// Response: intent with "status": "paid" and "paid_at" set.
// A payment.paid webhook is delivered to your endpoints.

Managed Wallets (No Wallet Required)

For web2 users who don't have a crypto wallet, create a managed wallet. Each user gets a deterministic address derived from your merchant ID. Funds deposited here are automatically routed through Anonym vaults.

Create a managed wallet
POST /api/gateway/managed-wallets
{
  "user_identifier": "user-123",
  "label": "Alice's payment wallet"
}

// Response
{
  "ok": true,
  "data": {
    "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
    "derivation_index": 1,
    "status": "active"
  }
}

Your user sends MON to the managed wallet address (from an exchange, fiat on-ramp, or another source). The system detects the deposit and routes it through the vault.

Hosted Checkout Integration

The hosted checkout is a Stripe-style payment page you redirect users to. It handles wallet connection, on-chain payment, vault routing, and confirmation — no custom UI needed on your end. Every API key gets this for free.

How It Works

1

Create Intent

Your backend calls POST /intents to create a payment. Returns an intent ID.

2

Redirect

Send the user to {APP_URL}/checkout/{intent_id}?return_url={your_success_url}.

3

User Pays

The checkout page loads the intent, the user connects their wallet, and pays on-chain through Anonym vaults.

4

Automatic Confirm

The page calls POST /checkout/:id/confirm to mark the intent paid — no action needed from you.

5

Return

After payment, the user is redirected to your return_url. You receive a webhook when the payment is confirmed.

Integration Flow

Your App                    Anonym Gateway              Shopper
  │                              │                          │
  │  POST /intents ─────────────►│                          │
  │  ◄──── { id } ──────────────│                          │
  │                              │                          │
  │  redirect ──────────────────►│  /checkout/{id}          │
  │                              │  ◄───────────────────────│  (connects wallet)
  │                              │  GET /checkout/{id} ────►│
  │                              │  ◄──── intent data ──────│
  │                              │                          │
  │                              │  protocolTransfer() ────►│  (on-chain payment)
  │                              │  POST /checkout/{id}/confirm
  │                              │                          │
  │  webhook: payment.paid ──────│                          │
  │                              │                          │
  │  ◄────────────────────────── │  redirect to return_url  │

Step 1: Create a Payment Intent

Call this from your backend (never expose your API key in client code). The intent ID is what you redirect the user to.

POST /api/gateway/intents
curl -X POST https://anonympay.vercel.app/api/gateway/intents \
  -H "Authorization: Bearer $ANONYM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 25,
    "token": "MON",
    "description": "Pro plan — monthly",
    "recipient_address": "0xYourReceivingWallet",
    "metadata": { "order_id": "ord_abc123", "plan": "pro" },
    "expires_in_seconds": 3600
  }'
Response
{
  "ok": true,
  "data": {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "status": "created",
    "amount": 25,
    "token": "MON",
    "expires_at": "2026-07-18T15:30:00Z"
  }
}

Step 2: Build the Checkout URL

Append the intent ID to the checkout path. Optionally pass?return_url= to send the user back to your app after payment.

Checkout URL pattern
https://anonympay.vercel.app/checkout/{intent_id}?return_url=https://your-app.com/thank-you
Generate in Node.js
const APP_URL = "https://anonympay.vercel.app";

const intent = await fetch("https://anonympay.vercel.app/api/gateway/intents", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANONYM_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: 25,
    token: "MON",
    description: "Pro plan",
    recipient_address: "0xYourReceivingWallet",
  }),
}).then((r) => r.json());

const checkoutUrl = `${APP_URL}/checkout/${intent.data.id}?return_url=https://your-app.com/success`;

// Redirect the user, embed in an iframe, or show as a link
res.redirect(checkoutUrl);

Step 3: Receive Confirmation

When the user completes payment, they land on yourreturn_url. To know for sure the payment succeeded (and to verify the amount), listen for the webhook.

Webhook payload (payment.paid)
{
  "event": "payment.paid",
  "data": {
    "id": "f47ac10b-...",
    "status": "paid",
    "amount": 25,
    "token": "MON",
    "tx_hash": "0x9c2f...",
    "paid_at": "2026-07-18T15:31:00Z",
    "metadata": { "order_id": "ord_abc123", "plan": "pro" }
  }
}

The metadata field echoes back whatever you passed when creating the intent — use it to match payments to orders in your database.

Integration Examples

Next.js Route Handler

// app/api/checkout/route.ts
import { NextResponse } from "next/server";

const APP_URL = "https://anonympay.vercel.app";

export async function POST(req: Request) {
  const { amount, description } = await req.json();

  const res = await fetch("https://anonympay.vercel.app/api/gateway/intents", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.ANONYM_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ amount, token: "MON", description }),
  });

  const { ok, data, error } = await res.json();
  if (!ok) {
    return NextResponse.json({ error }, { status: 400 });
  }

  const checkoutUrl = `${APP_URL}/checkout/${data.id}?return_url=${encodeURIComponent("https://your-app.com/success")}`;

  return NextResponse.json({ checkoutUrl });
}

Python (Flask)

import os, requests
from flask import Flask, request, redirect

ANONYM_KEY = os.environ["ANONYM_API_KEY"]
ANONYM_BASE = "https://anonympay.vercel.app/api/gateway"
APP_URL = "https://anonympay.vercel.app"

@app.route("/checkout", methods=["POST"])
def checkout():
    amount = request.json["amount"]
    resp = requests.post(
        f"{ANONYM_BASE}/intents",
        headers={"Authorization": f"Bearer {ANONYM_KEY}"},
        json={"amount": amount, "token": "MON"},
    ).json()

    intent_id = resp["data"]["id"]
    checkout_url = f"{APP_URL}/checkout/{intent_id}?return_url=https://your-app.com/success"
    return redirect(checkout_url)

Cancelling: The checkout page includes a cancel button. Users can bail out before paying. The intent is marked cancelled and is no longer active. You can also cancel via POST /intents/:id/cancel from your backend.

Expiry: Intents expire after expires_in_seconds (default 1 hour). The checkout page shows a countdown. Once expired, the user can no longer pay and must start a new checkout.

Webhooks

Register a webhook endpoint to receive payment notifications. Each request carries a SHA-256 signature so you can verify it came from Anonym. Your signing secret (whsec_…) is returned when you create the endpoint.

Event Types

Two events are delivered today. New endpoints subscribe to these by default; pass an events array when registering to narrow the set.

payment.paidSent after you confirm an intent.
payment.settledSent after you settle a paid intent.

Register an endpoint

POST /api/gateway/webhooks
{
  "url": "https://your-app.com/webhooks/anonym",
  "events": ["payment.paid", "payment.settled"]
}

// Response includes the signing secret — store it, shown once:
// { "ok": true, "data": { "id": "...", "url": "...", "secret": "whsec_..." } }

Verifying Signatures

The signature is sha256("{timestamp}.{raw_body}.{secret}"). Compute it over the exact raw request body bytes — do not re-serialize the parsed JSON, or key ordering will change the hash.

Webhook Headers
X-Anonym-Signature: sha256=<hex_signature>
X-Anonym-Timestamp: <unix_timestamp>
X-Anonym-Event: payment.paid
Verify in Node.js
import crypto from "crypto";

// rawBody: the exact string received, before JSON.parse
function verifyWebhook(rawBody, headers, secret) {
  const timestamp = headers["x-anonym-timestamp"];
  const signature = headers["x-anonym-signature"]; // "sha256=<hex>"

  const expected =
    "sha256=" +
    crypto
      .createHash("sha256")
      .update(`${timestamp}.${rawBody}.${secret}`)
      .digest("hex");

  // constant-time compare to avoid timing leaks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected),
  );
}

Error Handling

All errors return a consistent JSON structure with an error message and optional code.

Error Response
{
  "ok": false,
  "error": "Amount must be positive",
  "code": "INVALID_AMOUNT"
}
CodeHTTP StatusDescription
UNAUTHORIZED401Invalid or missing API key
RATE_LIMITED429Too many requests. Retry after cooldown.
INVALID_AMOUNT400Payment amount must be positive
INVALID_STATUS400Operation not allowed in current intent status
NOT_FOUND404Resource does not exist

Privacy Architecture

Every payment through the Gateway API is routed through Anonym vaults. The blockchain shows only vault interactions — never direct wallet-to-wallet transfers. Your users' financial relationships stay private.

Vault Settlement

All funds route through TransferVault smart contracts. No direct P2P hops on-chain.

Commitment Hashes

Cryptographic commitments link deposits to recipients without revealing addresses on-chain.

Nullifiers

Prevent double-spending without a public ledger of recipient addresses.

Need help?

Reach out to the Anonym team for API access, enterprise pricing, or integration support.