Editability note: this guide was drafted against the OpenAPI spec. If the product/engineering team hasn’t validated it against a recent end-to-end trace, flag anything that reads off and edit the relevant section — each H2 below is self-contained.
The data model
Three entities come together on every payout:- Beneficiary — who you’re paying. Identity only; PII is tokenized on creation.
- Instrument — where the money goes. Bank account, wallet, or card, attached to a beneficiary. Credentials are tokenized.
- Payout — the single payment. Links a beneficiary and one of their instruments to an amount, currency, and rail.
Economics: source vs dest amounts
Every payout has two amounts:source_amount— what’s debited from your merchant balance in your source currency.dest_amount— what the beneficiary receives in their destination currency.
fixed_side field tells Anton which amount is authoritative:
fixed_dest(default) — beneficiary receives exactlydest_amount; Anton computessource_amountincluding FX and fees.fixed_source— merchant pays exactlysource_amount; Anton computes how much the beneficiary receives after FX and fees.
fee_bearer controls who absorbs the fee:
merchant(default) — fee is added on top ofsource_amount.beneficiary— fee is deducted fromdest_amount, so the beneficiary receives less than the stated amount.
Corridors, methods, and rails
A corridor is a(currency, country, method, network) combination Anton can deliver through. Before attempting a payout, verify the corridor is enabled on your account:
method field on POST /v1/payouts selects the delivery method. For fiat:
faster_payment— UK Faster Paymentssepa— SEPA Credit Transfer (EUR)ach— US ACHswift— SWIFT international wirewire— generic domestic wirebank_transfer— generic bank transfer (rail picks based on corridor)mobile_money— M-Pesa, MTN, etc.
rail_type (fiat, crypto, or stablecoin) is a hint Anton may override based on corridor availability.
Purpose and reference
Two required fields that serve different audiences:purpose— a compliance-facing payment-purpose code. Examples:contractor_payment,supplier_payment,salary,refund,services,goods. Used for reporting and some rails require it.reference— your own free-form string, up to 100 chars. Appears on the beneficiary’s statement where the rail supports it. Use your invoice or order number so both sides can reconcile.
Send end-user session context
If a person triggered this payout in your product — a customer hitting “pay”, an operator releasing an invoice — send thesession object. Every field is optional and
none of them can fail your payout, but they are the difference between Anton scoring a
payout it can see and one it is guessing at.
Why it materially improves the risk assessment
Without session context, the only address Anton sees is your server’s — which tells it where your infrastructure runs, not where your user is. That is the single biggest blind spot in scoring a payout. With it, Anton can reason about:- Where the payer actually is — country and network of
ip, checked against the payout’s destination corridor. - Whether the story is consistent —
timezoneagainst the country the IP resolves to. A Toronto browser paying from a Singapore address is worth a second look; the same browser from a Toronto address is not. - What kind of network it is — residential broadband, a datacenter, a Tor exit, an iCloud Private Relay egress. These carry very different weight, and Anton treats legitimate consumer privacy tooling differently from anonymity infrastructure.
- Whether it fits your own pattern — once you send session data consistently, a payout that arrives without it stands out against your own baseline, which is a useful signal in its own right.
Send the IP your edge observed for the end user — not your server’s address and not
a value the browser supplied. If you sit behind a load balancer or CDN, take the client
entry from
X-Forwarded-For counting from the right, at the hop your own infrastructure
appends. A caller-supplied leftmost entry is attacker-controlled.Data-quality feedback, never rejection
Only a syntactically invalidip is an error (422). Everything else is accepted and
reported back on the payout as session_quality, so you can fix your integration without
anything failing in production:
non_public_ip almost always means a misconfigured proxy handed us your own load
balancer’s private address instead of the user’s.
session.ip supersedes end_user_ip
The older top-level end_user_ip field still works. When both are present, session.ip
wins, unconditionally. New integrations should send session and leave end_user_ip
alone.
What you are confirming by sending it
By sending session data you confirm you collected it lawfully from your end user under your own privacy notice, and that you are authorized to share it with Anton for fraud prevention and AML transaction monitoring. Anton keeps it as transaction evidence on a 7-year horizon aligned to the payout record, and never uses it to build a profile of your users outside that purpose.Idempotency
POST /v1/payouts requires an Idempotency-Key header. Derive it from your own business data so retries after a network failure converge on the same payout:
X-Idempotent-Replayed: true. Different bodies with the same key return 409 idempotency_conflict. See Idempotency for details.
The state machine
Payouts move through a 13-state machine. The full detail is in How Anton Evaluates Payouts; the short version:Subscribe to webhooks — don’t poll
Every state transition fires apayout.* event. Subscribe once via POST /v1/webhooks and handle the events you care about:
payout.completed— funds deliveredpayout.failed,payout.returned— terminal failure pathspayout.screening_failed,payout.velocity_blocked,payout.engine_blocked— compliance/risk blocks (payout.engine_blockedfires alongsidepayout.velocity_blockedwhen the Anton engine drove the block)payout.cancelled— operator or API cancellation
GET /v1/payouts/{id} works in development but wastes rate-limit budget at scale and misses transitions.
Cancelling a payout
You can cancel a payout that has not yet been submitted to a rail — fromcreated, pending_screening, pending_approval, pending_engine_review, or manual_review:
processing, the rail has it — cancellation is no longer possible via the API. Contact support if you need to halt an in-flight payout.
On successful cancellation, the debited funds (source amount, fee, and any FX buffer) are released back to your balance.
What can go wrong
422 insufficient_balance
422 insufficient_balance
Your merchant balance in the source currency can’t cover
source_amount + fee + buffer. Top up the balance or reduce the payout.403 corridor_not_enabled
403 corridor_not_enabled
The requested
(source_currency, dest_currency, country, method) isn’t active on your account. Call GET /v1/corridors to see active ones, or contact support to enable a new corridor.404 beneficiary_not_found / instrument_not_found
404 beneficiary_not_found / instrument_not_found
The ID doesn’t exist or belongs to a different merchant. Double-check the ID, including prefix (
ben_..., ins_...).422 invalid_instrument
422 invalid_instrument
The instrument is archived, disabled, or its method/currency doesn’t match the payout. Instruments are scoped to a single country + method at creation.
429 rate_limit_exceeded
429 rate_limit_exceeded
Honor
Retry-After and back off. See Rate Limits.Next steps
Manage beneficiaries
Dedup, update PII, archive, restore.
Handle webhooks
Subscription, signing, delivery semantics.
Crypto & stablecoin
Network selection, finality, memo/tag fields.
FX & exchange
Lockable quotes and cross-currency payouts.