> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paywithatoa.com/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 approves it once at their bank, and Atoa checks
its per-payment and period caps on every payout drawn from it.

## Set up the contract

```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
```

## 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.

```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)
```

**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

SCA (Strong Customer Authentication) here is the **business owner's** sign-off: they approve 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.

```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
}
```

To keep the owner in your own web UI, embed the approval with the
[**Approvals SDK**](https://docs.paywithatoa.com/agent-pay/approvals.md) instead of sharing the URL — pass `nextAction.clientSecret` to
`confirmApproval`. A declined payout reads back `FAILED` with `failureReason: APPROVAL_DECLINED`; a lapsed one,
`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.

```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);
}
```

## Update or revoke

`contract.update` returns a fresh `authorizationUrl` — the existing limits stay in force until the owner
approves the new ones. `contract.revoke` is final; further sends are rejected.

```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);
```

> [!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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.