title: Virtual IBAN
summary: Your company's dedicated IBANs, opened by PayCA: a EUR IBAN to receive and pay out by SEPA, or EUR/USD IBANs whose payments are converted into USDC or USDT and credited to the company's crypto accounts, with crypto withdrawals to your address book and withdrawals to a bank account. How fees, including monthly ones, are charged.
updated: 2026-10-22

A Virtual IBAN is a dedicated EUR IBAN opened in the name of your company. SEPA payments sent to it land on the IBAN balance. From there you pay out by SEPA to any IBAN and, if enabled for you, move the money to your own EUR account.

You can use the IBAN in the PayCA cabinet, through the API, or both — whichever your account manager enabled for you.

Before You Start #

Virtual IBAN is set up individually for each merchant. PayCA opens the IBAN for your company once your company verification is complete, and your account manager sends you:

  • companyId — the company the IBAN belongs to;
  • your tariff and which operations are enabled.

Until the setup is done, every call returns 403 with capability_disabled.

All endpoints use the usual x-client-id / x-client-secret headers. Amounts are EUR with at most two decimals and are sent and returned as strings.

Integration Flow #

  1. Read the state: the IBAN, its balance, your tariff and what is enabled.
  2. Give the IBAN to your payers. Incoming payments are credited automatically.
  3. Pay out by SEPA: quote the fee, then create the payout with that fee.
  4. If enabled, move money to your own EUR account.
Step Endpoint
Read state GET /v1/corporate-banking/{companyId}/account
Quote a payout POST /v1/corporate-banking/{companyId}/quote
Pay out POST /v1/corporate-banking/{companyId}/payouts
Follow a payout GET /v1/corporate-banking/{companyId}/payouts/{payoutId}
Move to your EUR account POST /v1/corporate-banking/{companyId}/transfers

1. Read the State #

GET /v1/corporate-banking/{companyId}/account

The response shows:

  • account — your IBAN: iban, bic, ownerName, label and status, or null until PayCA has opened it;
  • wallet.balance — the IBAN balance: available and pending (held for payouts in progress);
  • capabilities — which of deposit, payout and transfer are enabled;
  • tariff — your deposit and payout fees;
  • minimumDeposit — the smallest incoming payment that still credits something after the deposit fee;
  • purposeCodes — the values accepted as reason in payouts.
account.status Meaning
pending Being opened by the bank.
active Ready to receive payments.
failed The bank refused it. PayCA will contact you.

2. Receive Payments #

Give your payers the iban, bic and ownerName from the account object. No payment reference is required.

Each incoming SEPA payment is credited to the IBAN balance automatically, net of the deposit fee. Read the balance with GET …/account.

3. Pay Out by SEPA #

Quote the fee first:

POST /v1/corporate-banking/{companyId}/quote
Content-Type: application/json

{ "amount": "100.00" }
{ "amount": "100.00", "fee": "5.00", "totalDebit": "105.00", "currency": "EUR" }

Then create the payout with the quoted fee as expectedFee:

POST /v1/corporate-banking/{companyId}/payouts
Idempotency-Key: payout-2026-104
Content-Type: application/json

{
  "virtualAccountId": "6b0f2b1e-6f1c-4c5e-9a55-0f2a5b7c1d10",
  "amount": "100.00",
  "expectedFee": "5.00",
  "destination": {
    "name": "Supplier GmbH",
    "iban": "DE89370400440532013000",
    "bic": "COBADEFFXXX",
    "country": "DE",
    "addressLine1": "Hauptstrasse 1",
    "city": "Berlin",
    "postcode": "10115",
    "reason": "SUPP",
    "reference": "Invoice 2026-104",
    "scheme": "AUTO"
  }
}
  • virtualAccountId is account.id from the state response.
  • If the tariff changed after the quote, the payout is refused with fee_changed instead of charging a different fee. Quote again.
  • amount plus the fee is reserved on the IBAN balance at once. The reserve is spent when the payout settles and released if it fails.

The response is 202; its correlationId is the payout ID. Follow the payout with GET …/payouts/{payoutId}:

status Meaning
settled Sent. Final.
failed Rejected; amount and fee returned to the IBAN balance. Final.
unknown The outcome is being confirmed with the bank. Do not resend — keep polling.
any other In progress, money held.

