# Worked example: Brightline's payment run as a business AI Worker (/claude-and-chatgpt-2/architecture/worked-example-brightlines-payment-run-as-a-business-ai-worker)

---
type: Document
title: "Worked example: Brightline's payment run as a business AI Worker"
description: "Brightline's Friday payment run, designed as a weekly business AI Worker. A temporary sandbox works with a database and a payment connector that enforce approval and pay each invoice once."
status: stable
order: 0.47
ksor:
  owner: team:panaversity
  audience: [ public ]
  approval:
    by: process:panaversity
    at: 2026-11-09T20:42:36Z
chapter: "F00A"
part: Front
expert_status: required
concepts: [ "Worked example" ]
last_verified: 2026-11-09
sources:
  - id: cloud-scheduled-tasks
    title: "Automate work with scheduled tasks (Anthropic, verified 2026-11-09)"
    resource: https://code.claude.com/docs/en/routines
  - id: cloud-environments
    title: "Configure cloud environments (Anthropic, verified 2026-11-09)"
    resource: https://code.claude.com/docs/en/cloud-environments
generated:
  at: 2026-11-09T20:42:36Z
  by: process:panaversity
trust_tier: unverified
build_id: sha256:46fd53c5d7ab1c14f6347908d45c9fdaecda4d914439923ee878bdcecd57803e
dirty: true
ksor_version: 0.0.60
---

### The job, one step further

This example extends Brightline Wholesale Supply's Friday payment run from [One job, start to finish](../new-way-of-working/one-job.md). There, the AI Worker only suggests and the payment officer pays. This design keeps that rule for a weekly job. It is an illustration built from Claude features, with the nearest OpenAI equivalent. It is not a vendor reference architecture.

The weekly **reconciliation run** checks the invoices and proposes payments. It never makes them. It has no access to the payment tool. A separate **payment caller** makes each payment. That is the payment officer, or a payment worker whose narrow scope only reads approvals and calls the payment tool. The safety comes from a database and a payment connector that you control. It does not come from the sandbox or from prompts.

| Role in the design | Claude | Nearest OpenAI equivalent |
| --- | --- | --- |
| Trigger | A weekly cloud scheduled task | A ChatGPT scheduled task (Work) |
| Invoice policy and matching rules | A skill (a `SKILL.md` file) that the run loads each time | A skill in Codex |
| Agent loop and model | The Claude Code harness with a Claude model | The Codex harness with an OpenAI model |
| Where the work runs | A fresh cloud sandbox for each run | A cloud sandbox backed by a VM, which Work may reuse across tasks |
| Authoritative state: invoice status, approvals, payment intents | A database behind your MCP connector, with transactions and unique constraints | The same, behind an MCP server |
| Review interface | A Claude Sheets artifact that displays the database rows. It is not the system of record, and approval is not recorded there | A review view in a connected app |
| Invoices and payments | The accounting system, reached through the same connector | The same |
| Approval | Recorded in the database from a separate approval page, by a named person. The connector refuses any payment without a valid approval record | The same. Codex's approval policy can add a prompt |
| Payment caller | The payment officer, or a separate payment worker with only the payment scope. Never the reconciliation run | The same |

Some terms: **authoritative state** is the one copy of the facts that counts, kept in a **system of record**. A **transaction** is a group of changes that succeed or fail together. A **unique constraint** stops the same value from being stored twice. A **payment intent** records one approved payment waiting to be made.

![The weekly payment run, by design. A skill gives rules to the reconciliation run, which never pays. The run writes status and proposals to the run database through the connector, with the propose scope only. The database feeds the review artifact, which only displays rows. A named person approves on a separate approval page, which records the approval in the database. A separate payment caller calls the payment connector. The connector checks the approval while claiming the intent, then posts to the accounting system, which pays once per intent.](img/weekly-payment-run-by-design.png)

The sandbox can vanish without losing progress, because the status lives in the database. No payment moves without an approval the connector checks.

### What the design must answer

1. **The VM disappears while invoice 9 of 15 is in progress.** Each invoice's status is written to the database, through the connector, as soon as the invoice is processed. It is never held only in the sandbox. So invoices 1 to 8 are safe. Losing the VM loses only the unfinished work on invoice 9.
2. **How the next run knows where to resume.** It asks the database for the invoices not yet reconciled, and it starts at invoice 9. It never relies on VM files, the review artifact or the chat history.
3. **Who authorizes a payment.** A named person approves on a separate approval page (see the [business-layer appendix](appendix-business-layer-details.md)). The artifact only displays rows. The approval page writes the approval to the database.
   - **What the approval covers.** It is bound to the exact payee, the payee's bank account, the amount, the currency and the invoice version, for example with a hash of those fields. A changed bank account is the main fraud path, so a change voids the approval. The approval also expires after a set time.
   - **Who may do what.** The approver must not be the person who set the worker's access. The approver must also not be the payment caller for the same intent (separation of duties).
   - **The check.** Before every payment, the connector checks for a valid, unexpired approval record. If there is none, it rejects the call, whatever the agent or its prompts do. A prompt from `requiresUserInteraction` is a second layer, not the safeguard. See [Scheduled tasks](scheduled-tasks.md) for where that setting is documented.
4. **How duplicate payments are prevented.** Each approved invoice gets one stable payment-intent ID under a unique constraint.
   - The connector reads the approval and claims the intent **atomically**, in one database transaction. A second claim fails. Nothing can change between the check and the claim.
   - Each intent moves through clear states: claimed, submitted, then confirmed or failed.
   - A claim has a lease, a time limit. An expired lease reopens only a *claimed* intent. A *submitted* intent is never retried until the accounting system has been checked for that payment.
   - The connector passes the intent ID as an **idempotency key** if the API accepts one. That label makes a repeated request take effect only once.
   - A duplicate invoice under a different number is a matching problem. The reconciliation run flags it.
5. **What the artifact is for.** The Sheets artifact is a view for reviewers. It lacks what payments need: atomic writes, concurrency control and recovery. So it never holds the authoritative state.

The same rule runs through the whole design: the sandbox does the work, the database keeps the record, and the connector decides what is allowed.

**Where the keys live.** **[Inferred]**
- Do not store the payment key as a [network secret](cloud-environments-and-self-hosted-runners.md) on the run's environment. Any session there could call the payment API with it and skip the approval check. Keep the payment key in the MCP connector.[^cloud-environments]
- Give the reconciliation run its own connector token with only the `record_status` and `propose_payment` scopes. "The same connector" must never mean the same scopes. Only the payment caller's token can call `execute_payment`.
- In the Claude app, a scheduled task uses its owner's connectors, and its actions "appear as you".[^cloud-scheduled-tasks] So the task must belong to a dedicated worker account that signs in the connector, never to the person who approves payments.

### Running it as a project

**[Inferred]** The same run can live in a [Claude project](projects-coordination-on-top-of-sessions.md). The weekly task becomes a scheduled task inside the project. So each run is a thread that starts with the project's instructions and memory. Say the owner prefers a different layout for the exception list. Claude saves that preference to project memory, and later threads start with it. A change to the payment policy itself goes into the skill as a new, reviewed version, never into memory, because memory is not enforced. The business layer does not change. The database holds the status. The connector checks the approval and pays each intent once.

[^cloud-environments]: As verified on November 9, 2026. Configure cloud environments, Anthropic.
[^cloud-scheduled-tasks]: As verified on November 9, 2026. The page says anything a scheduled task does through your connectors "appears as you". Automate work with scheduled tasks, Anthropic.
