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 #
- Read the state: the IBAN, its balance, your tariff and what is enabled.
- Give the IBAN to your payers. Incoming payments are credited automatically.
- Pay out by SEPA: quote the fee, then create the payout with that fee.
- 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,labelandstatus, ornulluntil PayCA has opened it;wallet.balance— the IBAN balance:availableandpending(held for payouts in progress);capabilities— which ofdeposit,payoutandtransferare enabled;tariff— your deposit and payout fees;minimumDeposit— the smallest incoming payment that still credits something after the deposit fee;purposeCodes— the values accepted asreasonin 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"
}
}
virtualAccountIdisaccount.idfrom the state response.- If the tariff changed after the quote, the payout is refused with
fee_changedinstead of charging a different fee. Quote again. amountplus 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.cryptoandwithdrawals.fiat(withfiatCurrencies, and the reason infiatUnavailablewhen 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;usdTransferandusdTopUp.
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 therailyou 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
fiatMinimumsand the quote asminimum; a smaller amount isbelow_minimum. indicativeis what the amount would yield at the current market price. It is indicative only: the amount paid out follows the actual sale, shown asfiatAmountonce the withdrawal is completed. Where an OTC margin applies, the indicative rate includes it and the completed payout reports the retained amount asotcMarginFiat. The withdrawal fee in the coin is quoted separately.indicativeisnullwhen 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 hasswiftFeeQuoteRequired: true. If explicitly selecting an EUR payment scheme, include the sameschemein the quote. If the fee changes before submission, the create call returns409 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.fiatCurrenciesand the calls return403 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_requestwith adetail. - 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/historylists the moves underusdTransfers.- Without the permission the call is
403 capability_disabled. It is separate fromcapabilities.transferof 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_requestwith adetail. - 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/historylists the top-ups underusdTopUps.- 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, itsfeesWithheldthe 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. |