> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.paywithatoa.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Pay Send: Pay Money Out to Payees

> Send payouts with Agent Pay under a SEND contract. The account owner authorises once at their bank and Atoa enforces per-payment and period caps.

Every send happens under a **SEND contract**: the account owner authorises it once at their bank, and Atoa enforces
its per-payment and period caps on every draw.

## Set up the contract

<CodeGroup>
  ```python Python theme={null}
  contract = atoa.contract.create(
      type="SEND",
      name="Supplier payouts",
      limits={
          "max_per_payment": 500.00,
          "period_limits": [{"amount": 2000.00, "period": "MONTH"}],
          "valid_to": "2026-12-31T23:59:59Z",
      },
  )

  print(contract.authorization_url)               # the account OWNER approves here, at their bank
  atoa.contract.await_active(contract.contract_id)         # → ACTIVE
  ```

  ```typescript TypeScript theme={null}
  const contract = await atoa.contract.create({
    type: "SEND",
    name: "Supplier payouts",
    limits: {
      maxPerPayment: 500.00,
      periodLimits: [{ amount: 2000.00, period: "MONTH" }],
      validTo: "2026-12-31T23:59:59Z",
    },
  });

  console.log(contract.authorizationUrl);         // the account OWNER approves here, at their bank
  await atoa.contract.awaitActive(contract.contractId);   // → ACTIVE
  ```
</CodeGroup>

## Send a payout

`payment.send` takes an array of instructions — one element for a single payout — and returns one `Payment` per
instruction, in order, plus a **`nextAction`** (TS) / **`next_action`** (Python) for the owner's approval.

<CodeGroup>
  ```python Python theme={null}
  result = atoa.payment.send(
      contract_id=contract.contract_id,
      payments=[{
          "amount": {"amount": 250.00},
          "beneficiary": {"name": "ACME LTD", "sortCode": "040004", "accountNumber": "12345678"},
          "orderId": "payout-3001",
          "reference": "Invoice 2043",
      }],
  )
  # result.next_action — the owner approves before money moves (next section)
  ```

  ```typescript TypeScript theme={null}
  const result = await atoa.payment.send({
    contractId: contract.contractId,
    payments: [{
      amount: { amount: 250.00 },
      beneficiary: { name: "ACME LTD", sortCode: "040004", accountNumber: "12345678" },
      orderId: "payout-3001",
      reference: "Invoice 2043",
    }],
  });
  // result.nextAction — the owner approves before money moves (next section)
  ```
</CodeGroup>

**Sandbox:** the recipient account decides the outcome — `040004` / `12345678` settles `COMPLETED`; `10000002` and
`10000003` fail with a `failureReason`. Fetch the authoritative list with `atoa.sandboxTestAccounts()` rather than
hardcoding.

## SCA on a payout

The **business owner** approves every payout on Atoa's page with a one-time code or a passkey before money moves.
After the decision, read each payment's outcome — business failures come back as `FAILED` payments you branch on,
not thrown errors.

<CodeGroup>
  ```python Python theme={null}
  send_to_owner(result.next_action.approval_url)     # your own delivery
  decision = atoa.payment.await_decision(result.next_action.approval_id)
  print(decision.status)                             # APPROVED / DECLINED / EXPIRED

  for p in result:                                   # result is still a list[Payment]
      print(p.order_id, p.status, p.failure_reason or "")   # e.g. NAME_MISMATCH, LIMIT_EXCEEDED
  ```

  ```typescript TypeScript theme={null}
  sendToOwner(result.nextAction.approvalUrl);        // your own delivery
  const decision = await atoa.payment.awaitDecision(result.nextAction.approvalId);
  console.log(decision.status);                      // APPROVED / DECLINED / EXPIRED

  for (const p of result) {                          // result is still a Payment[]
    console.log(p.orderId, p.status, p.failureReason ?? "");   // e.g. NAME_MISMATCH, LIMIT_EXCEEDED
  }
  ```
</CodeGroup>

To keep the owner in your own web UI, embed the approval with the
[**Approvals SDK**](/agent-pay/approvals) instead of sharing the URL — pass `nextAction.clientSecret` to
`confirmApproval`. Declined payments read back `FAILED` with `failureReason: APPROVAL_DECLINED`; lapsed,
`APPROVAL_EXPIRED`. In sandbox, open the `approvalUrl` and force either decision.

## Batches

Up to **20** instructions per call; each `orderId` unique within the batch; results in the order you sent. A batch
is one `send` call, so it carries one `nextAction` — the owner approves it once.

<CodeGroup>
  ```python Python theme={null}
  payments = atoa.payment.send(
      contract_id=contract.contract_id,
      payments=[
          {"amount": {"amount": 120.00}, "beneficiary": {"name": "ACME LTD", "sortCode": "040004", "accountNumber": "12345678"}, "orderId": "batch-1"},
          {"amount": {"amount": 80.00},  "beneficiary": {"name": "GLOBEX",   "sortCode": "040004", "accountNumber": "12345678"}, "orderId": "batch-2"},
      ],
  )

  for p in payments:
      print(p.order_id, p.status)
  ```

  ```typescript TypeScript theme={null}
  const payments = await atoa.payment.send({
    contractId: contract.contractId,
    payments: [
      { amount: { amount: 120.00 }, beneficiary: { name: "ACME LTD", sortCode: "040004", accountNumber: "12345678" }, orderId: "batch-1" },
      { amount: { amount: 80.00 },  beneficiary: { name: "GLOBEX",   sortCode: "040004", accountNumber: "12345678" }, orderId: "batch-2" },
    ],
  });

  for (const p of payments) {
    console.log(p.orderId, p.status);
  }
  ```
</CodeGroup>

## Update or revoke

`contract.update` returns a fresh `authorizationUrl` — the existing limits stay enforced until the owner
re-approves. `contract.revoke` is terminal; further sends are rejected.

<CodeGroup>
  ```python Python theme={null}
  updated = atoa.contract.update(
      contract.contract_id,
      limits={"max_per_payment": 750.00, "period_limits": [{"amount": 3000.00, "period": "MONTH"}], "valid_to": "2027-06-30T23:59:59Z"},
  )
  print(updated.authorization_url)         # owner re-approves the new caps

  atoa.contract.revoke(contract.contract_id)
  ```

  ```typescript TypeScript theme={null}
  const updated = await atoa.contract.update(contract.contractId, {
    limits: { maxPerPayment: 750.00, periodLimits: [{ amount: 3000.00, period: "MONTH" }], validTo: "2027-06-30T23:59:59Z" },
  });
  console.log(updated.authorizationUrl);   // owner re-approves the new caps

  await atoa.contract.revoke(contract.contractId);
  ```
</CodeGroup>

<Warning>
  On **production** these calls move real money to real accounts. Keep amounts small and beneficiaries verified
  while testing, and switch to `environment: "production"` only when you're ready.
</Warning>
