---
name: stripe-payout-reconciliation
description: "Every Monday: each Stripe, Gumroad and Paddle payout matched to a Mercury deposit and an entry in QuickBooks or Xero, with the ones that went missing. Use when the user asks for this, or when it runs on a schedule."
---

# Payouts that never reached the bank: Stripe, Gumroad or Paddle, Mercury and your books

Every Monday: each Stripe, Gumroad and Paddle payout matched to a Mercury deposit and an entry in QuickBooks or Xero, with the ones that went missing.

A payout that says "paid" in Stripe or Gumroad is a promise, not money. Most of the time it lands two days later and the bookkeeper records it, but sometimes it goes to an old bank account, bounces, or arrives and never gets booked. Nobody notices until month-end close, or until the books and the bank disagree by an amount nobody can explain.

Every Monday the agent lists the last 30 days of payouts from each payment provider you use, finds the matching deposit in Mercury by amount, date and sender, and then the matching deposit or transfer in QuickBooks or Xero. What lines up is counted; what does not is listed with the reason it probably failed, and the agent offers to draft the support message.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- Read access to each payment provider you use: a Stripe restricted key with Read on Payouts, a Gumroad token with `view_payouts`, a Paddle API key with `report.read`.
- A Mercury Read Only token or the Mercury MCP server with the `read` scope, and read access to QuickBooks or Xero bank transactions and transfers.
- The names your bank shows for each provider's deposits, if they are not simply STRIPE, GUMROAD or PADDLE.

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **List Stripe payouts** (Stripe): `GET /v1/payouts?arrival_date[gte]=<30 days ago>&limit=100`, keeping `id`, `amount` (in cents), `currency`, `arrival_date`, `status` (`paid`, `in_transit`, `pending`, `failed`, `canceled`) and `statement_descriptor`. A `failed` payout goes straight on the list with its `failure_code`.
2. **Add Gumroad and Paddle payouts, whichever you use** (Gumroad): Gumroad: `GET /v2/payouts?after=<30 days ago>&include_upcoming=false`, keeping `amount` (a decimal string), `currency`, `status`, `processed_at`, `payment_processor` and `bank_account_visual`; skip `paypal` payouts, which never touch the bank. Paddle has no payout list endpoint: `POST /reports` with `type: "payout_reconciliation"` and a `balance_movement_date` filter, download it from `GET /reports/{id}/download-url`, and sum `balance_movement_in_balance_currency` per `remittance_reference`, dated by `payout_created_at`.
3. **Read deposits from the bank** (Mercury): `GET /api/v1/transactions?start=<35 days ago>&end=<today>` across all accounts, dropping `failed`, `cancelled`, `reversed` and `blocked`, `internalTransfer` rows, and money out (check the sign on one deposit you know). Keep `amount`, `postedAt` (or `createdAt` while pending), `counterpartyName` and `bankDescription`. Read `GET /api/v1/accounts` for each account's last four digits.
4. **Match each payout to one deposit**: Match on amount to the cent and currency, with the deposit dated from the payout's expected date to 3 business days after it; when two candidates fit, prefer the one whose `counterpartyName` or `bankDescription` contains the provider name (`STRIPE`, `GUMROAD`, `PADDLE` or the names in settings). Each deposit matches once. A paid payout older than 3 business days with no deposit is "not in bank"; compare Gumroad's `bank_account_visual` with your Mercury account numbers. A provider deposit with no payout is "unknown deposit".
5. **Check each deposit is in the books** (QuickBooks): QuickBooks: `SELECT * FROM Deposit WHERE TxnDate >= '<date>'` and `SELECT * FROM Transfer WHERE TxnDate >= '<date>'`, matching `TotalAmt` or `Amount` into the bank account within 3 business days of the Mercury date. Xero, if that is your ledger: `GET /BankTransactions?where=Type=="RECEIVE"` and `GET /BankTransfers`, matching `Total` or `Amount` and `Date`. A deposit with no entry is "not in books".
6. **Post the gaps as an ask**: If everything matched, post a short update instead. Otherwise list each gap with provider, payout date, amount and reason, and ask whether to draft a message to the provider's support (payout ID, date, amount, account last four) and a note for the bookkeeper. The agent never moves money or creates entries.

## Route B: the browser

### What you need

