Step 1
Authenticate
Create an API key in Dashboard → Settings (shown once). Send it as a bearer token from your server only — never from a browser.
Authorization: Bearer nxp_test_…A small, versioned REST API and signed webhooks. Every account starts in test mode with its own keys; nothing you do in test mode touches real funds.
Step 1
Create an API key in Dashboard → Settings (shown once). Send it as a bearer token from your server only — never from a browser.
Authorization: Bearer nxp_test_…Step 2
Amounts are decimal strings. Send an Idempotency-Key so a retried request returns the same invoice instead of a duplicate.
curl -X POST https://api.example/v1/invoices -H "Authorization: Bearer nxp_test_…" -H "Idempotency-Key: order-1001" -H "Content-Type: application/json" -d '{"amount":"75.00","currency":"USD","merchant_order_id":"1001","description":"Order 1001"}'
# → 201 { "id": "…", "public_id": "chk_…", "status": "pending", "checkout_url": "https://…/pay/chk_…", … }Redirect the customer to checkout_url. Poll GET /v1/invoices/{id} if you need status, but rely on webhooks to fulfil.
Step 3
Register an endpoint (Dashboard → Developers). Every event is signed over the raw body. Verify, then deduplicate on the event id inside the same transaction that credits the order — deliveries are at-least-once and you will see duplicates.
X-NexusPay-Signature: t=<unix seconds>,v1=<hex>
signature = HMAC_SHA256(secret, "<t>." + raw_body) # reject if |now − t| > 300s
{ "id": "…", "type": "invoice.paid", "version": 1, "environment": "test",
"data": { "invoice_id": "…", "merchant_order_id": "1001", "status": "paid", "amount": "75.00",
"payment": { "asset_symbol": "USDT", "network_id": "bsc-testnet", "tx_hash": "0x…", … } } }Event types: invoice.confirming, invoice.paid, invoice.partial, invoice.expired, invoice.late_review, invoice.cancelled, refund.*, ping. Only invoice.paid should credit an order.
Step 4
Errors are JSON with a stable machine code.
{ "error": { "code": "idempotency_conflict", "message": "Idempotency-Key reused with a different payload" } }
401 invalid key · 403 suspended / forbidden · 404 not found (also for other tenants' objects) · 409 conflict · 422 invalid · 429 rate limited · 503 pricing_unavailable / platform_pausedexamples/merchant/ in the repository.GET /openapi.json on the API host; interactive docs at /docs.packages/contracts/events/webhook.v1.schema.json.Framework stack
For Node or Laravel stores, the flow is identical: create invoice on checkout, save merchant_order_id, and mark paid only from verified webhook callback.
// Laravel route idea
Route::post('/checkout', [CheckoutController::class, 'create']);
Route::post('/nexuspay/webhook', [WebhookController::class, 'handle']);
// Node webhook: verify with raw body
app.post('/nexuspay/webhook', express.raw({type: 'application/json'}), (req, res) => {
const ok = verifyNexusPaySignature(req.headers['x-nexuspay-signature'], req.body);
if (!ok) return res.status(400).send('invalid signature');
// if event.id not processed, update order inside single transaction, then 200
});Need starter files? Use examples/merchant/node/server.js for raw Node and examples/merchant/laravel/ README + controllers for Laravel.