What you’ll build

A recovery step: a charge failed last night with insufficient_funds. Retry it now — on the same card, or on a new card the customer just added.

Which tool?

There are two ways to retry, and the right one depends on whether you’re keeping the same card:

Use…WhenWhat it does
retry_orderSame card on file — including a failed subscription renewal.Re-attempts the charge on the same order. For a subscription cycle it reconciles the cycle, so the daily billing cron won’t charge again.
retry_failed_chargeYou need to charge a different card.Reconstructs the order from the failed transaction and creates a new order on the chosen card. Does not reconcile the original subscription cycle.

For a failed subscription renewal you want to move to a new card, update the subscription’s payment method first (update_subscription), then call retry_order — that keeps future cycles on the new card and reconciles the cycle.

Same card — retry_order

{
  "name": "retry_order",
  "arguments": {
    "order_id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
    "idempotency_key": "retry-2026-04-21-6ba7b811"
  }
}

Only orders in failed or refund_failed status are eligible. The response is the updated order — check status (a re-decline leaves it failed with an incremented attempt_count). For a subscription cycle, success reconciles the cycle automatically.

Different card — retry_failed_charge

Use retry_failed_charge (a composite tool) to charge a different card.

{
  "name": "retry_failed_charge",
  "arguments": {
    "transaction_id": "6ba7b813-9dad-11d1-80b4-00c04fd430c8",
    "payment_method_id": "6ba7b815-9dad-11d1-80b4-00c04fd430c8",
    "idempotency_key": "retry-2026-04-21-6ba7b813"
  }
}
ArgumentMeaning
transaction_idThe failed transaction to retry.
payment_method_idOptional. If omitted, retries against the same card; if present, charges the new card.
idempotency_keyPass a stable key per retry attempt so accidental re-runs do not double-charge.

When to retry against the same card

  • Decline reason was insufficient_funds and a few days have passed (paydays).
  • Decline reason was gateway_error (transient).

When to retry against a different card

  • Decline reason was expired_card and the customer added a new one.
  • Decline reason was card_declined repeatedly — the issuer is consistently saying no.

What you get back

{
  "transaction_id": "9c1d2e3f-4a5b-4c6d-8e7f-0123456789ab",
  "status": "succeeded",
  "amount": 2999,
  "currency": "usd"
}

Or:

{
  "error": {
    "type": "processing_error",
    "code": "card_declined",
    "message": "Card was declined.",
    "request_id": "req_a1b2c3d4e5f67890abcdef0123456789"
  }
}

Stop retrying

Most issuers will eventually mark a card as “do not retry” if you keep hammering it. If you drive your own manual retry cadence on top of EPD’s daily cron, keep it finite — e.g. one manual retry after a likely-cleared decline, then stop and ask for a new card — and notify the customer at each step. (EPD’s cron itself just re-attempts the failed cycle once per daily run; it has no day-1/3/7 curve, so layering your own loop on top can over-charge attempts if you’re not careful.)

When a subscription renewal fails, EPD’s billing cron re-attempts the failed cycle on its next daily run (10:00 UTC) until it succeeds or the subscription ends — there is no accelerated backoff curve. Use retry_order to re-attempt a failed cycle on demand before then; it reconciles the cycle so the cron won’t also charge it. Reach for retry_failed_charge when you need to move the charge to a different card.