Skip to main content
PanoFlow applies a two-person rule: a payment above the business’s approval threshold, or another sensitive change, waits for a second person before it happens. When your integration creates such a payment, it is created in pending_approval and someone in the business approves or rejects it in the PanoFlow web app.

What your integration sees

When a transfer needs approval, POST /v1/transfers succeeds with 201 and returns the transfer with status: pending_approval and status_reason: awaiting_approval. It is not an error: you don’t get approval_threshold_exceeded from this endpoint. While it waits, the amount and fee stay reserved in the source account. Then: PanoFlow sends payment.created when the pending transfer is created, so you can follow it with webhooks or by polling GET /v1/transfers/{transfer_id}. To find a business’s threshold, read GET /v1/limits (scope transfers:read).

The approval object

Each pending decision is an approval (apr_...):
Read approvals with GET /v1/approvals and GET /v1/approvals/{approval_id} (scope approvals:read). The list defaults to status=pending and accepts a comma-separated kind filter.

Approving happens in the web app

API keys and OAuth tokens can’t approve or reject. Deciding an approval needs a signed-in person in the PanoFlow web app who confirms with two-factor authentication, and the person who requested a payment can never approve it themselves. If you no longer want a payment that is waiting, cancel it before it is processed with POST /v1/transfers/{transfer_id}/cancel, or POST /v1/batches/{batch_id}/cancel for a batch.

Agent payments

A payment an AI agent makes that hits one of its ask-first rules, such as an amount above its ask-first amount, is held the same way with an agent_payment approval, and PanoFlow sends agent.payment.held. If nobody decides within 30 minutes, it is canceled with status_reason: approval_expired. See Agents and MCP.