Submit invoices via the Recovery API
Submit a failed invoice to Recurly Recover for automated retry collection, read the response, and stop retries when a payment is collected or abandoned.
Prerequisites
- An active Recurly Recover account with an API key generated — see Getting started.
- At least one retry window (dunning campaign) configured.
- A reusable gateway token for each customer's payment method from Stripe or Braintree.
Submit a failed invoice
Send a POST request to /invoices/recovery. A successful call creates a Recurly Account, a past-due charge invoice, and an initial failed transaction — and immediately begins the retry schedule.
Recover authenticates with HTTP Basic Auth: pass your API key as the username with an empty password.
curl -u YOUR_RECOVER_API_KEY: \
-X POST https://v3.recurly.com/invoices/recovery \
-H "Content-Type: application/json" \
--data @recovery-request.jsonRequest body
{
"currency": "str",
"due_at": "2019-08-24T14:15:22Z",
"po_number": "string",
"external_recovery_eligible": true,
"account": {
"address": {
"phone": "string",
"street1": "string",
"street2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"billing_infos": [
{
"first_name": "string",
"last_name": "string",
"company": "string",
"address": {
"phone": "string",
"street1": "string",
"street2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"ip_address": "string",
"gateway_code": "string",
"primary_payment_method": true,
"backup_payment_method": true,
"payment_gateway_references": [
{
"token": "string"
}
],
"network_transaction_id": "string",
"transactions": [
{
"gateway_error_code": "string",
"merchant_advice_code": "st",
"attempted_collection_date": "2019-08-24T14:15:22Z"
}
]
}
],
"code": "string",
"email": "[email protected]",
"custom_fields": [
{
"name": "string",
"value": "string"
}
],
"dunning_campaign_id": "string"
},
"line_items": [
{
"tax": 0,
"custom_fields": [
{
"name": "string",
"value": "string"
}
],
"harmonized_system_code": "string",
"product_code": "string",
"quantity": 1,
"description": "string",
"unit_amount": 0
}
]
}If you are using Stripe, the Customer ID and Payment Method IDs are two-part tokens, and you will provide the payment_gateway_references array as follows:
"payment_gateway_references": [
{
"token": "stripe-customer-id", // ex: cus_xxxxxxxx
"reference_type":"stripe_customer"
},
{
"token": "stripe-pm-id", // ex: pm_xxxxxxxx
"reference_type":"stripe_payment_method"
}
],If you are providing multiple payment methods in a single account for this Recover invoice, your payload will look like below. The example shows 5 payment methods associated with the invoice, 3 of which were used on a previous attempt.
The example shows formats for tokens mixing between Stripe formatting and non-Stripe formatting.
{
"currency": "USD",
"po_number": "NNNN",
"due_at": "YYYY-MM-DDTHH:MM:SS.MSZ", // Date and Time
"account": {
"code": "account-code", // Account code
"dunning_campaign_id": "{{dunning_campaign_id}}", // Dunning Campaign ID
"billing_infos": [
// each billing info with gateway code, and the transaction attempt, error code, attempted date, and MAC code
{
"gateway_code": "{{gateway_code}}", // Gateway code -- must have access to the gateway token provided
"primary_payment_method": true, // Wallet Primary indicator
"backup_payment_method": false,
"payment_gateway_references": [ // Stripe Token Format
{
"token": "pm_XXXXXXXXXXX",
"reference_type": "stripe_payment_method"
},
{
"token": "cus_XXXXXXXXXXX",
"reference_type": "stripe_customer"
}
],
"transactions": [
{
"gateway_error_code": "gateway-responsed-code-value", // The actual gateway response code returned in your integration
"attempted_collection_date": "YYYY-MM-DDTHH:MM:SS.MSZ",
"merchant_advice_code": "NN"
}
]
},
{
"gateway_code": "{{gateway_code}}", // Gateway Code
"primary_payment_method": false,
"backup_payment_method": true, // Wallet Backup Indicator
"payment_gateway_references": [ // Non-Stripe Token Example
{
"token": "XXXXXXXXXXX"
}
],
"network_transaction_id": "string", // Example token that requires NTID
"transactions": [
{
"gateway_error_code": "gateway-responsed-code-value", // The actual gateway response code returned in your integration
"attempted_collection_date": "YYYY-MM-DDTHH:MM:SS.MSZ",
"merchant_advice_code": "NN"
}
]
},
{
"gateway_code": "{{gateway_code}}",
"primary_payment_method": false,
"backup_payment_method": false,
"payment_gateway_references": [
{
"token": "XXXXXXXXXXX" // Example token that does not required separate NTID
}
],
"transactions": [
{
"gateway_error_code": "gateway-responsed-code-value",
"attempted_collection_date": "YYYY-MM-DDTHH:MM:SS.MSZ",
"merchant_advice_code": "NN"
}
]
},
{
"gateway_code": "{{gateway_code}}",
"primary_payment_method": false,
"backup_payment_method": false,
"payment_gateway_references": [
{
"token": "pm_XXXXXXXXXXX",
"reference_type": "stripe_payment_method"
},
{
"token": "cus_XXXXXXXXXXX",
"reference_type": "stripe_customer"
}
]
},
{
"gateway_code": "{{gateway_code}}",
"primary_payment_method": false,
"backup_payment_method": false,
"payment_gateway_references": [
{
"token": "XXXXXXXXXXX"
}
]
}
],
"email": "[email protected]"
},
"line_items": [
{
"description": "Description of Invoice", // Overwritten when using Vindicia
"unit_amount": 9.99
}
],
"external_recovery_eligible": true,
"transaction_descriptor_suffix": "Descriptor Suffix" // New Descriptor Field (Suffix)
}Fields that drive retry behavior
The full schema is documented in the API reference. These are the fields that determine how Recover collects:
| Field | What it does |
account.code | Your unique identifier for the account. Reusing a code that already exists returns an error — each call creates one account with one invoice. |
account.dunning_campaign_id | The retry window Recover follows for this invoice. Assign a different campaign per request to test strategies across segments. |
gateway_code | Routes the transaction to the correct gateway connection. |
payment_gateway_references | The reusable gateway token and its reference_type. |
transactions | Prior failed attempt history — gateway_error_code, merchant_advice_code, and attempted_collection_date — used to calculate the first retry date. |
Handle the response
A 201 response confirms that Recurly created the account and started the retry process. Save the id of the returned charge_invoice — you'll need it to stop retries later.
{
"object": "string",
"charge_invoice": {
"id": "string",
"uuid": "string",
"object": "string",
"type": "charge",
"origin": "carryforward_credit",
"state": "open",
"account": {
"id": "string",
"object": "string",
"code": "string",
"email": "[email protected]",
"first_name": "string",
"last_name": "string",
"company": "string",
"parent_account_id": "string",
"bill_to": "parent",
"dunning_campaign_id": "string"
},
"billing_info_id": "string",
"subscription_ids": ["string"],
"previous_invoice_id": "string",
"number": "string",
"collection_method": "automatic",
"po_number": "string",
"net_terms": 0,
"net_terms_type": "net",
"currency": "str",
"discount": 0,
"subtotal": 0,
"subtotal_after_discount": 0,
"tax": 0,
"total": 0,
"refundable_amount": 0,
"paid": 0,
"balance": 0,
"dunning_campaign_id": "string",
"due_at": "2019-08-24T14:15:22Z",
"closed_at": "2019-08-24T14:15:22Z",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
}Stop retries
While an invoice is in a past_due state, you can cancel all future retry attempts at any time. Use the invoice id returned in the original response. Once marked, Recover makes no further attempts on that invoice.
Mark as paid
Use when the payment was collected outside of Recurly.
curl -u YOUR_RECOVER_API_KEY: \
-X PUT https://v3.recurly.com/invoices/{invoice_id}/mark_successfulMark as failed
Use when you want to abandon collection.
curl -u YOUR_RECOVER_API_KEY: \
-X PUT https://v3.recurly.com/invoices/{invoice_id}/mark_failedPayment method wallet
When the Wallet feature is enabled, you can designate payment methods as primary or backup in the same request. Set primary_payment_method or backup_payment_method to true on each entry in billing_infos. You can submit multiple payment methods, but only one can be marked as primary.
Supported gateways
Recover currently supports the following gateways with reusable gateway tokens:
| Gateway | Token support |
| Stripe | Reusable gateway tokens) |
| Braintree | Reusable gateway tokens |
Error handling
Every call creates exactly one account with one invoice. Submitting a request with an account.code that already exists returns an error rather than creating a duplicate — generate a unique code per invoice, or mark the existing invoice as paid or failed before resubmitting.
What's next
- Recovery API reference — the complete endpoint and field schema
- Webhooks — track retry progress and confirm the final outcome of each invoice
- Getting started — connect a gateway, set up webhooks, and generate your API key
Updated 1 day ago