Payment Request webhooks and operations
Fulfill receivables from verified events and monitor delivery, unapplied funds and aggregate drift.
Subscribe to payment_request.* or exact events. Verify signatures against the raw body, persist
each event ID with a unique constraint, and tolerate duplicates and out-of-order delivery.
| Event | Meaning |
|---|---|
payment_request.finalized | Terms were locked and the request became payable. |
payment_request.sent | The email provider accepted one delivery attempt. |
payment_request.delivery_failed | Email exhausted its retry policy. |
payment_request.payment_processing | Funds were observed and are awaiting finality. |
payment_request.payment_applied | Confirmed funds were allocated. |
payment_request.payment_unapplied | Confirmed funds require review. |
payment_request.payment_failed | An attempt ended without allocatable funds. |
payment_request.paid | The remaining receivable balance reached zero. |
payment_request.sent is not proof of inbox delivery. Likewise, payment_processing is not final
payment. Fulfill only from valid terminal resource state, normally payment_request.paid, and
retrieve the request if event order is ambiguous.
Process transitions idempotently
Keep the Payment Request ID separate from the Payment Intent and allocation IDs. A single request can receive several attempts and partial allocations.
async function processPaymentRequestEvent(event) {
await database.transaction(async (transaction) => {
if (await transaction.events.exists(event.id)) return
await transaction.events.insert(event.id)
if (event.type === 'payment_request.paid') {
const request = await paybytoken.paymentRequests.get(event.data.id)
if (request.status === 'paid') {
await transaction.receivables.markPaid(request.id)
}
}
})
}Use a decimal library when your accounting workflow also compares monetary fields; never use JavaScript floating-point arithmetic for those checks.
Review unapplied payments
const unapplied = await paybytoken.paymentRequests.listAllPayments({
status: 'unapplied',
limit: 50,
})For each item, inspect its unapplied_reason, Payment Intent, request status, amount requested,
amount received and amount already applied. Resolve it through an authorized accounting or support
workflow. Do not mutate allocation tables or change a paid request back to open.
Check aggregate reconciliation
const report = await paybytoken.paymentRequests.reconciliation()
if (!report.reconciled) {
alertOperations(report.mismatches)
}Reconciliation reports drift; they do not automatically move money or rewrite request history. Persist the report time and affected request IDs, investigate the underlying payments and escalate before taking a compensating action.
Operational checks should alert on reconciliation mismatches, unapplied payments, and terminal delivery failures. The API reports these without mutating financial data automatically.
Did this page answer your question?
Your feedback helps us improve the integration path.