API documentation

Accept SOL and USDC in five minutes.

Authentication

Every gateway request needs an API key. Create one in the dashboard and send it in a header:

x-api-key: adudu_live_xxxxxxxxxxxxxxxx

# or
Authorization: Bearer adudu_live_xxxxxxxxxxxxxxxx

Create an order

POST /api/v1/orders
Content-Type: application/json
FieldTypeRequiredDescription
amountnumberyesAmount to charge, in display units (e.g. 2.5)
currencystringnoSOL (default) or USDC
externalIdstringnoYour own order/cart reference
buyerEmailstringnoBuyer email, for receipts
descriptionstringnoShown on the payment page
expiresInSecondsnumbernoInvoice lifetime, default 1800, max 86400
metadataobjectnoArbitrary JSON, echoed in webhooks
curl -X POST https://YOUR-DOMAIN/api/v1/orders \
  -H "x-api-key: adudu_live_…" \
  -H "content-type: application/json" \
  -d '{ "amount": 2.5, "currency": "SOL", "externalId": "INV-1042" }'
201 Created
{
  "id": "order_uuid",
  "reference": "ADU7K2Q9R3",
  "currency": "SOL",
  "amount": 2.5,
  "amountRaw": 2500001003,
  "status": "pending",
  "paymentUrl": "https://YOUR-DOMAIN/pay/ADU7K2Q9R3",
  "receivingAddress": "Merchant…wallet",
  "expiresAt": "2026-09-23T13:00:00Z"
}

Redirect the buyer to paymentUrl — it renders a QR and polls until the payment lands.

Check order status

GET /api/v1/orders/:id
GET /api/v1/orders?limit=50

Webhooks

Set a webhook URL in settings. We POST signed events to it:

FieldTypeRequiredDescription
order.paida pending order was confirmed on-chain
order.expiredthe invoice passed its deadline unpaid
POST /your/webhook
Content-Type: application/json
x-adudu-event: order.paid
x-adudu-signature: <base64url HMAC-SHA256 of the raw body>
{
  "event": "order.paid",
  "data": {
    "id": "order_uuid",
    "reference": "ADU7K2Q9R3",
    "externalId": "INV-1042",
    "currency": "SOL",
    "amount": 2.500001003,
    "amountReceived": 2.500001003,
    "amountUsd": 375.42,
    "status": "paid",
    "paymentSignature": "5xK3…",
    "payerAddress": "Buyer…wallet",
    "paidAt": "2026-09-23T12:35:12Z"
  }
}

Verify the signature before trusting a webhook:

import crypto from 'node:crypto'

function verify(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('base64url')
  return crypto.timingSafeEqual(
    Buffer.from(expected), Buffer.from(signature)
  )
}

We retry failed deliveries up to 5 times with exponential backoff. Respond with any 2xx to acknowledge.

Self-hosting

The whole gateway is MIT-licensed Next.js + Supabase. See the README in the repository for the deployment checklist.