# Chase failed direct debits

You have access to your direct-debit provider, your accounting tool,
a mailbox, a team chat and a table you can read and write. Run this
for **[the failed direct debits of the window you are chasing, e.g.
this month]**.

## 0. Set up (skip if you're already connected)

If you don't already have live tool access for this, connect it
first. This prompt is only as real as the tools behind it:

1. Get a Tulina account: book a demo at https://tulina.ai/book.
2. Add Tulina's MCP server to your assistant: https://mcp.tulina.ai/mcp
3. In Tulina, connect your own API keys for the tools this
   prompt uses: your direct-debit provider, your accounting tool,
   your mailbox and your team chat.

Once connected, your assistant has real tool access and the rest of
this prompt runs as written.

## 0b. Already on Tulina? Three things around the run

An account and the MCP server are not the whole setup. Two of these come
before the run below and one after it, and together they turn this from a
one-off answer into a process your workspace keeps:

1. **Activate this process's connectors first.** Call
   `oto_connector(op="list")`, match it against the tools named in step 3
   above, and `oto_connector(op="select", name="...")` every one that
   isn't active yet. Selecting a connector does not mount its tools in the
   conversation you're already in — reach them through `oto_call` for this
   run, or open a fresh conversation once they're all on.
2. **Attach the work to an existing project.** `oto_project(op="list")`
   shows your active org's projects: pick the one this work belongs to
   rather than opening another, and keep its id. The project is where this
   process, the tables it writes to and the connectors it uses hang
   together.
3. **When the run is done, save it as a process — with its graph.** Write
   the body with `oto_procedure(op="set", ...)`, then attach it with
   `oto_project(op="link", project_id=..., target_type="procedure",
   target_ref="<your slug>")`. The body has to carry a drawing: read
   `oto_guide(op="read", slug="procedure-flowchart")` and follow it
   exactly — ONE untagged fenced block in that grammar, opening with the
   trigger and a quoted example of what you'd type to start a run. Tulina
   parses that drawing back into the graph it renders as the process's
   default view, which is what makes it come out in the same style as
   every other process in the app; a drawing the grammar can't read falls
   back to raw characters instead. Saving a process needs org-admin
   rights — without them, hand the finished body to someone who has them.

## 1. List the failed debits not yet closed

- Pull the failed payments in one call, with the page size set
  explicitly to its maximum (500). Each row already carries the
  customer's name and email, the amount, the charge date, the failure
  time, the cause and reason code, whether a retry is scheduled, and
  the mandate's state. The payment → mandate → customer chain is
  resolved for you: there is no per-row lookup to do.
- **The date filter is on when the payment was created, not when it
  failed.** A payment created before your window that failed inside
  it will not come back. Set the filter one full billing cycle
  earlier than the window you care about, then keep only the rows
  whose failure time falls inside it. If a page still comes back
  full, narrow the window instead of assuming you have everything.
- Read **[your reminder log]** (step 6) once, here, before anything
  else runs, and index it by payment id. **A payment whose logged
  outcome is final (settled, escalated, needs a person, already
  chased, drafted) is dropped now**, before step 3 can post anything
  about it. Runs overlap by a full cycle on purpose, so without this
  the same dispute would be posted to your billing channel on every
  run. Only *retry pending* rows are evaluated again.
- **A retry is scheduled → draft nothing.** While the provider says
  it will retry, it re-presents the payment on its own, and a
  reminder now asks the customer to fix something that may fix
  itself within days. Log it as *retry pending* and move on.
- **Carry over what an earlier run left pending.** For every *retry
  pending* row in the log, re-read the payment by its id: its
  creation date may now sit outside the new window, so this is the
  only way a retry that failed too gets picked up. Confirmed or paid
  out → *settled*. Failed again → read its latest failure reason, and
  whether yet another retry is scheduled.

## 2. Confirm the invoice is still owed

Resolve the invoice through a fallback chain, strongest key first:

- **Find by external reference**, with the payment id as the
  reference. The search is filtered server-side, so an old or
  archived document still turns up, and a miss comes back as "not
  found" rather than an empty list. This key only exists if your
  billing flow writes the payment id onto its documents: test it on
  one known payment before trusting a miss.
- **A hit is not always the invoice.** The document carrying the
  payment id is often a credit note raised against the failed
  payment. Credit notes carry negative amounts: one means the debt
  was already cancelled, and the payment ends as *settled
  (credited)*. Only a sales invoice with a positive amount goes on.
- **On a miss:** resolve the payment to its party, whose metadata may
  carry your own customer reference (depending on how the mandate was
  created, it may not). Find the customer in the accounting tool by
  that reference, or list customers to resolve the id from the name.
- Then list invoices, **always bounded with a page limit**: without
  one the whole invoice history comes back and can overflow the
  response. Start small and widen. Match sales invoices only, on the
  customer, the amount and a due date close to the charge date.
  **Two open invoices match → pick neither**: log the payment as
  *needs a person* rather than chase the wrong document.

