PaygatePaygate
Sign in Sign up

API documentation

Flow: create an invoice → send the customer to the payment page → receive a signed webhook. Prefix /v1. Auth via the X-Api-Key header.

OpenAPI 3 spec (JSON) Get keys

Supported networks

ton
tron
solana
evm
bsc
polygon
arbitrum
optimism
base
avalanche
hyperevm
sonic
cronos
gnosis
linea
scroll
zksync
mantle
celo
blast
sei
berachain
moonbeam
btc
doge
ltc
monero

Switch from another processor — no code rewrite

Already integrated with Cryptomus / NOWPayments / Coinbase Commerce? Change only the base URL and key in your SDK — we accept their create-invoice shape, return our checkout in their response shape, and emit the webhook in their signed dialect, so your existing verification code just works. Correlated by order_id.

# before:  https://api.cryptomus.com/v1/payment
# after:  https://paygate.love/compat/cryptomus/v1/payment
# key: your paygate API key; webhook secret = your paygate apiSecret
cryptomus✅ /compat/cryptomus
heleket✅ /compat/heleket
nowpayments✅ /compat/nowpayments
oxapay✅ /compat/oxapay
cryptocloud✅ /compat/cryptocloud
coinbase✅ /compat/coinbase
plisio✅ /compat/plisio
coinpayments✅ /compat/coinpayments
opennode✅ /compat/opennode
confirmo✅ /compat/confirmo
btcpay✅ /compat/btcpay
bitpay✅ /compat/bitpay
enot✅ /compat/enot
0xprocessing✅ /compat/0xprocessing
2328✅ /compat/2328
cispay✅ /compat/cispay
lava✅ /compat/lava
pawpayments✅ /compat/pawpayments
zenobank✅ /compat/zenobank
aaio✅ /compat/aaio
coingate✅ /compat/coingate
cryptobot✅ /compat/cryptobot

Need another one? Ping us — a new adapter is a single module.

Accept payments inside your own Telegram bot

Merchant is a bot? Don't redirect users to a web page or a third-party wallet bot. Your bot calls our API, shows the address + amount + QR right in the chat, and flips the message to "✅ Paid" the moment the payment confirms on-chain. Same in-bot UX as CryptoBot, but funds land on-chain, you keep your keys, and the fee is a fraction of a Star.

1. POST /v1/invoices               # your API key → { id, pay_address, pay_uri, amount_expected }
2. bot.sendPhoto( https://paygate.love/i/<id>/qr.png )   # public QR, Telegram fetches it
   + "Open wallet" button → pay_uri
3. our invoice.paid webhook → bot.editMessage → "✅ Paid"

The user never leaves the merchant's bot. The QR endpoint /i/<id>/qr.png is public (encodes only the address). A copy-paste example (grammy/telegraf) is in docs/BOT-INTEGRATION.md.

For streamers: donation alerts, goal bar, leaderboard

All streamer endpoints below use the alert token — it's already embedded in the overlay and leaderboard URLs on the cabinet's Alerts page. It's a read-only capability: it never replaces your API key, but don't post the widget URL publicly. Under the hood a donation is just an invoice with a donor name and message.

How to set up donations on your stream — step by step

  1. Register as a streamer: on the sign-up page pick the “Streamer / creator” account type — the cabinet is then tailored to tips.
  2. Open Cabinet → “Alerts”: it holds your overlay URL (/alerts/widget?token=…), alert-look settings and the goal editor. Copy the overlay URL.
  3. In OBS/Streamlabs: Sources → “+” → Browser Source → paste the URL, set the size to your canvas (e.g. 1920×1080) → OK. Alerts and the goal bar now render on stream; check with the test-donation button.
  4. Set a fundraising goal on the same Alerts page — title, target amount and currency. The progress bar appears in the overlay and via GET /alerts/goal.
  5. Create a donation link (Cabinet → “Links”), share the link/QR with viewers, and post the public leaderboard /d/<token> in your channel.
  6. Advanced: push donations from other platforms via POST /v1/donations/external, or feed a third-party progress bar from GET /alerts/goal — details below.

OBS overlay (Browser Source)

A ready HTML page with live donation alerts and the goal bar — add it to OBS/Streamlabs as a Browser Source:

https://paygate.love/alerts/widget?token=<alertToken>

Fundraising goal — JSON for any progress bar (pull)

Public JSON of the current goal (the token is the capability; cached ~5 s). Any external progress-bar widget can poll it to display the combined total elsewhere — this is how you connect the paygate fundraiser to another bar.

curl "https://paygate.love/alerts/goal?token=<alertToken>"
→ { "active": true, "title": "New PC", "target": 1000,
    "current": 337.5, "currency": "USD" }
# no goal set → { "active": false }

External donations — merge other sources into the bar (push)

Record a donation that happened elsewhere (PayPal, DonationAlerts, manual) so it counts toward the SAME goal bar and, optionally, fires the same OBS alert. One bar, all sources — crypto plus whatever you push here. Auth: your API key.

curl -X POST https://paygate.love/v1/donations/external \
  -H "X-Api-Key: pk_..." -H "Content-Type: application/json" \
  -d '{ "amount": 5, "currency": "USD", "name": "Alice",
        "message": "gg!", "source": "paypal", "fire_alert": true }'