Retries #

Retries are safe with the same Idempotency-Key: the same key returns the same payout, while a different body under that key is idempotency_conflict. Never change the key to retry a payout whose outcome you do not know — look it up with GET …/payouts/{payoutId} instead.

4. Move Money to Your EUR Account #

Available when capabilities.transfer is true.

POST /v1/corporate-banking/{companyId}/transfers
Idempotency-Key: sweep-2026-10-07
Content-Type: application/json

{ "toAccountId": "d290f1ee-6c54-4b01-90e6-d701748f0851", "amount": "500.00" }

The transfer is immediate and free. Only this direction is possible: the IBAN balance is funded by incoming SEPA payments, not by transfers. Not enough money on the IBAN balance is banking_rejected.

IBANs Converting into a Stablecoin #

Besides the EUR IBAN described above, PayCA can open IBANs in EUR or USD whose incoming payments are converted into USDC or USDT. A company may have several. The coins do not stay on the IBAN: they are credited to the company's crypto accounts, one in USDC and one in USDT, shared by all its IBANs. Withdrawals, moves to your USD account and top-ups from it use the crypto accounts. Coin amounts have two decimals.

Step Endpoint
List your IBANs GET /v1/corporate-banking/{companyId}/ibans
One IBAN GET /v1/corporate-banking/{companyId}/ibans/{ibanId}
Switch an IBAN's coin POST /v1/corporate-banking/{companyId}/ibans/{ibanId}/asset
History of an IBAN (deposits, conversions) GET /v1/corporate-banking/{companyId}/ibans/{ibanId}/history
Your crypto accounts GET /v1/corporate-banking/{companyId}/crypto-accounts, GET …/crypto-accounts/{accountId}
Their withdrawals, moves and top-ups GET /v1/corporate-banking/{companyId}/crypto-accounts/history[?asset=USDC]
Address book GET /v1/corporate-banking/{companyId}/addresses (addresses are managed by your account manager)
Withdraw in crypto POST …/crypto-accounts/{accountId}/crypto-payouts/quote, POST …/crypto-accounts/{accountId}/crypto-payouts, GET …/crypto-payouts/{payoutId}
Withdraw to a bank account POST …/crypto-accounts/{accountId}/fiat-payouts/quote, POST …/crypto-accounts/{accountId}/fiat-payouts, GET …/fiat-payouts/{payoutId}
Move to your USD account POST …/crypto-accounts/{accountId}/usd-transfers, GET …/usd-transfers/{transferId}
Top up from your USD account POST …/crypto-accounts/{accountId}/usd-topups, GET …/usd-topups/{topUpId}

Every POST that creates something needs an Idempotency-Key; the same key returns the same result, a different body under it is idempotency_conflict.

The IBAN's Coin #

Each IBAN shows the coin its payments are converted into now as asset. PayCA sets it when the IBAN is opened, and you can switch it at any time:

POST /v1/corporate-banking/{companyId}/ibans/{ibanId}/asset
Content-Type: application/json

{ "asset": "USDT" }

The response is the IBAN with its new coin. The coin is fixed when a conversion is ordered, so after a switch:

  • money still waiting (below the minimum) or queued for conversion goes in the new coin, measured against the new pair's minimum;
  • money already in a conversion finishes in that conversion's coin and is credited to that coin's account, whether or not the order has gone to the market.

Switching to the same coin changes nothing. The EUR IBAN without a coin cannot switch (invalid_request).

Incoming Payments #

Payments to such an IBAN are converted into its coin and credited to the company's crypto account in that coin, net of the deposit fee (charged in the IBAN's currency). The minimum deposit depends on the pair. Every IBAN states its current one as minimumDeposit and the one of each coin as minimumDeposits, in its currency:

Pair Minimum deposit
EUR → USDC 100 EUR
EUR → USDT 10 EUR
USD → USDC, USD → USDT 10 USD

A payment below the minimum is not credited. It waits and is added to your next payments until together they reach it. The history shows such a payment as waiting. Each conversion is listed with your amount, the fee, the monthly charges withheld (see Fees), the rate, the crypto account (accountId) and what was credited, rounded down to the cent.

