---
title: "Approval controls for stablecoin payouts: maker-checker, limits, and audit trails"
seoTitle: "Stablecoin payout approval controls for finance teams"
description: "How finance teams control stablecoin payouts: maker-checker approval that survives 5-minute quotes, payee checks, limits, idempotency, and an audit trail."
date: "2026-10-06"
updated: "2026-10-06"
category: "payments"
author: "BlindPay Team"
howto:
  name: "How to set up approval controls for stablecoin payouts"
  steps:
    - name: "Separate who requests and who approves"
      text: "Give the person who creates a payment request a different role from the person who approves it, and record both user IDs on every payment. Nobody approves their own request."
    - name: "Approve the payment intent, not the quote"
      text: "Approve the recipient, the amount in the recipient's currency or in USD, and a tolerance band. Quotes expire in about 5 minutes, so the system requests the quote and executes only if the quoted amount stays inside the approved band."
    - name: "Re-approve every new or changed payee"
      text: "Treat new bank details as a new payee. Alert on every bank account added, verify the details through a known channel, and hold the first payout until a second person approves it."
    - name: "Set internal limits below the provider's limits"
      text: "Cap per-payout, daily, and monthly amounts per recipient and per approver, and route anything above the cap to a senior approver."
    - name: "Make every execution idempotent and logged"
      text: "Send the same Idempotency-Key on every retry, store the quote ID and payout ID against your internal payment ID, and keep the signed webhook events as the status record."
    - name: "Reconcile daily"
      text: "Match approved intents to payouts and final statuses every day, and escalate anything failed, on hold, or unmatched."
faq:
  - q: "What is maker-checker approval for payouts?"
    a: "Maker-checker means one person prepares a payment and a different person approves it before money moves. It stops a single compromised or careless account from sending funds alone. For stablecoin payouts it matters more than for card payments, because an on-chain transfer can't be reversed once it is final, so the approval is the last real checkpoint."
  - q: "How do you approve a stablecoin payout if the quote expires in 5 minutes?"
    a: "Approve the payment intent instead of the quote. The approver signs off on the recipient, the amount, and a tolerance band, such as the recipient getting 5,000 reais give or take 1%. Your system then requests a fresh quote and executes only if it lands inside the band. If it doesn't, the payment goes back to the approver."
  - q: "What controls stop paying the wrong person?"
    a: "Payee verification and change control. Verify bank details through a channel you already trust, never through the email that sent them, and treat any change in bank details as a new payee that needs fresh approval. Alert on every new bank account in your provider account. Business email compromise is the classic way payout details get swapped."
  - q: "How do you prevent duplicate stablecoin payouts?"
    a: "Use one internal ID per obligation and an idempotency key on every request that creates a payout. With BlindPay, sending the same Idempotency-Key and the same body replays the original response instead of creating a second payout, and the key is kept for 24 hours. Never let a timeout trigger a retry with a new key."
  - q: "What should a stablecoin payout audit trail include?"
    a: "For each payment: who requested it, who approved it and when, the recipient and bank details used, the quote ID with its rate and fees, the payout ID, every status change with timestamps, and any bank reference such as a UETR. Keep the signed webhook events, because they are the provider's own record of each state change."
  - q: "Do provider limits replace internal payout limits?"
    a: "No. Provider limits exist for the provider's compliance program and are set per customer, often by KYC or KYB tier. Your internal limits exist for your own risk appetite and should sit below them, per recipient and per approver. A payout that is allowed by the provider can still be one your company never meant to send."
---

Stablecoin payout controls come down to six rules: separate who requests from who approves, approve the payment intent rather than a 5-minute quote, re-approve every new or changed payee, keep internal limits below the provider's, make every execution idempotent, and reconcile daily. On-chain transfers are final, so the approval is the last checkpoint.

This guide is for finance and operations teams running contractor, supplier, or partner payouts over stablecoin rails. If you are new to the rails themselves, the [guide to blockchain payments vs crypto payments](/resources/more/blockchain-payments-vs-crypto-payments) is the place to start.

**Key takeaways**