Two checks then end the payment as *settled*:

- The matched invoice already shows as paid: a bank transfer came in
  after the debit failed. This is the check to trust.
- A confirmed or paid-out payment of the same amount on the same
  mandate since the failed charge date. **On a subscription, that row
  is usually just the next cycle**, and reading it as a re-collection
  drops a real debt without a warning. Count it only when the payment
  shows no subscription or instalment schedule and, when your billing
  flow writes one, its reference points at the same invoice.
  Otherwise rely on the invoice's paid status alone.

## 3. Sort each failure by cause, post the disputes

Map the cause and reason code into groups once, then treat each group
the same way every run:

- **Low funds, no retry left.** The mandate still works. A
  refer-to-payer refusal belongs here too: the bank declined and sent
  the payer to ask why, which is usually low funds, not a dispute. The
  reminder states the amount and the invoice and gives one next step:
  the date you will collect again, or your transfer details.
- **Dead mandate**: cancelled, expired, or the bank account closed.
  Collecting again fails the same way, so the ask is a new mandate
  through **[your mandate setup link]**, never "we will try again".
- **Dispute**: only a payer disputing the authorization, or a
  chargeback-type cause. A chasing email escalates it. Post the
  customer, amount, invoice reference and cause to **[your billing
  channel]** and stop: a person handles it. Logged as *escalated*.
- **Anything unmapped**: invalid bank details, a transferred account,
  a cause you have never seen. Guessing a group sends the wrong ask,
  so it becomes *needs a person* and is listed in the report.
- **Repeat failures.** List the mandate's failed payments since the
  start of **[your lookback window]**, page size 500, and count them.
  Count payments, not events: the events feed has no date filter. At
  **[your repeat-failure threshold]** the payment gets the same channel
  post as a dispute instead of a polite email, logged as *escalated*.
- Right after posting, write the *escalated* rows to the log in one
  batch keyed on the payment id, instead of waiting for step 6. A run
  that stops between the post and the end-of-run log would otherwise
  post the same payment again next time.

Order what remains by amount, then by days since the failure, so the
reviewer reads the largest, oldest debts first.

## 4. Skip what was already chased

One incident is one payment id, and it gets one reminder at most. The
log already dropped what it closed; what is left are the duplicates
it cannot see:

- Search the mailbox for `in:drafts subject:"[invoice reference]"`:
  a draft from an earlier run that stopped before logging it. Search
  rather than list drafts, since a list returns only the most recent
  page.
- Search for `in:sent subject:"[invoice reference]"`: a reminder
  someone wrote by hand, outside this process.

Either match ends the payment as *already chased*. Both checks work
only because the subject line in step 5 always carries the invoice
reference. Don't reword it run to run.

## 5. Draft one reminder per failure

- Save each reminder as a **draft** in the mailbox. Nothing in this
  process sends: report every one as *draft*, never *sent*.
- **To**: the invoice recipient on the accounting side when it
  differs from the payer's email on the debit. Whoever receives
  invoices is usually the one who can fix a payment. **Subject**: a
  fixed pattern carrying the invoice reference, e.g. *Payment failed —
  invoice [invoice reference]*. **Body**: amount, invoice reference,
  charge date, and the one next step from step 3. Firm and courteous;
  no late-payment penalty unless your terms state one. Let the
  mailbox append its own signature rather than writing a sign-off.
- A new draft can be missing from a mailbox tab that is already open
  for a while. Tell the reviewer to reload or search the drafts
  folder rather than assume it failed.

## 6. Log every payment against its id

- One batch write at the end of the run, keyed on the payment id, so
  a re-run merges onto the same rows instead of appending duplicates.
  One row per payment this run evaluated, **including the ones that
  exited early**: payment id, invoice reference, cause group, outcome
  (*retry pending*, *settled*, *settled (credited)*, *escalated*,
  *needs a person*, *already chased*, *drafted*), the draft id when
  there is one, and the run date read at run time rather than typed.
- Payments dropped in step 1 because their outcome was already final
  stay out of the batch, so a *drafted* row is never overwritten by a
  weaker outcome on a later run.

## 7. Read and send each draft

A person opens the drafts, largest first, and sends, edits or deletes
each one. Nothing leaves the mailbox until they do.

## Rules

- The accounting side is read-only here: never collect again, create
  a credit note, or finalize or send an invoice.
- Never send an email: every reminder is a draft a person sends.
- Never email a customer about a disputed debit.

## Output

A short report: failures found in the window, then how many were
skipped as already handled, retry pending, settled (paid, credited or
collected again), escalated to your billing channel (disputes, repeat
failures), already chased, or left for a person (ambiguous invoice
match, unmapped cause), and how many drafts wait in the mailbox,
listed largest first with customer, amount and cause.
