Invoices
Invoice lifecycle
- Create invoice.
- Build canonical payment intent.
- Execute payment (direct or relay).
- Track status and stream updates.
- Cancel or confirm fallback if needed.
Create invoice
What this does: creates offchain invoice metadata and pricing context.
import { createApiClient } from '@pepay/x402flex';
const api = createApiClient({ baseUrl: 'https://api.bnbpay.org' });
const invoice = await api.invoices.create({
title: 'Order #4201',
merchantId: 'merchant-123',
merchantName: 'Runey',
amount: '25.00',
currencyToken: 'USDT',
network: 'bnbTestnet',
reference: 'order-4201',
});
Expected result: invoice.invoiceId to anchor the payment workflow.
Build payment intent
What this does: returns API-aligned intent + derived IDs + signing metadata.
const built = await api.payments.buildIntent({
mode: 'minimal',
network: 'bnbTestnet',
merchant: '0x1111111111111111111111111111111111111111',
token: '0x55d398326f99059fF775485246999027B3197955',
amount: '25.00',
scheme: 'permit2',
invoiceId: invoice.invoiceId,
});
console.log({
paymentId: built.derived.paymentId,
resourceId: built.derived.resourceId,
intentHash: built.derived.intentHash,
});
Expected result: canonical paymentId/resourceId tied to invoice reference.
Execute payment
What this does: submits a relay payment from built payloads.
const witness = {
schemeId: '0xc07338ac3a63d5933e6a5b2184602e306eb7c25700866301b635132c811546f1',
intentHash: built.derived.intentHash,
payer: '0x2222222222222222222222222222222222222222',
salt: built.input.salt,
};
const permit2 = {
permit: {
permitted: { token: built.input.token, amount: built.input.amountWei },
nonce: 1,
deadline: Math.floor(Date.now() / 1000) + 3600,
},
transferDetails: { to: '0xf14f56A54E0540768b7bC9877BDa7a3FB9e66E91', requestedAmount: built.input.amountWei },
signature: '0xPERMIT2_SIGNATURE',
};
await api.relay.payment({
network: 'bnbTestnet',
scheme: 'permit2',
intent: built.derived.intent,
witness,
witnessSignature: '0xWITNESS_SIGNATURE',
permit2,
reference: built.input.baseReference,
});
Expected result: relay returns transaction hash and payment ID.
Track status and stream events
What this does: observes invoice updates via polling and SSE/WS streams.
const status = await api.invoices.status(invoice.invoiceId);
const sseUrl = api.invoices.streamSseUrl(invoice.invoiceId);
const wsUrl = api.invoices.streamWsUrl(invoice.invoiceId);
console.log(status.status, sseUrl, wsUrl);
Expected result: realtime invoice status transitions (pending -> paid etc.).
Cancel and confirm fallback
What this does: handles operational exceptions.
await api.invoices.cancel(invoice.invoiceId);
await api.invoices.confirmPayment(invoice.invoiceId, {
txHash: '0x...',
paidBy: '0x2222222222222222222222222222222222222222',
paidAmount: '25.00',
paidToken: '0x55d398326f99059fF775485246999027B3197955',
});
Expected result: invoice reaches terminal state even when automatic linkage is delayed.
Production checklist
- Persist invoice ID, payment ID, resource ID, and reference.
- Persist nonce for deterministic payment reproduction.
- Recompute reference hash from final tagged reference string.
- Add retries for temporary indexer lag.