→ 201 { "ok": true, "amount_usd": 5 }

Fields: amount (>0, required), currency (default USD), name (≤60), message (≤300), source (≤40, default "api"), fire_alert (default true). The amount is converted to USD for the goal total.

Live alert stream (SSE)

Server-Sent Events with each donation — build a fully custom overlay instead of our widget:

const es = new EventSource(
  "https://paygate.love/alerts/stream?token=<alertToken>");
es.onmessage = (e) => {
  const d = JSON.parse(e.data); // { name, amount, currency, asset, message }
  showAlert(d);
};

Public leaderboard

A shareable public top-donors page (top supporters, recent donations, the goal) — post it in your channel description or chat:

https://paygate.love/d/<alertToken>

Payouts: by default donations are custodial — withdraw from the cabinet whenever you like. Or add your wallet's xpub in the cabinet (non-custodial) and donations land straight in your wallet on EVM / TRON / BTC / LTC / DOGE.

Referral program

Invite shops and streamers and earn a share of our commission on every payment they make — for life. The default rate is 20%, and it can be set individually per partner.

https://paygate.love/?ref=<yourCode>

Your unique link lives in Cabinet → Referrals. Anyone who registers through it (the ?ref= code is captured via a cookie, or entered in the optional field on the signup form) is permanently linked to you.

Earnings accrue automatically on each confirmed (paid) invoice of a referred merchant, in USD; stats and amounts are shown in Cabinet → Referrals.

💸 Donor prepaid wallet (instant donations)