- Signed in to Stripe, Gumroad or Paddle (Admin or Finance role for Paddle payouts), Mercury, and QuickBooks or Xero, in this browser. Mercury may ask for a 2FA code; the person enters it.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://dashboard.stripe.com/payouts. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **List payouts in each provider**: In Stripe's Payouts page, note each payout of the last 30 days with its arrival date, amount and status. In Gumroad, open Payouts and note date, amount and destination account. In Paddle, open the Payouts page (Admin or Finance role) and note each payout's date, amount and remittance reference.
2. **Find each deposit in Mercury**: Open `https://app.mercury.com/transactions`, set the date range to the last 35 days and search `stripe`, `gumroad` and `paddle` in turn. Match each payout to a deposit of the same amount dated up to 3 business days later; note the account it landed in.
3. **Check the books**: In QuickBooks, open the bank register for that Mercury account (Chart of accounts > View register) and look for a deposit or transfer of the same amount near that date. In Xero, open the bank account under Accounting > Bank accounts and check Account Transactions.
4. **Sort out what is missing**: A paid payout older than 3 business days with no bank deposit is not in the bank: compare the destination account digits with your Mercury accounts. A deposit with no ledger entry is not in the books. Report both and ask before drafting any message.

Note: Paddle's Payouts page is only visible to Admin and Finance roles. Mercury search matches description and counterparty names, so a provider that pays under a different legal name needs that name typed instead. Thirty days of payouts is a few minutes of clicking; for daily Stripe payouts over several months the API route is far quicker.

## The report

- **Payouts in the last 30 days** per provider, and how many matched in the bank and in the books.
- **Not in bank**: paid payouts with no deposit after 3 business days, with the destination account.
- **Not in books**: deposits that arrived but were never recorded.
- **Unknown deposits** from a provider with no payout behind them.
- The ask: which support messages and bookkeeper notes to draft.

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "stripe-payout-reconciliation/<date of this run, e.g. 2026-10-16>",
  "item_key": "stripe-payout-reconciliation",
  "project": "Acme",
  "source": "Payouts that never reached the bank: Stripe, Gumroad or Paddle, Mercury and your books skill",
  "kind": "action",
  "title": "Gumroad's $612 payout of October 14 never reached the bank",
  "summary": "**6 payouts** in the last 30 days: 3 matched in Mercury and QuickBooks, 1 is still in transit. The **Gumroad payout of October 14 ($612)** is not in the bank, and **1 Stripe payout ($3,982.10)** has no matching deposit in QuickBooks.",
  "action": {
    "request": "Shall I draft a message to Gumroad support and a note for your bookkeeper?",
    "options": [
      "Draft both",
      "Only the Gumroad message",
      "Only the bookkeeper note",
      "I will handle it"
    ]
  },
  "widget": [
    {
      "type": "Table",
      "props": {
        "columns": [
          "Provider",
          "Payout date",
          "Amount",
          "In Mercury",
          "In QuickBooks"
        ],
        "align": [
          "left",
          "left",
          "right",
          "left",
          "left"
        ],
        "rows": [
          [
            "Stripe",
            "Oct 6",
            "$4,210.55",
            "Oct 7",
            "Yes"
          ],
          [
            "Stripe",
            "Oct 13",
            "$3,982.10",
            "Oct 14",
            "Missing"
          ],
          [
            "Gumroad",
            "Oct 14",
            "$612.00",
            "Missing",
            "Missing"
          ],
          [
            "Paddle",
            "Oct 15",
            "$2,318.40",
            "Oct 16",
            "Yes"
          ],
          [
            "Stripe",
            "Oct 20",
            "$4,455.80",
            "Oct 21",
            "Yes"
          ],
          [
            "Stripe",
            "Oct 27",
            "$4,104.25",
            "In transit",
            "Not due"
          ]
        ]
      }
    },
    {
      "type": "Callout",
      "props": {
        "text": "Gumroad paid to an account ending 4821; your Mercury checking ends in 7730. Check the payout account under Settings > Payments in Gumroad.",
        "tone": "bad"
      }
    }
  ]
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

## Run it on a schedule

Suggested: Mondays at 9:00 (`0 9 * * 1`). From cron, with the agent signed in on that machine:

```bash
0 9 * * 1 claude -p "Run the stripe-payout-reconciliation skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/stripe-payout-reconciliation#schedule

Source: https://briefkin.dev/skills/stripe-payout-reconciliation
