Events
Send billing events to Declined via POST /v1/events. Events drive dunning sequences, recovery attempts, and analytics. Each event requires a unique event_id for idempotency across retries and worker redelivery.
Supported event types
payment_failedpayment_recoveredinvoice_paidinvoice_openedpayment_method_updatedsubscription_canceledsubscription_past_duesubscription_renewed
Payment failed
Start or continue a recovery sequence when a charge fails:
json
{
"event_id": "evt_unique_001",
"type": "payment_failed",
"customer_id": "cus_123",
"invoice_id": "inv_456",
"amount": 24900,
"currency": "usd",
"provider": "stripe",
"metadata": { "attempt_count": 2 }
}Payment recovered
Notify Declined when a customer pays outside hosted recovery or via your own checkout. This stops active sequences and marks the invoice paid. See Recoveries for resolution rules when multiple attempts exist.
json
{
"event_id": "evt_unique_002",
"type": "payment_recovered",
"customer_id": "cus_123",
"invoice_id": "inv_456",
"amount": 24900,
"currency": "usd",
"provider": "stripe"
}Successful response
New events return HTTP 201:
json
{
"status": "accepted",
"event_id": "evt_unique_001",
"inbound_event_id": "ie_abc123",
"payment_event_id": "pe_def456",
"recovery_attempt_id": "ra_ghi789"
}recovery_attempt_id is present when the event creates or updates an active recovery. Duplicate event_id values return 200 with status: "duplicate" and no new side effects.
cURL example
curl
curl -X POST https://app.declined.io/api/v1/events \
-H "Authorization: Bearer decl_live_sk_..." \
-H "Content-Type: application/json" \
-d '{"event_id":"evt_1","type":"payment_failed","customer_id":"cus_1","invoice_id":"inv_1","amount":24900,"currency":"usd","provider":"stripe"}'