All jobs

Report Failed Payments in Stripe

Yes. An agent lists the open Stripe invoices with failed payment attempts and writes a worklist ranked by amount, with each decline code and next retry date.

What the agent does

There is no repository in this job. The agent reads your account through the Stripe connection, Stripe's remote MCP server, which you connect once and the request names in connections. It looks up invoices whose status is open with attempted set and at least one failed attempt, and keeps an invoice whose due date has passed even when Stripe has stopped retrying it. Paid, void and draft invoices are left out, and so are invoices marked uncollectible, which the report counts separately as already written off.

For each invoice it collects the fields that decide whether money can still be recovered: the customer, amount_remaining and currency, attempt_count, and next_payment_attempt, which is empty when no more automatic retries are scheduled. The decline itself lives on the payment, not the invoice, so the agent reads the invoice's latest payment attempt and its error: the decline_code from the card issuer (insufficient_funds, expired_card, do_not_honor and the rest) and the broader failure code when there is no decline code. It also notes the subscription the invoice belongs to, if any, because a failed renewal is a different conversation from a failed one-off invoice.

Then it sorts the worklist. Rows go by amount, largest first, and each row says what kind of action fits its decline: a card that expired needs the customer to update it, insufficient_funds often clears on a later retry, and a hard decline such as stolen_card or fraudulent should not be retried at all. The agent groups totals by decline code and by currency, and flags invoices that have no retry left, since those only come back if someone acts.

It writes failed-payments.md from those lookups only. Nothing is retried, voided, finalized or marked paid; the prompt says read only and the transcript shows every call the agent made, so you can see that it did no writes. Where Stripe returned no decline code for a payment, the row says so instead of filling one in.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Use the Stripe connection to list invoices that are open or past due with at least one failed payment attempt. For each, read the customer, amount_remaining and currency, attempt_count, next_payment_attempt, the subscription if any, and the decline_code (or failure code when there is none) from its latest payment attempt. Write failed-payments.md with one row per invoice, sorted by amount, with a column saying whether automatic retries remain, plus totals by decline code and by currency, and a separate count of invoices already marked uncollectible. Read only; do not retry, void, finalize or mark anything paid.",
  "connections": [
    "stripe"
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

What comes back is failed-payments.md, an artifact on the session that downloads from a link valid for an hour. The top of the file gives the totals: how many invoices are recoverable, how much is outstanding per currency, and how much has no automatic retry left. The main table has one row per invoice with the customer, amount, decline code, attempts so far, next retry date or none, and the subscription it renews. Under it come the totals by decline code, which show at a glance whether the problem is expired cards, insufficient funds or something your checkout could prevent.

The session's transcript records each Stripe lookup with what came back, so anyone who questions a row can open the call behind it. The agent's closing message, which reads back as the session's result, summarises the totals in a few lines for a channel post.

Before anyone acts on the list, check it against your dunning settings: the retry schedule and what happens to a subscription when retries run out decide which rows can still recover without a person. Customer contact should go through your usual billing emails or the customer portal, not ad hoc messages based on a decline code alone.

Run it on every weekday morning

A recovery list is most useful while the retries are still running, so schedule this request on weekday mornings from your server, with an Idempotency-Key built from the date so a retried call does not start a second run. Each run reads the account fresh, so an invoice that got paid overnight drops off the list.

With a webhook URL on the API key, Rush POSTs run.completed when the run finishes, including the result text up to 16 KiB and the session_url. Your server posts the summary to the billing channel and links the full failed-payments.md from the session's artifacts.

The use case this job follows, with its automation and trigger: Produce a report or file, no repo.

Why run it on Rush?

Doing this by hand means filtering invoices in the dashboard, opening each payment to find its decline code and copying both into a spreadsheet, every day. A script would need a secret key sitting on someone's laptop. On Rush the agent reads Stripe through a connection you approved once, inside its own sandbox, and the run gets only the connections it names.

The worklist arrives with its evidence: every row traces to a lookup in the run's record, and the record shows no writes were made. Finance can act on it without re-checking each invoice, and several accounts or currencies can run at once, one run each, up to the key's concurrent run limit.

Frequently asked questions

Will it retry payments or email customers?

No. The prompt makes the run read only, and the report is the only output. Recovering the money stays with your dunning settings, your billing emails and whoever works the list. The transcript lets you confirm the agent made lookups only.

Where does the decline code come from?

From the latest failed payment attempt on each invoice, where the card issuer's decline_code is recorded. When the issuer gave none, the report shows the broader failure code and says that no decline code was returned.

Does it handle more than one currency?

Yes. Amounts stay in each invoice's own currency, the table shows the currency per row, and totals are given per currency rather than converted, so no exchange rate is guessed.

How do I connect Stripe for this run?

Connect Stripe's MCP server once with POST /me/connections, signing in through the authorize_url it returns while you are signed in to the console, or with a restricted read-only key as a bearer token. Then name the connection in the request's connections, stripe here.