A viewer tops up once (crypto confirms once), then fires instant donations to any Paygate streamer from an internal balance — the alert pops immediately, with no per-donation network wait. Donations land in your normal balance; withdraw as usual. Wallet page: /w (bearer link, token in the #fragment — never hits the logs).

🧩 Plugin setup guides

Before you start, grab your API key and secret from your store's Settings page. ⚙️

🛒 WooCommerce — setup

  1. Download the plugin zip (the “Download” button on the Plugins page or in your dashboard).
  2. WP Admin → Plugins → Add New → Upload Plugin → choose the zip → Install → Activate.
  3. WooCommerce → Settings → Payments → enable “Paygate (crypto)” and click Manage.
  4. Paste your API key and secret, save. The webhook is wired automatically.
  5. Place a test order: pick “Paygate” at checkout, pay, and the order flips to Paid on the signed webhook.

🖥️ WHMCS — setup

  1. Download and unzip. Inside you'll find a modules/gateways/ folder.
  2. Upload the contents of modules/gateways/ into your WHMCS root (it merges with the existing structure).
  3. WHMCS Admin → Setup → Payments → Payment Gateways → “All Payment Gateways” tab → activate “Paygate”.
  4. Enter your API key and secret, save. Verify with a test invoice — status updates via the callback.

🛍️ OpenCart — setup

  1. Download the zip. Copy the contents of upload/ into your OpenCart root (merges with admin/ and catalog/), or install the zip via Extensions → Installer.
  2. Extensions → Extensions → Payments → find “Paygate — Crypto Payments” → “+” (Install) → pencil (Edit).
  3. Status = Enabled, paste your API key and secret, pick the order statuses, save. The webhook is wired automatically (callback_url).
  4. Test order: pick “Pay with Crypto” at checkout, pay, and the status updates via the signed webhook.

🧿 PrestaShop — setup

  1. Download the module zip. Back office → Modules → Module Manager → “Upload a module” → choose the zip → install.
  2. Click “Configure”, paste your API key and secret (leave base URL as https://paygate.love), save.
  3. The webhook is wired automatically (callback_url) and shown on the settings page.
  4. Test order: pick “Pay with Crypto”, pay, and the order moves to “Payment accepted” on the signed webhook.

🅜 Magento 2 — setup

  1. Copy the Paygate folder into app/code/ (module lives at app/code/Paygate/Crypto).
  2. From the Magento root: bin/magento module:enable Paygate_Crypto && bin/magento setup:upgrade && setup:di:compile && cache:flush.
  3. Admin → Stores → Configuration → Sales → Payment Methods → “Paygate — Crypto Payments”: Enabled = Yes, paste your API key and secret, save.
  4. Webhook: https://your-store/paygate/webhook (sent automatically as callback_url). Verify with a test order.

🛒 CS-Cart — setup

  1. Download the zip. Administration → Add-ons → Manage add-ons → “+” (Upload & install) → choose the zip.
  2. Administration → Payment methods → Add: Processor = “Paygate (crypto)”.
  3. On the Configure tab paste your API key and secret (leave base URL as https://paygate.love), save and activate.
  4. The webhook is wired automatically (callback_url). Verify with a test order — the status updates via the signed webhook.

🅱️ Blesta — setup

  1. Download the zip. Copy components/gateways/nonmerchant/paygate/ into your Blesta install at the same path.
  2. Settings → Company → Payment Gateways → Available → install “Paygate — Crypto Payments”.
  3. Click “Manage”, enter your API key and secret (leave base URL as https://paygate.love), save.
  4. The callback URL is Blesta's standard gateway callback, sent automatically. Verify with a test invoice.

🧾 FOSSBilling — setup

  1. Download the zip and extract library/Payment/Adapter/Paygate.php into your FOSSBilling root (paths merge).
  2. Admin → System → Payment gateways → New payment gateway → activate “Paygate”.
  3. Paste your API key and secret (leave base URL as https://paygate.love), save.
  4. The webhook (IPN) is wired automatically as callback_url. Verify with a test invoice — payment applies via the signed webhook.

💬 XenForo — setup

  1. Download the zip and copy the contents of upload/ into your forum root (creates src/addons/Paygate/Crypto).
  2. Admin → Add-ons → install “Paygate — Crypto Payments”.
  3. Admin → Setup → Payment profiles → Add payment profile → Paygate: paste your API key and secret, save.
  4. Attach the profile to your User upgrades. Payment confirms via the signed webhook through payment_callback.php.

📦 BoxBilling — setup

  1. Download the zip and extract bb-library/Payment/Adapter/Paygate.php into your BoxBilling root.
  2. Admin → Configuration → Payment gateways → New payment gateway → activate “Paygate”.
  3. Paste your API key and secret (base URL https://paygate.love), save. The webhook (IPN) wires automatically.
  4. Verify with a test invoice — payment applies via the signed webhook.

🎮 Paymenter — setup

  1. Download the zip and extract extensions/Gateways/Paygate into your Paymenter root.
  2. Admin → Extensions → Gateways → enable “Paygate”.
  3. Paste your API key and secret (base URL https://paygate.love), save.
  4. Webhook: /extensions/gateways/paygate/webhook (sent automatically as callback_url). Verify with a test invoice.

👥 Invision Community — setup

  1. Download the zip and install the paygate application (AdminCP → System → Applications; see README for dev-mode / tar build).
  2. AdminCP → Commerce → Payments → Payment Methods → Create New → Paygate.
  3. Paste your API key and secret (base URL https://paygate.love), save.
  4. Payment confirms via the signed webhook; underpaid goes to Held for manual review.

📋 vBulletin — setup (vB4 / vB5)

  1. Pick your archive: vB4 (4.2.x) → includes/paymentapi/class_paygate.php; vB5 → core/includes/paymentapi/class_paygate.php.
  2. Copy the class file to the right path and run install.sql from the archive (registers the method in the paymentapi table).
  3. AdminCP → Paid Subscriptions → Payment API Manager → Paygate: enable, paste your API key and secret (base URL https://paygate.love).
  4. The subscription activates via the signed webhook (payment_gateway.php); duplicates bounce on the transaction id.

🎮 Azuriom — setup

  1. Download the zip and add PaygateMethod to the Shop plugin (see README: patch PaymentManager or register via registerPaymentMethod).
  2. Admin → Shop → Settings → Payment gateways → Paygate: paste your API key and secret (base URL https://paygate.love).
  3. Payment confirms via the signed webhook (shop.payments.notification); completed payments are idempotent.

🏬 Webasyst / Shop-Script — setup

  1. Download the zip and extract wa-plugins/payment/paygate into your Webasyst root.
  2. Store → Settings → Payment → add method → Paygate: paste your API key and secret (base URL https://paygate.love).
  3. Payment confirms via the signed webhook (waPayment relay URL); dedup via native_id.

🛒 X-Cart — setup

  1. Download the zip and extract classes/ and skins/ into your X-Cart root, then rebuild the cache (Re-deploy).
  2. Admin → Store setup → Payment methods → enable “Paygate”.
  3. Paste your API key and secret (base URL https://paygate.love), save. Payment confirms via the signed webhook.

🛍️ Zen Cart — setup

  1. Download the zip: module file to includes/modules/payment/, language to includes/languages/english/modules/payment/, and ipn_paygate.php to the store root.
  2. Admin → Modules → Payment → Paygate → Install; paste your API key and secret (base URL https://paygate.love).
  3. The order is created as pending; status updates via the signed webhook (ipn_paygate.php).

🏪 osCommerce — setup

  1. Download the zip (targets osCommerce 2.3.x): module file to includes/modules/payment/, callback.php to ext/modules/payment/paygate/, language to includes/languages/english/….
  2. Admin → Modules → Payment → Paygate → Install; paste your API key and secret (base URL https://paygate.love).
  3. Order status updates via the signed webhook (ext/…/callback.php); the webhook retries until the order is found.

🛒 VirtueMart (Joomla) — setup

  1. Joomla → Extensions → Install: upload the zip (or copy to plugins/vmpayment/paygate/ and click Discover).
  2. Enable the “VM Payment - Paygate” plugin, then VirtueMart → Payment Methods → create a method using it.
  3. Paste your API key and secret (base URL https://paygate.love), save. Payment confirms via the signed webhook.

💧 Drupal Commerce — setup

  1. Extract the module to modules/custom/paygate (or via composer), enable it on Extend.
  2. Commerce → Configuration → Payment gateways → Add: choose Paygate (off-site redirect).
  3. Paste your API key and secret (base URL https://paygate.love), save. The notify webhook is the source of truth.

⬇️ Easy Digital Downloads — setup

  1. WP Admin → Plugins → Add New → Upload → choose the zip → Install → Activate.
  2. Downloads → Settings → Payment Gateways → enable “Paygate” and open its settings.
  3. Paste your API key and secret (base URL https://paygate.love), save. Payment confirms via the signed webhook (edd-listener).

🧾 HostBill — setup (free bridge)

  1. This is a lightweight bridge, not the paid SDK module: unzip it into a web-accessible folder, e.g. https://your-billing/paygate/.
  2. HostBill → Settings → API: create an API user, whitelist this server's IP. Copy config.sample.php → config.php and fill in the HostBill + Paygate keys and a random link_secret.
  3. In your Paygate store settings set the webhook/callback → https://your-billing/paygate/callback.php. A payment closes the invoice automatically via the Admin API (addInvoicePayment).
  4. Add the “Pay with Crypto” button to invoices via the hooks/paygate_button.php hook (into includes/hooks/) or a ready signed link pay.php?invoice_id=…&token=… — see the README.

🖥️ WISECP — setup

  1. Copy the coremio/ folder from the zip over your WISECP root (the module lands in coremio/modules/Payment/Paygate/).
  2. Admin → Settings → Payment Gateways → enable “Paygate — Crypto Payments” and paste your API key and secret (base URL https://paygate.love).
  3. No webhook setup needed: the module passes its callback link with every checkout. Payment confirms via the signed webhook.

🧾 ClientExec — setup

  1. Unzip the archive into plugins/gateways/paygate/ of your ClientExec install.
  2. Settings → Plugins → Payment Processors → activate Paygate and paste your API key and secret (base URL https://paygate.love).
  3. Webhook: https://your-domain/plugins/gateways/paygate/callback.php — set it in your Paygate store settings.

🎨 Tilda — setup (universal payment system)

  1. This is a self-hosted bridge: unzip it onto your PHP hosting (e.g. https://your-domain/paygate/) and fill in config.php from the sample.
  2. In Tilda: Site Settings → Payment Systems → Universal payment system → API URL = https://your-domain/paygate/receive.php; field mapping and signature per the README.
  3. Paygate webhook: https://your-domain/paygate/callback.php. On payment the bridge sends Tilda a signed notification — the order flips to paid.

🛒 BigCommerce — setup (bridge)

  1. BigCommerce's native payment list is partner-gated, so this is a bridge: unzip onto your PHP hosting and fill in config.php.
  2. In BigCommerce create a store-level API account (Orders scope), enable the offline method “Cryptocurrency (Paygate)” and add the pay button per the README (Script Manager).
  3. Paygate webhook: https://your-domain/paygate/callback.php — on payment the order moves to Awaiting Fulfillment automatically.

🛍️ Zid — setup (private bridge)

  1. Zid's App Store won't list crypto (SAMA), so the bridge runs privately with your own partner credentials. Deploy the Node service from the zip (npm i && npm run build).
  2. Fill in .env (Zid tokens, Paygate keys) and register the order-created webhook per the README.
  3. The buyer pays via the /pay/:orderId link; on confirmation the bridge marks the order paid through the Zid API.

1. Create an invoice

POST /v1/invoices
X-Api-Key: pk_...
Idempotency-Key: order-1042        # optional, prevents duplicates
Content-Type: application/json

{ "network": "ton", "asset": "USDT", "amount": "25.00", "order_id": "1042" }

The response has id, pay_address, pay_uri, expires_at. Send the buyer to /pay/.

Optional request fields: quote_currency (amount currency, default USD), order_id, callback_url (per-invoice webhook), success_url (where to return the buyer), test (sandbox). The full response also includes status, network, asset, amount_expected, rate_locked, fee_percent, telegram_url.

Sandbox: add "test": true — the invoice isn't chain-watched and never affects your balance; simulate its payment in the dashboard to validate webhooks. Its webhook is signed identically but carries "test": trueonly fulfil orders when test === false.

1b. Live rate — price a USD amount in BTC/LTC

GET /v1/quote?asset=BTC&quote_currency=USD
X-Api-Key: pk_...
→ { "asset": "BTC", "quote_currency": "USD", "rate": "63022.25" }

# price a $12.99 item in BTC:
#   amount = 12.99 / 63022.25 = 0.00020612  → send as "amount" to /v1/invoices
# optional: pass &amount=12.99 to get "quote_amount" back too

The amount is denominated in quote_currency (default USD) — the gateway converts it to the coin at the live rate, no manual math needed. For USDT/USDC quoted in USD that's 1:1. To price directly in the coin, set quote_currency to the coin symbol (e.g. quote_currency=BTC) — then no conversion happens. The rate comes from CoinGecko/Coinbase, refreshes every ~45s and is locked into the invoice (rate_locked), so the buyer always pays the correct up-to-the-minute amount. The response returns quote_amount (as you sent it) and amount_expected (the final coin amount).

Don't want to do the math? Use POST /v1/checkouts with a USD amount — the buyer picks the coin and we handle the live conversion.

Payment link (buyer picks the coin)

POST /v1/checkouts
X-Api-Key: pk_...
Content-Type: application/json

{ "amount": "25.00", "quote_currency": "USD", "order_id": "1042" }
→ { "checkout_url": "https://…/checkout/…", "short_url": "https://…/c/…",
    "telegram_url": "https://t.me/…", "expires_at": "…" }

POST /v1/checkouts with an amount creates a link where the buyer picks the network and coin — ideal with no integration. Response: checkout_url, short_url, telegram_url, expires_at. Supports the same order_id, callback_url and success_url as invoices.

🤖 Accept payments in a Telegram bot / shop

Selling right inside Telegram? No website needed. Your bot creates a checkout via the API and gets a telegram_url — a deep link that opens the payment flow inside our Telegram bot: the buyer picks a coin/network, sees the address and QR, and pays. You receive a signed webhook and deliver the goods.

  1. The buyer taps “Buy” in your bot → your bot calls POST /v1/checkouts (with order_id and callback_url).
  2. Your bot replies with an inline button linking to telegram_url (or short_url to pay on a web page).
  3. The buyer pays without leaving Telegram → you get the invoice.paid webhook → your bot delivers the product/access.
// Telegram bot (grammY/Telegraf) — sell for crypto
bot.callbackQuery("buy", async (ctx) => {
  const r = await fetch("https://paygate.love/v1/checkouts", {
    method: "POST",
    headers: { "X-Api-Key": PK, "Content-Type": "application/json" },
    body: JSON.stringify({ amount: "9.99", quote_currency: "USD",
      order_id: ctx.from.id + ":" + Date.now(),
      callback_url: "https://my-bot.example/paygate-webhook" }),
  }).then((x) => x.json());
  // r.telegram_url opens the pay flow INSIDE Telegram (coin choice + address + QR)
  await ctx.reply("Оплатить криптой:", {
    reply_markup: { inline_keyboard: [[{ text: "💳 Pay", url: r.telegram_url }]] },
  });
});

// Deliver the goods on the signed webhook (see "Webhooks" below)
app.post("/paygate-webhook", (req, res) => {
  if (verifySignature(req) && req.body.event === "invoice.paid" && !req.body.test)
    deliverOrder(req.body.order_id);   // ship / grant access
  res.sendStatus(200);
});

Tip: use telegram_url to pay inside Telegram, or short_url for a normal web checkout page. Tie order_id to the buyer (chat id) and the order so the webhook maps unambiguously. Never deliver goods while test is not false.

2. Invoice status

GET /v1/invoices/<id>
X-Api-Key: pk_...
→ { "status": "paid", "amount_received": "25",
    "settlement": { "gross": "25", "fee": "…", "spread": "…", "net": "…", "revenue": "…" } }

Statuses: pending → detected → paid (plus underpaid, overpaid, expired, cancelled, settled).

More endpoints

GET /v1/invoices — list invoices with pagination (limit up to 200, offset, status filter).
POST /v1/invoices/<id>/cancel — cancel a pending/detected invoice (fires invoice.cancelled).
GET /v1/quote?asset=&quote_currency=&amount= — preview the rate and converted amount.
GET /v1/networks — list networks and coins (no key required).
GET /v1/reconciliation?from=&to= — invoiced-vs-received reconciliation (limit 30 req/min).

Reconciliation: GET /v1/reconciliation?from=&to= — invoiced vs received (net of fees) + per-order discrepancies (under/overpaid, unpaid). We're the source of truth for what arrived; for non-custodial, reconcile against your own wallet. The tool gives data — decisions (shipping, disputes) are on you.

3. Webhook

On status change we POST to your webhook URL. Header X-Signature = HMAC-SHA256(body, api_secret). Verify the signature and freshness (timestamp) before processing.

Webhook payload

{
  "event": "invoice.paid",
  "invoice_id": "inv_…", "order_id": "1042",
  "status": "paid", "test": false,
  "asset": "USDT", "network": "ton",
  "quote_currency": "USD",
  "amount_expected": "25", "amount_received": "25",
  "tx_hash": "…", "timestamp": "2026-07-12T20:00:00.000Z",
  "invoice": { "id": "inv_…", "order_id": "1042", "status": "paid",
               "quote_currency": "USD",
               "amount_expected": "25", "amount_received": "25" }
}

Events: invoice.detected, invoice.paid, invoice.underpaid, invoice.overpaid, invoice.expired, invoice.cancelled. Headers: X-Signature, X-Webhook-Id, X-Event.

// Node — verify signature (constant-time), dedupe, gate on test
import crypto from "node:crypto";
const expected = crypto.createHmac("sha256", API_SECRET).update(rawBody).digest("hex");
const sig = String(req.headers["x-signature"] ?? "");
if (sig.length !== expected.length ||
    !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
  return res.sendStatus(401);
const evt = JSON.parse(rawBody);
if (Date.now() - new Date(evt.timestamp) > 5*60_000) return res.sendStatus(400); // anti-replay
if (seen(req.headers["x-webhook-id"])) return res.sendStatus(200);               // idempotency
if (evt.event === "invoice.paid" && evt.test === false) fulfil(evt.order_id);   // only real payments

Delivery: 3 quick attempts, then a durable queue up to 12 attempts with backoff up to 1h. Dedupe by X-Webhook-Id. The webhook URL must be public http(s) — localhost/private hosts and redirects are rejected. Never fulfil while test is not false.

Hardening

Full server-to-server integration example (Node, no plugins): merchant-backend.mjs
Get keys →