Guides
Withdraw to a bank or a wallet
Withdraw USDC to an Icelandic bank account in your own name, or crypto to a wallet. Crypto withdrawals are confirmed from a link in your email.
Before you start
- A key with
withdrawals:create. Addtransactions:readif the same key should list your other withdrawals and transactions;withdrawals:createalone can read withdrawals and your saved bank accounts. - Withdrawals switched on for the API:
withdrawals_enabledin GET/v1/status. - Enough of the asset in your available balance. The amount you ask for includes the fee.
Bank withdrawals
Bank withdrawals are always from your USDC balance, to an Icelandic bank account in the account holder's name: we pay to your kennitala, so the bank refuses an account in someone else's name. There's nothing else to choose: an ordinary account is paid in krónur at Arion's rate, and an Arion foreign-currency account (03xx-38-…) in US dollars.
Your saved accounts
GET/v1/bank-accounts lists the accounts you have withdrawn to before, most recently used first:
# Signed by sign-headers.sh: see Authentication
curl https://public-api.myntkaup.is/v1/bank-accounts \
$(./sign-headers.sh GET /v1/bank-accounts | sed 's/^/-H /')import { Myntkaup } from "@myntkaup/api";
const client = new Myntkaup(); // reads the key from the environment
const { data: accounts } = await client.bankAccounts.list();
console.log(accounts.map((account) => account.account_number));from myntkaup import Myntkaup
client = Myntkaup() # reads the key from the environment
accounts = client.bank_accounts.list()["data"]
print([account["account_number"] for account in accounts]){
"data": [
{
"account_number": "0133-26-012345",
"payout_currency": "ISK",
"added_at": "2026-03-02T14:05:00Z",
"last_used_at": "2026-10-28T09:12:00Z"
}
]
}Withdraw
POST/v1/withdrawals/bank takes the amount of USDC, with at most 2 decimals, and the bank
account: a saved one, or a new one as 0000-00-000000 or 12 digits. The Idempotency-Key header is required.
# Signed by sign-headers.sh: see Authentication
body='{"amount":"250.00","bank_account":"0133-26-012345"}'
idempotency_key=$(uuidgen) # reuse it to retry safely
curl https://public-api.myntkaup.is/v1/withdrawals/bank \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $idempotency_key" \
$(./sign-headers.sh POST /v1/withdrawals/bank "$body" | sed 's/^/-H /') \
--data "$body"import { Myntkaup } from "@myntkaup/api";
const client = new Myntkaup(); // reads the key from the environment
// Sends a random Idempotency-Key unless you pass idempotencyKey.
const withdrawal = await client.withdrawals.createBank({
amount: "250.00",
bankAccount: "0133-26-012345",
});
console.log(withdrawal.id, withdrawal.status);from myntkaup import Myntkaup
client = Myntkaup() # reads the key from the environment
# Sends a random Idempotency-Key unless you pass idempotency_key.
withdrawal = client.withdrawals.create_bank(amount="250.00", bank_account="0133-26-012345")
print(withdrawal["id"], withdrawal["status"]){
"id": "wd_01JB8X2Q4M7Z3V9K5T1N6R0P2W",
"type": "bank",
"status": "pending",
"asset": "USDC",
"network": null,
"amount": "250",
"fee": "7",
"address": null,
"memo": null,
"bank_account": "0133-26-012345",
"tx_id": null,
"source": "public_api",
"created_at": "2026-11-03T10:15:10Z",
"confirm_by": null,
"completed_at": null
}- The amount goes on hold at once, and the withdrawal is
pendinguntil we pay it out, on a business day. It is thencompleted. - The minimum is 15 USDC and the fee is taken from the amount (
feein the answer). Below the minimum, or not more than the fee:422 amount_below_minimum. - A foreign-currency account at a bank other than Arion:
400 invalid_request. - The account owner gets an email for every bank withdrawal made through the API.
Crypto withdrawals
A crypto withdrawal made through the API is a request. We email a link to the account's email address, and nothing is sent, or even held, until someone opens that link and confirms it, within 30 minutes. The email names the API key the request came from.
POST/v1/withdrawals/crypto takes:
assetandamount, fee included;address, andmemofor XRP (destination tag) and HBAR;network, only for USDC:ethereum(the default, ERC-20) orsolana;travel_rule: who the address belongs to, as the app asks. The law requires it for every crypto withdrawal.
travel_rule | When |
|---|---|
{ "address_owner": "self", "wallet_type": "self_hosted" } | your own wallet, whose keys you hold |
{ "address_owner": "self", "wallet_type": "hosted", "vasp": "kraken" } | your own account at an exchange |
{ "address_owner": "other", "wallet_type": "self_hosted", "beneficiary": { "type": "individual", "full_name": "Anna Jónsdóttir" } } | someone else's wallet |
{ "address_owner": "other", "wallet_type": "hosted", "vasp": "other", "vasp_name": "Example Exchange", "beneficiary": { "type": "company", "company_name": "Dæmi ehf.", "registration_number": "5501012340" } } | a company's account at an exchange not in the list |
vasp is one of binance, coinbase, kraken, crypto_com, bybit, okx, bitget, kucoin, gate_io, htx, mexc, bitfinex, gemini, bitstamp, upbit, bithumb, bitpanda, etoro, revolut or other. To another Myntkaup customer's deposit address, we fill the travel rule in from their account.
# Signed by sign-headers.sh: see Authentication
body='{"asset":"BTC","amount":"0.01","address":"bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh","travel_rule":{"address_owner":"self","wallet_type":"self_hosted"}}'
idempotency_key=$(uuidgen) # reuse it to retry safely
curl https://public-api.myntkaup.is/v1/withdrawals/crypto \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $idempotency_key" \
$(./sign-headers.sh POST /v1/withdrawals/crypto "$body" | sed 's/^/-H /') \
--data "$body"import { Myntkaup } from "@myntkaup/api";
const client = new Myntkaup(); // reads the key from the environment
// Nothing is sent until the link in the confirmation email is opened.
const withdrawal = await client.withdrawals.createCrypto({
asset: "BTC",
amount: "0.01",
address: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
travelRule: { addressOwner: "self", walletType: "self_hosted" },
});
console.log(withdrawal.status, withdrawal.confirm_by);from myntkaup import Myntkaup
client = Myntkaup() # reads the key from the environment
# Nothing is sent until the link in the confirmation email is opened.
withdrawal = client.withdrawals.create_crypto(
asset="BTC",
amount="0.01",
address="bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
travel_rule={"address_owner": "self", "wallet_type": "self_hosted"},
)
print(withdrawal["status"], withdrawal["confirm_by"]){
"id": "wd_01JB8X2Q4M7Z3V9K5T1N6R0P2W",
"type": "crypto",
"status": "awaiting_confirmation",
"asset": "BTC",
"network": "bitcoin",
"amount": "0.01",
"fee": "0.0005",
"address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"memo": null,
"bank_account": null,
"tx_id": null,
"source": "public_api",
"created_at": "2026-11-03T10:15:10Z",
"confirm_by": "2026-11-03T10:45:10Z",
"completed_at": null
}The answer is 202 with status awaiting_confirmation and confirm_by, when the link stops working. Then:
- Open the email and confirm. The amount goes on hold and the withdrawal is
pendingwhile we check and send it. - Once it's sent it is
completed, with the blockchain transaction intx_id. - A link not used in time leaves the withdrawal
expired, and nothing was held. Ask again if you still want it.
Refusals before anything is saved:
422 asset_not_withdrawable: the asset, or that network, can't be withdrawn through the API;422 amount_below_minimum: below the asset's minimum, or not more than its fee;422 insufficient_funds: not enough available;400 invalid_request: an address that isn't valid for the asset, a missing memo, an incompletetravel_rule, or a Myntkaup deposit address of your own;403 account_restricted: crypto withdrawals are frozen on the account, or your profile is missing your address (finish it in the webapp);403 forbidden: withdrawals are switched off for the API.
Follow up
GET/v1/withdrawals lists bank and crypto withdrawals from every channel, newest first, filtered
by type, status, asset, from and to:
# Signed by sign-headers.sh: see Authentication
curl "https://public-api.myntkaup.is/v1/withdrawals?type=bank&limit=10" \
$(./sign-headers.sh GET "/v1/withdrawals?type=bank&limit=10" | sed 's/^/-H /')import { Myntkaup } from "@myntkaup/api";
const client = new Myntkaup(); // reads the key from the environment
const page = await client.withdrawals.list({ type: "bank", limit: 10 });
console.log(page.data.map((withdrawal) => [withdrawal.id, withdrawal.status]));from myntkaup import Myntkaup
client = Myntkaup() # reads the key from the environment
page = client.withdrawals.list(type="bank", limit=10)
print([(withdrawal["id"], withdrawal["status"]) for withdrawal in page["data"]])GET/v1/withdrawals/{id} returns one.
Security checklist
- A key used only for withdrawals, with
withdrawals:createand, as we recommend, a tight IP allowlist. - One
Idempotency-Keyper withdrawal, stored before sending and reused on retries. - Crypto addresses checked before they are sent: we can't reverse a withdrawal to the wrong address.
- Every confirmation email read before you confirm it: it shows the amount, the address and the key.
- The
request_idof every withdrawal is logged.