The fee may be taken in the coin when a deposit is small. The market converts no less than a minimum amount of the coin. When taking the deposit fee in the currency would leave less than that, your whole payment is converted, and the same fee is taken from the coins instead: it is converted at the provider's execution rate, rounded up to the cent and deducted before the credit. The conversion then shows feeTakenIn: "asset", fee 0, and the deposit fee taken in feeAsset. For example, 100 EUR with a 2 EUR fee converted at 0.985 buys 101.52 USDC. The fee is 2 ÷ 0.985 = 2.0304…, so 2.04 USDC, and 99.48 USDC is credited. Otherwise feeTakenIn is currency and feeAsset is 0.

When an OTC margin applies, rate includes the margin and otcMarginAsset reports the coins retained separately from the deposit fee. credited is what reaches the account.

Crypto Accounts #

GET /v1/corporate-banking/{companyId}/crypto-accounts

Each account shows its asset and balance (available, and pending held for withdrawals in progress). It also shows what it offers now:

  • withdrawals.crypto and withdrawals.fiat (with fiatCurrencies, and the reason in fiatUnavailable when there are none);
  • fiatMinimums, the smallest withdrawal to a bank account per currency;
  • payoutFee, the company's withdrawal fee, taken in the account's coin;
  • usdTransfer and usdTopUp.

A withdrawal that is not offered is 403 capability_disabled (crypto) or 403 withdrawal_unavailable (bank account).

GET …/crypto-accounts/history lists the company's withdrawals (payouts), moves to its USD account (usdTransfers) and top-ups (usdTopUps), newest first, of both accounts or of one coin with ?asset=. Withdrawals made from an IBAN before the crypto accounts are listed there too, naming that IBAN in ibanId.

Address Book #

Crypto withdrawals go only to an address in your company's address book, on Polygon. Your account manager adds the addresses, sets the coins each one accepts (USDC, USDT or both) and disables them, at your request; send it through your usual confirmed channel. You list the book:

GET /v1/corporate-banking/{companyId}/addresses

Adding, changing or disabling an address through the API is refused with 403 addresses_managed_by_support.

A withdrawal from an account whose coin the address does not accept is refused with asset_not_allowed. One already accepted fails, with its amount and fee returned, if the address stops accepting the coin before it is sent.

A new address becomes usable at activeFrom, 24 hours after it was added; your account manager can confirm it earlier at your request. The address itself cannot be edited: ask your account manager to disable a wrong one and add the right address (it waits 24 hours again). A withdrawal to an address that is disabled before it is sent fails and its amount and fee return to the account.

Our payout system checks every new address on its own as well, independently of the address book. Where it does, each entry carries custodyStatus, and active turns true only when both agree:

custodyStatus Meaning
active Withdrawals may go to it (active: true).
activating Still in its 24 hours. activeFrom is when it becomes usable, usually a few minutes after the 24 hours; right after it is added, before the security checks report, it is the earliest possible time. An early confirmation by your account manager also waits here until the security checks confirm it.
blocked Refused by our security review; contact your account manager.
disabled Disabled.

Send a withdrawal only to an entry with active: true; any other is refused at once with address_inactive, and detail says from when it is usable.

Withdraw in Crypto #

POST /v1/corporate-banking/{companyId}/crypto-accounts/{accountId}/crypto-payouts
Idempotency-Key: payout-77
Content-Type: application/json

{ "addressId": "0c6f1f5e-8f0b-4f37-9d61-3f8d2f6e9a11", "amount": "250.00", "expectedFee": "3.00" }

Use POST …/crypto-accounts/{accountId}/crypto-payouts/quote with { "amount": "250.00" } to get fee and totalDebit in the account's coin. Pass the returned fee as expectedFee. If the account has cryptoFeeQuoteRequired: true, its crypto payout uses a separate tariff with an EUR minimum converted at the current market rate. Other accounts can also calculate the fee from payoutFee. amount plus the fee is held on the account at once. amount is sent in the account's coin on Polygon to the address; once the transfer is confirmed the withdrawal is completed with its txHash.

Withdraw to a Bank Account #

