EUR payouts
Send EUR to European bank accounts over SEPA, settled from your EUR international account. Recipients are identified by IBAN + BIC.
See the Payouts overview for common fields + customer attribution, and the NGN page for the shared payout object + management endpoints.
Want the exact fee before you send? Preview it with POST /v1/payouts/quote — an advisory, read-only fee + cost breakdown for your account.
Prerequisites
- International accounts enabled on your merchant account.
- An active EUR account to send from. In the individual flow this is the sender’s own virtual account (
sender_account_not_provisionedif missing); in the business/treasury flow it’s your merchant international account (no_active_international_accountif missing). If your account is configured for both flows, the account checked follows the payout — see sender attribution. See the error table. - A sender for compliance — how you supply it depends on your flow: the individual flow passes
sender_customer_idon every payout; the business/treasury flow passes no per-payout sender; an account configured for both passes it or omits it per payout. See below. - For attribution reads on the customer feed: the API key needs
customer_transaction_view.
POSTSave a EUR beneficiary, then pay by reference
A saved EUR beneficiary captures the address the receiving network needs (the inline path does not).
| Path | Field | Required | Notes |
|---|---|---|---|
| Beneficiary | bank.iban | yes | Recipient IBAN. |
| Beneficiary | bank.bic_code | yes | 8–11 char BIC/SWIFT. |
| Beneficiary | address.street / city / zip_code | yes | Receiving-network compliance. |
| Beneficiary | name | yes | Recipient name. |
curl https://api.swappr.me/api/v1/beneficiaries \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"currency": "EUR",
"name": "Hans Müller",
"bank": {
"iban": "DE89370400440532013000",
"bic_code": "COBADEFFXXX",
"bank_name": "Commerzbank"
},
"address": {
"street": "Friedrichstraße 1",
"city": "Berlin",
"zip_code": "10117"
},
"external_reference": "vendor-de-7"
}'POSTCreate a EUR payout
amount_minor is in cents (100000 = €1,000.00). Prefer the by-beneficiary path; the inline recipient is soft-deprecated for FX.
The inline path is the simpler shape — iban + bic_code + name:
| Path | Field | Required | Notes |
|---|---|---|---|
| Inline | recipient.iban | yes | Recipient IBAN. |
| Inline | recipient.bic_code | yes | 8–11 char BIC/SWIFT. |
| Inline | recipient.name | yes | Recipient name. |
| Inline | recipient.bank_name | yes | Recipient’s bank name. |
| Inline | recipient.email | yes | Recipient email. |
| Inline | recipient.street / recipient.city / recipient.country | yes | Recipient address (country as ISO 3166-1 alpha-2, e.g. DE). |
The recipient identity + address is now required for EUR. Unlike GBP/USD, EUR does not require state or zip_code.
Sender attribution
EUR requires the sending customer to be identified for compliance, and how you identify them depends on your flow.
Individual flow — pass sender_customer_id on every payout (the id of a customer created via POST /v1/customers); Swappr resolves their stored KYC. It is required — an inline sender block does not substitute for it, and omitting it returns missing_field. You may still send an inline sender alongside it: the two are complementary, inline fields winning per-field while the referenced customer’s stored KYC backfills any you omit.
Business / treasury flow — omit sender_customer_id. The sender is your merchant treasury customer, resolved automatically. If only this flow is enabled on your account, sending one anyway returns customer_id_mismatch. If your account is configured to require sender identity, supply it with an inline sender block.
Both flows enabled — if Technest has enabled both flows on your account, sender_customer_id is optional, and it selects the flow per payout. Supply it and the payout is attributed to that end customer and leaves the sender’s own account (sender_account_not_provisioned if they have none). Omit it and the payout is attributed to your treasury customer and leaves your merchant international account (no_active_international_account if you have none). customer_id_mismatch does not apply — supplying a sender is a valid instruction for this configuration, not an error. This is a Technest-configured capability, not a per-request option.
customer_id must match sender_customer_id if both are passed.
Response
201 Created with the payout object (currency: "EUR"). Status transitions to paid on network confirmation — listen for the payout.paid webhook.
Errors
| Code | HTTP | Cause |
|---|---|---|
fx_features_not_enabled | 403 | International accounts not enabled |
no_active_international_account | 403 | (Business/treasury) No active merchant EUR international account |
sender_account_not_provisioned | 422 | (Individual) The sending customer has no active EUR virtual account — issue one via POST /v1/customers/{id}/virtual_accounts |
missing_field | 400/422 | Required recipient field absent — recipient.iban, recipient.bic_code, recipient.name, recipient.bank_name, recipient.email, recipient.street, recipient.city, recipient.country |
beneficiary_not_found | 404 | beneficiary_id unknown / not yours / wrong env |
beneficiary_currency_mismatch | 400 | beneficiary_id is not a EUR beneficiary |
missing_field | 400 | (Individual) sender_customer_id absent — it is required on FX payouts and an inline sender block does not substitute. Returned before sender_info_required. |
sender_info_required | 422 | Your account is configured to require sender identity and the merged sender details (inline sender block + the referenced customer’s stored KYC) are still incomplete |
customer_id_mismatch | 400 | customer_id ≠ sender_customer_id — or a business/treasury-only account sent a per-payout sender_customer_id (omit it; the sender is your treasury customer). The second cause does not apply to an account configured for both flows |
no_treasury_customer | 400 | (Business/treasury) Your treasury customer isn’t provisioned yet — contact Technest to set up your international payouts |
idempotency_key_conflict | 409 | Same Idempotency-Key, different body |
idempotency_conflict | 409 | Same Idempotency-Key as a prior payout that differs in amount or recipient account — narrower than idempotency_key_conflict, which compares the whole request body |
merchant_reference_duplicate | 409 | merchant_reference was already used on a recent payout; each reference is single-use within the cool-down window |
insufficient_funds | 402 | Wallet balance is below the payout amount plus fees |
wallet_frozen | 403 | The source wallet is frozen; no debits are permitted |
beneficiary_blacklisted | 403 | Recipient is on your merchant blacklist — un-blacklist them on the Beneficiaries page, or send to a different recipient |
beneficiary_globally_blocked | 403 | Recipient is on the platform-wide blacklist and cannot be overridden — contact support |
provider_not_entitled | 403 | Your account isn’t enabled to send this currency through any configured route — contact Technest to enable it. Distinct from routing_failed: routes exist, your account is not enabled for them |
provider_paused | 403 | Sending this currency is temporarily paused on your account — contact Technest. Distinct from provider_not_entitled: your account is enabled for a route, but Technest has paused it |
routing_failed | 422 | No disbursement route is available for this payout at all, or the destination bank could not be identified |
beneficiary_cooldown | 429 | Same recipient paid recently — pass allow_duplicate: true if intentional |
provider_error | 502 | Downstream rail unreachable; retry-safe with the same key |
Shared management endpoints are on the NGN page.
curl https://api.swappr.me/api/v1/payouts \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount_minor": "100000",
"currency": "EUR",
"beneficiary_id": "ben_cmo8x2p9q0...",
"sender_customer_id": "cust_cmoji8...",
"customer_id": "cust_cmoji8...",
"merchant_reference": "DE-INV-55"
}'curl https://api.swappr.me/api/v1/payouts \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount_minor": "100000",
"currency": "EUR",
"recipient": {
"name": "Hans Müller",
"iban": "DE89370400440532013000",
"bic_code": "COBADEFFXXX",
"bank_name": "Commerzbank",
"email": "hans.mueller@example.com",
"street": "Hauptstrasse 1",
"city": "Berlin",
"country": "DE"
},
"sender_customer_id": "cust_cmoji8...",
"merchant_reference": "DE-INV-55"
}'Webhook events
payout.processing → payout.paid / payout.failed (+ payout.reversed). customer_id / customer_reference included when set.