Skip to main content

Setup

Required env vars:

How it works

Checkouts and one-off payments are both built on Xendit’s hosted Invoices. Xendit’s Recurring Plans API has no separate reusable plan template — each plan already carries its own amount/currency/schedule, and requires a pre-created Xendit customer id plus at least one saved payment token:

Webhooks

Xendit verifies webhooks with a Callback Verification Token copied from your dashboard — a plain string comparison via the x-callback-token header, not an HMAC signature.

Raw Xendit events

Opt into any native Xendit notification — fully typed against Xendit’s callback payload shape:
Every webhook always emits its raw event first, alongside the matching standard PayKit event below where one applies. Invoice callbacks are sent as the raw invoice resource itself (no event/data wrapper); Recurring webhooks use a wrapping { event, business_id, created, data } envelope instead — Xendit’s two product lines don’t share a webhook shape.
Raw eventPayKit event
xendit.invoice.pendingpayment.created
xendit.invoice.paidpayment.succeeded + invoice.generated
xendit.invoice.settledpayment.succeeded + invoice.generated
xendit.invoice.expiredpayment.failed
xendit.recurring.plan.activatedsubscription.updated
xendit.recurring.plan.inactivatedsubscription.canceled
xendit.recurring.cycle.succeededpayment.succeeded + invoice.generated
xendit.recurring.cycle.failedpayment.failed
xendit.recurring.cycle.created/retrying(raw only)
Xendit has no delete-customer API and no manual payment-capture API — deleteCustomer and capturePayment throw ProviderNotSupportedError. Use cancelPayment to expire a pending invoice instead.

provider_metadata