You give an amount in the account's coin, the currency to pay out in and a destination. The coins are sold and the proceeds are paid out in that currency, from either account:

  • EUR is paid by SEPA, to the same fields as a EUR payout (VirtualIbanDestination);
  • USD is paid to a bank account in USD (VirtualIbanUSDDestination), on the rail you choose — see USD destinations below.
POST /v1/corporate-banking/{companyId}/crypto-accounts/{accountId}/fiat-payouts/quote
Content-Type: application/json

{ "amount": "250.00", "currency": "EUR" }
{ "amount": "250.00", "fee": "3.00", "totalDebit": "253.00", "asset": "USDC", "currency": "EUR", "minimum": "100",
  "indicative": { "rate": "0.92", "amount": "230.00", "quotedAt": "2026-10-23T10:00:00Z" } }
  • The minimum is in the coin: 100 USDC to EUR, 10 for the others (USDT to EUR, USDC or USDT to USD). The account shows it in fiatMinimums and the quote as minimum; a smaller amount is below_minimum.
  • indicative is what the amount would yield at the current market price. It is indicative only: the amount paid out follows the actual sale, shown as fiatAmount once the withdrawal is completed. Where an OTC margin applies, the indicative rate includes it and the completed payout reports the retained amount as otcMarginFiat. The withdrawal fee in the coin is quoted separately. indicative is null when no current price is known.
  • The fee is in the account's coin. For a USD SWIFT payout, include "rail": "swift" in the quote when the account has swiftFeeQuoteRequired: true. If explicitly selecting an EUR payment scheme, include the same scheme in the quote. If the fee changes before submission, the create call returns 409 fee_changed. Get a fresh quote and confirm it before resubmitting.
  • It takes hours, up to a day.
  • If only part of the amount can be sold, PayCA may pay out what was sold and return the rest to the account in its coin: the completed withdrawal then shows returned.
  • If a currency is not available for the account's coin, it is missing from withdrawals.fiatCurrencies and the calls return 403 withdrawal_unavailable.

Then create it with the quoted fee:

POST /v1/corporate-banking/{companyId}/crypto-accounts/{accountId}/fiat-payouts
Idempotency-Key: sell-2026-11
Content-Type: application/json

{ "amount": "250.00", "expectedFee": "3.00", "currency": "EUR", "destination": { "name": "Supplier GmbH", "iban": "DE89370400440532013000", "bic": "COBADEFFXXX", "country": "DE", "addressLine1": "Hauptstrasse 1", "city": "Berlin", "postcode": "10115", "reason": "SUPP", "reference": "Invoice 2026-104", "scheme": "AUTO" } }

USD destinations

A payout in USD names its rail in the destination:

rail For Account fields Bank fields
us_domestic A bank account in the United States accountNumber (4–17 digits), routingNumber (9-digit ABA routing number, checksum verified), optional wireRoutingNumber bankName, bankAddress, bankCountry = US
swift A USD account at a bank abroad (or a US bank reached by SWIFT) iban or accountNumber (where the country has no IBAN) bic (the bank's SWIFT code), bankName, bankAddress, bankCountry (the SWIFT code's country), optional routingNumber for a US bank, optional intermediaryBank {bic, routingNumber}

Both rails also take the account holder: name, addressLine1, optional addressLine2, city, optional region and postcode, country, and the payment's reason (a purpose code) and reference. These take latin letters, digits, spaces and / - ? : ( ) . , ' + only, with no leading or trailing space; address lines and the city at most 35 characters, reference at most 140. A field the rail does not use (an iban on us_domestic, a wireRoutingNumber on swift) is refused rather than ignored, and any problem is invalid_request with a detail naming the field, for example destination.routingNumber must be a valid 9-digit ABA routing number. A SEPA destination with currency: "USD", or a USD one with EUR, is refused the same way.

POST /v1/corporate-banking/{companyId}/crypto-accounts/{accountId}/fiat-payouts
Idempotency-Key: sell-usd-2026-11
Content-Type: application/json

