Invoice paid
Fires when an invoice is paid in full: when payment allocations reach its total, when Stripe collects it, or when it's marked paid in the dashboard. A credit or zero-total invoice (a total of zero or less) that Stripe isn't collecting is settled as it's posted, and this event follows its billing-invoice-posted. Nothing was paid on such an invoice, so no payment is recorded, no billing-payment-succeeded is sent and no receipt is emailed; the same goes when Stripe reports one it collects paid with nothing paid by card, such as one it settled from the customer's Stripe balance, which shows amountPaid equal to its total and amountRemaining 0, and fires this event once. Credits the order grants on payment become available at the same time. data.invoice is the invoice after the change, as Get an invoice returns it, with paymentStatus: paid and amountRemaining: 0. Verify X-Webhook-Signature before trusting the body.
Headers
- Type: stringX
- Webhook - Signature requiredt=<timestamp>,s=<signature>.tis when the delivery was signed, in Unix milliseconds; each attempt is signed afresh, so a retry has a newt.sis the Base64 (standard alphabet, padded) HMAC-SHA256 of the string<t>.<raw request body>, keyed with your signing secret: the wholewhsec_…string as UTF-8. To verify, recompute it over the raw body exactly as received and compare in constant time, then reject attoo far from now (5 minutes is a good limit) so an old delivery can't be replayed.scan end in=, so split each part on its first=only.
Body
Every delivery's body.
- Type:datarequiredProperties: 1
The event's payload, under the key the event names.
- enumeventconst:billing-invoice-paidrequired
A billing event you can receive.
billing-invoice-paid,billing-invoice-posted,billing-invoice-refunded,billing-checkout-created,billing-checkout-completed,billing-checkout-expired,billing-payment-succeeded,billing-payment-failed,billing-credits-depleted,billing-overage-incurredandbilling-credit-cap-reached; each is described in the Webhooks section.values- billing
-invoice -paid - billing
-invoice -posted - billing
-invoice -refunded - billing
-checkout -created - billing
-checkout -completed - billing
-checkout -expired - billing
-payment -succeeded - billing
-payment -failed - billing
-credits -depleted - billing
-overage -incurred - billing
-credit -cap -reached
- billing
- Type: stringidrequired
The delivery's ID (
whd_…), the same on every retry of it: keep the IDs you've handled and ignore a delivery whose ID you've seen. A test delivery has an ID of its own. - Type: booleanis
Test requiredtruefor a delivery sent with Send a test delivery, whosedatais placeholder;falseotherwise. - Type: stringFormat: date-timetimestamprequired
When the event happened, and the delivery was first queued; the same on every retry.
Responses
- 200
Return any 2xx to acknowledge. Any other status, a redirect (redirects aren't followed), or no answer within 5 seconds is a failed attempt, recorded in the webhook's
lastStatus. A failed delivery is retried 1 minute, 5 minutes, 30 minutes, 2 hours and then 12 hours after each failed attempt in turn (retries are sent by a sweep that runs every minute, so each can be up to a minute later), and dropped after the sixth failed attempt. A retry carries the sameidandtimestampand goes to the webhook's current URL; a delivery whose webhook has since been switched off is dropped. Because of retries, an event can arrive more than once or after a later one: useidto ignore repeats. The response body is ignored.
{
"id": "whd_Ap3Kx8Qm1Vr6Tz4N",
"event": "billing-invoice-paid",
"timestamp": "2026-11-10T09:15:22.114Z",
"isTest": false,
"data": {
"invoice": {
"id": "inv_3Rk8Wq1Zp6Ty0Xm2",
"displayNumber": "INV-1007",
"orderId": "ord_8Jt3Vw0Ym5Ln2Qp7",
"customerId": "cus_Q2x9vB7mK4pT1sLw",
"status": "posted",
"paymentStatus": "paid",
"source": "order_based",
"startDate": "2026-10-01T00:00:00.000Z",
"endDate": "2026-11-01T00:00:00.000Z",
"issueDate": "2026-11-01T00:00:00.000Z",
"postedDate": "2026-11-01T00:00:04.198Z",
"dueDate": "2026-11-15T00:00:04.198Z",
"currency": "USD",
"taxAmount": 888,
"taxRate": 0.08,
"taxStatus": "committed",
"invoiceTotalExcludingTax": 11100,
"invoiceTotal": 11988,
"amountDue": 11988,
"amountPaid": 11988,
"amountRemaining": 0,
"creditNotesTotal": 0,
"metadata": {
"crmId": "0015g00000XyZ"
},
"createdAt": "2026-11-01T00:00:00.000Z",
"updatedAt": "2026-11-10T09:15:22.108Z",
"paymentLink": "https://billing.getspondo.com/public/invoices/5c1e9a7b3d2f4e60_kV9xQ2mL7pR4tW8yZ1nC6bD3",
"disputeLink": null,
"publicUrlToken": "5c1e9a7b3d2f4e60_kV9xQ2mL7pR4tW8yZ1nC6bD3",
"taxExempt": false,
"billingContactId": "con_5Tg8Kd2Wq7Lm4Rx1",
"purchaseOrderReference": "PO-2026-1187"
}
}
}