- Maker-checker approval is the core control: no one sends money alone.
- Quotes expire in minutes, so approve the recipient, amount, and a tolerance band, then quote and execute.
- Bank-detail changes are the top fraud path. Treat a changed payee as a new payee.
- Idempotency keys and one internal ID per obligation stop duplicate payouts.
- Daily reconciliation catches what approvals miss: failed, held, and unmatched payouts.

> **Definition:** Maker-checker (also called four-eyes approval) is a control where one person prepares a payment and a second, different person approves it before execution. The system records both identities, and nobody can approve their own request.

## Why do stablecoin payouts need stricter approval controls?

Because the on-chain leg can't be pulled back. Once stablecoins move and the transfer is final, there is no chargeback and no bank recall for that leg.

That puts the weight on the moment before execution. [Are stablecoin payments reversible?](/resources/more/are-stablecoin-payments-reversible) covers finality in detail.

The fraud pressure is real too. In the [2026 AFP Payments Fraud and Control Survey](https://www.financialprofessionals.org/about/learn-more/press-releases/Details/over-75-percent-of-us-firms-experienced-payments-fraud-in-2025-while-ai-adoption-for-fraud-mitigation-lags), published April 14, 2026, 76% of US organizations reported attempted or actual payments fraud in 2025, and 74% were affected by business email compromise. Most of those attacks target the approval process, not the payment rail.

## Where should the approval step sit in a stablecoin payout?

Before the execute call, but not on the quote itself. The quote window is too short for a human approval queue.

A BlindPay payout follows the same pattern every time: request a quote, authorize the funds, then execute before the quote expires, which is 5 minutes by default per the [payouts docs](/docs/payouts). BlindPay's own [guide to migrating manual payouts](/docs/migrations/manual-payouts) says the human approval step stays a gate in your pipeline, between the quote and the execute call.

That leaves two workable patterns:

| Pattern | How it works | Fits |
| --- | --- | --- |
| Approve the quote | Approver sees the live quote and approves inside the window, or the system re-quotes | Small teams, low volume, one approver online |
| Approve the intent | Approver signs off on recipient, amount, and a tolerance band; the system quotes and executes if the quote is inside the band | Payroll runs, batches, multiple time zones |

The tolerance band is the part most teams skip. An illustrative band such as "pay 5,000 reais, maximum cost 1,010 USDC" gives the system room to execute at a moving rate without letting it execute at any rate. [Batch payouts with live quotes](/resources/more/batch-stablecoin-payouts-live-quotes) covers re-quoting at scale.

## Which approval controls should a finance team set up?

Six controls cover most of the risk. Each one has a clear failure it prevents and evidence you should keep.

| Control | What it prevents | How to implement | Evidence to keep |
| --- | --- | --- | --- |
| Maker-checker | One account sending money alone | Requester and approver must be different users | Both user IDs and timestamps |
| Intent approval with tolerance | Executing at a bad rate after approval | Approve amount plus a max cost band | Approved band vs quoted amount |
| Payee change control | Paying a fraudster's account | New or changed bank details need fresh approval | Verification call log, approver ID |
| Internal limits | Oversized or unusual payouts | Caps per recipient, per approver, per day | Limit table and override approvals |
| Idempotent execution | Duplicate payouts on retries | One internal ID per obligation, idempotency keys | Internal ID to quote ID to payout ID |
| Daily reconciliation | Silent failures and holds | Match intents to final statuses each day | Reconciliation report and exceptions |

The [OFAC Framework for Compliance Commitments](https://ofac.treasury.gov/media/16331/download?inline) names internal controls as one of five essential parts of a sanctions program, next to risk assessment and testing. Payout approvals are where those controls meet real money.

## How do you verify a recipient before the first payout?

Confirm the bank details through a channel you already trust, and hold the first payout to any new payee for a second approval. Never verify details using the same email that delivered them.

Three habits do most of the work:

- **Call back on a known number** when a supplier or contractor sends new bank details.
- **Alert on every new bank account.** BlindPay fires a `bankAccount.new` webhook when a bank account is added to a customer, per the [webhook events docs](/docs/learn/webhooks-events). Route it to whoever owns payee approvals.
- **Use the rail's name checks** where they exist. [Verification of payee for instant payments](/resources/more/verification-of-payee-instant-payments) explains how rails check the account holder before money moves.

For Brazil and Mexico, [the details you need to pay someone](/resources/more/pix-key-cpf-clabe-payout-details) lists which identifiers to verify.

## How should payout limits be set?

Internally, below whatever the provider allows. Provider limits are about the provider's compliance program; yours are about your own risk.

At BlindPay, each customer starts with transfer limits set by its verification tier, calculated on the stablecoin amount, as listed in the [limit increase docs](/docs/learn/limit-increase):

| Default limit | KYC Standard | KYB Standard | KYC Enhanced |
| --- | --- | --- | --- |
| Per transaction | US$10,000 | US$30,000 | US$50,000 |
| Daily | US$50,000 | US$100,000 | US$100,000 |
| Monthly | US$100,000 | US$250,000 | US$500,000 |

Higher limits go through a compliance review with supporting documents. Set your own caps underneath: per recipient, per approver, and per day, with a named senior approver for anything above. [Stablecoin off-ramp limits](/resources/more/stablecoin-off-ramp-limits) explains how provider caps work across the industry.

## How do you lock down who can execute payouts?

Treat API access like signing authority. Whoever holds a production API key can create payouts, so keys belong on servers, not in people's hands.

On BlindPay, practical steps from the [API keys docs](/docs/learn/api-keys) and [instances docs](/docs/learn/instances):

- Keep keys server-side and restrict each one to your server IPs with `ip_whitelist`.
- Turn on **Require passkey for critical actions** so creating a key requires a registered passkey.
- Revoke a key by deleting it. Deletion takes effect immediately.
- Assign team roles deliberately. Instances support `owner`, `admin`, `finance`, `checker`, `operations`, `developer`, and `viewer` roles, and changing a member's role requires the owner, admin, or checker role.

Your maker-checker logic still lives in your own system. The provider sees the execute call; your pipeline decides who was allowed to make it.

## How do you keep an audit trail for stablecoin payouts?

Store the chain of IDs and the signed events, not screenshots. An auditor should be able to go from an invoice to the bank deposit in one lookup.

For every payment, keep: requester, approver, approval time, recipient and bank details used, the quote ID with rate and fees, the payout ID, each status change with timestamps, and bank references such as the UETR on SWIFT (POBO/COBO) payouts. BlindPay signs every webhook with `svix-id`, `svix-timestamp`, and `svix-signature` headers, so verified events double as tamper-evident records.

Duplicates are an audit problem too. BlindPay replays the original response when you retry with the same `Idempotency-Key` and body, and keeps keys for 24 hours, per the [idempotency docs](/docs/learn/idempotency). The [idempotency keys guide](/resources/more/stablecoin-api-idempotency-keys) shows the pattern, and [stablecoin API webhooks and reconciliation](/resources/more/stablecoin-api-webhooks-reconciliation) covers event handling.

## How do you reconcile stablecoin payouts every day?

Match approved intents to payouts, and payouts to final statuses, once a day. Anything not `completed` gets an owner.

A BlindPay payout ends as `completed`, `failed`, or `refunded`, and can pass through `on_hold` for review. The [payout statuses guide](/resources/more/stablecoin-payout-statuses-explained) explains each one. Two rules for the exceptions list:

- `refunded` means the stablecoins went back to the funding source. Re-approve before you send again.
- `failed`, or a payout sitting in review, doesn't refund itself. BlindPay refunds after an operator review on USD payouts and timed-out reviews, so contact support instead of waiting.

When something does go wrong, the [blockchain payment incident playbook](/resources/more/blockchain-payment-incident-playbook) takes over. And if you pay contractors, note that tax and worker classification rules vary by country; talk to an advisor, since this page isn't tax or legal advice. [Stablecoin payroll for LATAM contractors](/resources/more/stablecoin-payroll-latam-contractors) covers the payout side.

## What to do next

Write down your six controls, name an owner for each, and run one payout through the full path on a development instance: request, approve, quote, execute, webhook, reconcile. Fix whatever step needed a human to look something up.

Read the [BlindPay payouts docs](/docs/payouts) to place your approval gate between the quote and the execute call.