{ "amount": "250.00", "expectedFee": "3.00", "currency": "USD", "destination": { "rail": "us_domestic", "name": "Acme Supplies LLC", "addressLine1": "1 Main Street", "city": "New York", "region": "NY", "postcode": "10001", "country": "US", "accountNumber": "000123456789", "routingNumber": "021000021", "bankName": "JPMorgan Chase Bank NA", "bankAddress": "383 Madison Avenue, New York, NY", "bankCountry": "US", "reason": "SUPP", "reference": "Invoice 2026-104" } }
{ "rail": "swift", "name": "Supplier GmbH", "addressLine1": "Hauptstrasse 1", "city": "Berlin", "postcode": "10115", "country": "DE",
  "iban": "DE89370400440532013000", "bic": "COBADEFFXXX", "bankName": "Commerzbank AG", "bankAddress": "Kaiserplatz, Frankfurt am Main", "bankCountry": "DE",
  "intermediaryBank": { "bic": "CHASUS33XXX" }, "reason": "SUPP", "reference": "Invoice 2026-104" }

The withdrawal returns the destination as sent; on a USD one the SEPA fields it does not use come back empty.

Move to Your USD Account #

When PayCA has enabled it for you, a crypto account shows usdTransfer: true and its coins can be moved to your own active USD account in PayCA, at once, one for one (1 USDC or USDT = 1 USD) and without a fee:

POST /v1/corporate-banking/{companyId}/crypto-accounts/{accountId}/usd-transfers
Idempotency-Key: to-cards-2026-10-25
Content-Type: application/json

{ "toAccountId": "d290f1ee-6c54-4b01-90e6-d701748f0851", "amount": "250.00" }
{ "id": "6a1f2e3d-4c5b-5a69-8778-96a5b4c3d2e1", "accountId": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "fromAccountId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "toAccountId": "d290f1ee-6c54-4b01-90e6-d701748f0851", "asset": "USDC", "amount": "250", "currency": "USD", "credited": "250", "fee": "0",
  "status": "completed", "createdAt": "2026-10-25T09:00:00Z" }
  • The USD account must be active and belong to the crypto account's owner (your own USD account; for a cabinet company, the cabinet user's). Anything else is invalid_request with a detail.
  • Not enough on the crypto account is banking_rejected; it never goes below zero.
  • The USD account's usual account webhook reports the credit.
  • GET …/crypto-accounts/history lists the moves under usdTransfers.
  • Without the permission the call is 403 capability_disabled. It is separate from capabilities.transfer of the EUR IBAN.

Top Up from Your USD Account #

When PayCA has enabled it for you, a crypto account shows usdTopUp: true and it can be topped up from your own active USD account in PayCA, at once, one for one (1 USD = 1 USDC or USDT) and without a fee. It is a separate permission from moving coins to your USD account (usdTransfer).

POST /v1/corporate-banking/{companyId}/crypto-accounts/{accountId}/usd-topups
Idempotency-Key: from-cards-2026-10-25
Content-Type: application/json

{ "fromAccountId": "d290f1ee-6c54-4b01-90e6-d701748f0851", "amount": "250.00" }
{ "id": "1b4e28ba-2fa1-5d1a-8f4e-0e02b2c3d479", "accountId": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "fromAccountId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "toAccountId": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "currency": "USD", "amount": "250", "asset": "USDC", "credited": "250", "fee": "0",
  "status": "completed", "createdAt": "2026-10-25T09:00:00Z" }
  • The USD account must be active and belong to the crypto account's owner (your own USD account; for a cabinet company, the cabinet user's). Anything else is invalid_request with a detail.
  • Not enough on the USD account is banking_rejected; it never goes below zero.
  • The USD account's usual account webhook reports the debit.
  • GET …/crypto-accounts/history lists the top-ups under usdTopUps.
  • Without the permission the call is 403 capability_disabled.

Withdrawal Statuses #

status Meaning
pending Accepted; amount and fee held.
processing On its way.
completed Done. Final.
failed Nothing was sent; amount and fee are back on the account. Final.
refunded It could not be completed and PayCA returned the amount and fee in the coin. Final.

Webhooks #

Subscribe a URL to the events of your stablecoin IBANs and crypto accounts with type: virtual_iban:

POST /v1/webhooks
Content-Type: application/json

{ "url": "https://example.com/hooks/payca-iban", "type": "virtual_iban" }

Deliveries are signed (x-signature) and retried like every other PayCA webhook; POST /v1/webhooks/resend sends failed ones again with the same body (counted as virtualIban). Each body is:

{
  "id": "5b0a3e1c-4c55-4c3e-9a6b-0f7b4f3c2a10",
  "event": "virtual_iban.deposit.credited",
  "occurredAt": "2026-11-03T12:41:07Z",
  "data": {
    "id": "8f14e45f-ceea-467f-a9c6-3d1b2c4e5f60",
    "ibanId": "2c1e6b5a-7d8f-4e3a-9b2c-1d0e9f8a7b6c",
    "companyId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "accountId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "status": "credited",
    "currency": "EUR",
    "asset": "USDC",
    "gross": "1000.00",
    "fee": "4.00",
    "feesWithheld": "0",
    "net": "996.00",
    "feeTakenIn": "currency",
    "feeAsset": "0",
    "converted": "996.00",
    "rate": "0.9213",
    "credited": "1081.08",
    "createdAt": "2026-11-03T10:05:00Z",
    "creditedAt": "2026-11-03T12:41:07Z"
  }
}

Each event is delivered at least once: id identifies it (it is also the Idempotency-Key header, virtual-iban:{id}), so dedupe by id and process each one once. Events of one withdrawal may arrive out of order; each carries the status it is about.

event When data
virtual_iban.deposit.credited Incoming money of the IBAN was converted and credited The conversion as in the history: gross, fee, feesWithheld and net in the IBAN's currency, feeTakenIn and feeAsset (a small deposit's fee taken in the coin), converted, rate (currency per one coin), credited in the coin, and the crypto account credited (accountId)
virtual_iban.deposit.retained The deposit fee and the monthly charges owed took a whole payment; nothing was credited The deposit: id, amount, currency, fee, feesWithheld, receivedAt, retainedAt
virtual_iban.withdrawal.created A withdrawal was accepted (pending) The withdrawal as GET …/crypto-payouts/{payoutId} or …/fiat-payouts/{payoutId} returns it, with companyId and the crypto account (accountId)
virtual_iban.withdrawal.sent The coins left (processing) Same
virtual_iban.withdrawal.completed Done (completed): txHash for crypto, fiatAmount and any returned for a bank withdrawal Same
virtual_iban.withdrawal.failed Nothing was sent; amount and fee are back (failed) Same
virtual_iban.withdrawal.returned Returned by PayCA in the coin (refunded) Same
virtual_iban.period_fee.charged A monthly charge of an IBAN, owed in its currency kind (residency or minimum), amount, currency (the IBAN's), feesDue (all the IBAN owes now), periodStart, periodEnd, month, and for the minimum what it was worked out from: minimum, fees, residency
virtual_iban.period_fee.withheld Incoming money of an IBAN paid its monthly charges before conversion amount, currency, the deposits it came from (depositIds), the conversion (conversionId, absent when the payments were kept whole), feesDue (what is still owed), withheldAt

Every IBAN event names the IBAN (ibanId) and every event the company (companyId). A withdrawal made from an IBAN before the crypto accounts names that IBAN as well. The EUR IBAN without a coin sends no virtual_iban events.

Fees #

Your exact rates are in your agreement and in tariff. There are no invoices to pay.

Per operation. Incoming payments and payouts are charged max(amount × percent + fixed, minimum). The incoming fee is deducted from the amount received, in its currency; a payment no larger than its fee is kept whole as the fee. The payout fee is added to the payout amount and shown by the quote. On a stablecoin IBAN's crypto accounts the withdrawal fee is the company's one payout fee, in the coin of the account paid from.

Monthly. Two charges per IBAN and calendar month:

  • the residency fee of the IBAN, in advance: when the IBAN is opened, and then on the 1st of each month;
  • after the month ends, if the month's fees — operation fees and the residency fee together — are below your monthly minimum, the difference.

The days between the IBAN's activation and the end of that month count as part of the first full month. For example, for an IBAN activated on 7 October the residency fee is charged on 7 October for 7 October – 30 November, and the difference to the minimum for that period after 30 November. With a minimum of 100, a residency fee of 50 and operation fees of 40, that difference is 10.

The EUR IBAN without a coin is charged from its own balance (see below). An IBAN converting into a stablecoin owes its monthly charges in its currency (EUR or USD); nothing is taken from your crypto accounts. The amounts of your tariff count in the IBAN's currency (a residency fee of 50 is 50 EUR on a EUR IBAN). The IBAN shows what it owes as feesDue. Its next incoming payments pay it before they are converted:

  • the minimum deposit applies to the payments as received; the charges owed are withheld afterwards, from the payments that reached it;
  • the deposit fee is taken first, then the charges owed from what is left, and the rest is converted (net = gross − fee − feesWithheld);
  • a payment no larger than the deposit fee and the charges owed together is kept whole (retained, its feesWithheld the part that paid the charges); what is still owed carries over to the next payments, in this month or later ones;
  • each charge is made once, and what was withheld is listed on the conversion or the deposit as feesWithheld.

For example, a EUR IBAN converting into USDT (minimum 10 EUR) owes 30 EUR and receives 100 EUR with a 2 EUR fee: 30 EUR is withheld and 68 EUR converted. Receiving 20 EUR instead, it keeps the payment whole (2 EUR fee, 18 EUR towards the charges) and still owes 12 EUR. A payment of 8 EUR waits for the next ones, as any payment below the minimum, whatever is owed.

The monthly minimum counts the IBAN's operation fees in its currency: its deposit fees in the month its share of a conversion was credited (a fee taken in the coin by the tariff, in the currency), a payment the deposit fee took whole, and the company's withdrawal fees, at face value (1 USDC or USDT counts as 1 in the IBAN's currency) in the month the withdrawal completed. A company's withdrawals are not tied to an IBAN, so their fees fill the IBANs' minimums in order of age: the oldest IBAN first, up to what it lacks, then the next. Monthly charges withheld are not operation fees. A withdrawal that failed or was refunded charges no fee.

Moving to your USD account (…/usd-transfers) is free: one USDC or USDT is credited as one USD. Topping up from your USD account (…/usd-topups) is free too: one USD is credited as one USDC or USDT.

The EUR IBAN without a coin is charged its monthly fees from its balance, so available may become negative. While it is negative, nothing can leave the IBAN: payouts and transfers are refused with banking_rejected. Incoming payments cover the negative balance first.

Your EUR IBAN converting into a stablecoin. At your request PayCA can switch your EUR IBAN to USDC or USDT, once and for good, when its balance is exactly zero and nothing is in progress. The IBAN number stays the same; from then on payments to it are converted as described above, it appears in GET …/ibans with its asset (which you can then switch between USDC and USDT), and its monthly charges are owed in EUR from the next month on. The EUR calls (…/account, …/payouts, …/transfers) no longer show it.

Balances before the crypto accounts. Coins held on stablecoin IBANs when the crypto accounts were introduced were moved to the company's crypto account in the same coin. An IBAN whose balance was negative from monthly charges owes that amount instead, in its currency (one coin counted as one), and pays it from its next payments like any other charge.

Errors #

Errors are returned as {"code": "..."}, some with a detail. A wrong or missing x-client-id / x-client-secret is a 401 without a body, as on every other endpoint.

HTTP code What to do
400 invalid_request Fix the request. A refused address, a USD bank destination, an unknown coin, or a USD transfer or top-up with an account that is not your active USD account, says why in detail.
400 banking_rejected The bank refused the operation, or the balance is too low or negative.
403 capability_disabled Virtual IBAN, or this operation, is not enabled for the company. Contact your account manager.
404 not_found Unknown company, IBAN, account or payout.
409 fee_changed The tariff changed. Quote again.
409 idempotency_conflict The Idempotency-Key was already used with a different body.
409 bank_account_migration_required Contact your account manager.
400 address_inactive The address is not active yet (detail says from when), still waiting for the security checks, blocked, disabled, or not in your book.
400 asset_not_allowed The address does not accept the account's coin. Ask your account manager to add the coin to it, or use another address.
403 addresses_managed_by_support Addresses are added, changed and disabled by your account manager.
400 below_minimum Under the minimum of a withdrawal to a bank account of the coin and currency (detail says it).
403 withdrawal_unavailable This withdrawal is not available for the account's coin or the currency (detail says why).
503 banking_unavailable The bank is temporarily unavailable. Retry later.