← Blog/Developer

Crypto Payment API Integration Guide: From Zero to Production in One Day

May 24, 2026 · 10 min read

A complete technical walkthrough for integrating a crypto payment API. Covers invoice creation, address generation, webhook handling, signature verification, and error handling with code examples in Node.js and Python.

Integrating a crypto payment gateway is fundamentally simpler than integrating a card processor. There is no PCI compliance scope, no 3DS authentication flows, no redirect pages. The core loop is: create an invoice, display a payment address to the user, receive a webhook when the payment confirms. This guide walks through each step with production-ready code.

Architecture Overview

A crypto payment integration has four components: (1) your server calls the Bekena API to create an invoice, (2) you display the payment address and amount to the customer, (3) Bekena monitors the blockchain and calls your webhook when payment arrives, (4) your webhook handler verifies the signature and updates your order state.

Step 1: Create an Invoice

javascript
// Node.js (fetch API) async function createCryptoInvoice(orderId, amountUsd) { const res = await fetch("https://api.bekena.com/v1/invoices", { method: "POST", headers: { "X-Api-Key": process.env.BEKENA_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ amount: amountUsd.toFixed(2), currency: "USDT_TRC20", orderId, webhookUrl: `${process.env.BASE_URL}/webhook/bekena`, returnUrl: `${process.env.BASE_URL}/orders/${orderId}`, expiresIn: 3600, // 1 hour }), }); if (!res.ok) throw new Error(`Bekena API error: ${res.status}`); return res.json(); }

Step 2: Display the Payment Address

The invoice response contains a payment address and exact crypto amount. Display both clearly to the customer. Always show the amount in crypto (not just in USD) so the customer sends the exact amount. A QR code significantly improves mobile UX — most crypto wallets scan QR codes natively.

javascript
// Invoice response shape { "invoiceId": "inv_01JFK2...", "paymentAddress": "TRx8mX...", // TRC20 address "amountDue": "99.50", // USDT amount "currency": "USDT_TRC20", "expiresAt": "2026-05-22T16:00:00Z", "status": "pending" }

Step 3: Handle the Webhook

When payment confirms on-chain, Bekena sends a POST request to your webhookUrl. Always verify the signature before trusting the payload. Bekena signs each webhook with HMAC-SHA256 using your webhook secret, and the signature is in the X-Bekena-Signature header.

javascript
// Express.js webhook handler import crypto from "crypto"; app.post("/webhook/bekena", express.raw({ type: "application/json" }), (req, res) => { const sig = req.headers["x-bekena-signature"]; const expected = crypto .createHmac("sha256", process.env.BEKENA_WEBHOOK_SECRET) .update(req.body) .digest("hex"); if (sig !== expected) return res.status(401).send("Invalid signature"); const event = JSON.parse(req.body); if (event.type === "payment.confirmed") { const { invoiceId, orderId, amount, currency } = event.data; await fulfillOrder(orderId); // your business logic } res.status(200).send("ok"); });

Step 4: Python Example

python
# Python (Flask) webhook handler import hmac, hashlib, json from flask import Flask, request, abort app = Flask(__name__) @app.route("/webhook/bekena", methods=["POST"]) def bekena_webhook(): sig = request.headers.get("X-Bekena-Signature", "") body = request.get_data() expected = hmac.new( BEKENA_WEBHOOK_SECRET.encode(), body, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(sig, expected): abort(401) event = json.loads(body) if event["type"] == "payment.confirmed": fulfill_order(event["data"]["orderId"]) return "ok", 200

Idempotency: Handling Duplicate Webhooks

Webhooks can be delivered more than once. Network retries, server restarts, or timeout recoveries can cause the same event to arrive multiple times. Always make your webhook handler idempotent — check whether the invoiceId has already been processed before fulfilling the order.

javascript
// Idempotent webhook handler if (event.type === "payment.confirmed") { const alreadyProcessed = await db.payments.findOne({ invoiceId: event.data.invoiceId }); if (!alreadyProcessed) { await db.payments.insert({ invoiceId: event.data.invoiceId, ... }); await fulfillOrder(event.data.orderId); } }

Testing Your Integration

Use ngrok or Cloudflare Tunnel to expose your local webhook endpoint during development. Create a test invoice via the API, send a small real payment to the generated address, and verify your webhook handler receives and processes the confirmation correctly. For automated testing, use the Bekena sandbox environment with its test transaction simulator.

Production Checklist

  • ✓Webhook signature verification implemented and tested
  • ✓Idempotency check in webhook handler (prevent double-fulfillment)
  • ✓Invoice expiry handled gracefully (show "payment expired" UI)
  • ✓Crypto amount displayed clearly with network label (TRC20, ERC20, etc.)
  • ✓QR code generated for payment address (improves mobile conversion)
  • ✓Webhook endpoint returns 200 immediately (async processing)
  • ✓Failed webhook retries: Bekena retries 3× with exponential backoff
  • ✓Reconciliation: daily check of confirmed invoices vs your order DB
Note: The Bekena API documentation at docs.bekena.com includes interactive playground, language-specific SDKs, and a Postman collection for quick testing.

Ready to accept crypto payments?

Start with a free sandbox account

Create Free Account →

Related articles

Developer

How to Properly Verify Bekena Webhooks (With Code Examples)

Developer

Understanding Idempotency Keys in Payment APIs

Developer

Building a Telegram Bot That Accepts Crypto Payments