Marking payments as recovered
When a customer completes payment outside Declined's hosted flow — direct bank transfer, in-app purchase, manual reconciliation, or your own checkout — you must notify Declined so recovery sequences stop, invoices are marked paid, and analytics stay accurate.
What happens on recovery
- Active recovery attempt status changes to
recovered - Linked invoice status changes to
paid - A payment event is recorded for analytics
- Outbound webhooks fire (e.g.
recovery.completed) - Sequence enrollment stats are updated
Option 1 — Event API (recommended)
Send a payment_recovered event with your customer and invoice identifiers. Declined resolves the active recovery attempt automatically.
typescript
await client.events.markPaymentRecovered({
event_id: "evt_" + Date.now(),
customer_id: "cus_123",
invoice_id: "inv_456",
amount: 24900,
currency: "usd",
provider: "stripe",
});Equivalent raw request:
curl
curl -X POST https://dev.declined.io/api/v1/events \
-H "Authorization: Bearer decl_live_sk_..." \
-H "Content-Type: application/json" \
-d '{
"event_id": "evt_rec_001",
"type": "payment_recovered",
"customer_id": "cus_123",
"invoice_id": "inv_456"
}'Option 2 — Recovery attempt API
If you have a Declined recovery attempt ID (from GET /v1/recoveries, dashboard, or an outbound webhook), mark it directly:
typescript
await client.recoveries.markRecovered("ra_abc123");Equivalent raw request:
curl
curl -X POST https://dev.declined.io/api/v1/recoveries/ra_abc123/mark-recovered \
-H "Authorization: Bearer decl_live_sk_..."Response
json
{
"recovery_attempt_id": "ra_abc123",
"status": "recovered"
}If the attempt was already recovered, the API returns already_recovered: true without side effects.
When to use each approach
- Event API — You know the customer/invoice IDs from your billing system (Stripe, Paddle, etc.) but not the Declined recovery attempt ID.
- Recovery attempt API — You received a recovery attempt ID from Declined webhooks or listed recoveries via the API.
SDK examples
Language-specific snippets are in each SDK guide under SDKs.