API for developers
Automate your balance and cards from your own scripts — outside the cabinet.
https://app.fynko.net/api/v1
Authentication
- Open the cabinet → Security → “API access”.
- Name your token and press Create. The value is shown once — copy it now, it can't be shown again.
- Send it with every request:
Authorization: Bearer <token> Accept: application/json
You can revoke a token any time from the same page — it stops working immediately. No valid token → 401 Unauthorized.
Card number & CVV
Your regular API token can't see the full card number or CVV. That needs a separate, narrower token type — safer than putting that power in a token you might also use in a script.
- In the cabinet → Security → “Card number & CVV access”, create a token: list the IP address(es) it may be used from, and confirm with your current password.
- That token can only call the reveal endpoint below — nothing else, and only from the IP(s) you listed. Any other request, or a request from another IP, is rejected even with a valid token.
Like in the cabinet, the CVV is shown once — a second reveal returns "cvv": null, "cvv_consumed": true.
Endpoints
GET/me
Your account profile and current balance.
{
"id": 42, "name": "Ivan", "email": "[email protected]",
"balance_minor": 5000, "balance": "50.00", "two_factor_enabled": true
}
GET/bins
The card options you can order (the bin_id values POST /cards accepts) — with fees and minimums already calculated for your account.
{
"data": [
{
"id": 3, "code": "400242", "brand": "visa",
"fee_rate_bps": 600, "open_price_minor": 100,
"description": "US Ads", "region": "US",
"min_top_minor": 500, "instant": true, "topup": true,
"withdraw": false, "history": true
}
]
}
GET/cards
Your cards.
GET/cards/{id}
Details for one card. balance is what you can spend right now: the balance minus open holds (authorizations the merchant has not settled or cancelled yet; a hold counts as spent until it is released). holds_minor is the amount currently held.
{
"data": {
"id": 7, "brand": "visa", "label": "Ads card", "last4": "4242",
"status": "active", "balance_minor": 12000, "balance": "120.00",
"holds_minor": 0, "pending_recharge_minor": 0, "expiry_month": 8, "expiry_year": 2028,
"created_at": "2026-08-03T12:00:00+00:00"
}
}
GET/cards/{id}/reveal
The full card number, CVV, expiry — and, for cards that have one, the static online-payment password (threeds_password): the value asked for on the second step of a 3DS purchase check. It is the same for all your cards and never changes; null when the card has none. Requires a reveal-scoped token — see “Card number & CVV” above.
{
"pan": "4111111111111111", "cvv": "123", "cvv_consumed": false,
"expiry": "08/28", "threeds_password": "Kx7pQ2"
}
GET/cards/{id}/statement
That card's own recent activity — issuing, recharges, purchases, refunds, cash-out. Up to 500 of the most recent entries; "truncated": true means older history isn't included.
{ "data": [ { "id": 501, "type": "card_spend", "amount": "−$12.34", "...": "..." } ], "truncated": false }
GET/cards/{id}/3ds-codes
Polling fallback for 3DS one-time codes: the codes for that card that haven't expired yet (10 minutes), newest first. Prefer the webhook — this is for clients that can't receive one. Up to 60 requests per minute.
{
"data": [
{ "id": 123, "otp": "482913", "merchant": "Amazon",
"created_at": "2026-09-13T12:00:00+00:00", "expires_at": "2026-09-13T12:10:00+00:00" }
]
}
GET/history
Your recent wallet activity: deposits, and money moving to/from a card (issuing, recharging, cashing out). A card's own purchases show up in that card's statement instead, not here. Up to 500 most recent entries.
POST/cards
Order a new card.
{ "bin_id": 3, "amount": 50 }
POST/cards/{id}/recharge
Top up an existing card.
{ "amount": 20 }
POST/cards/{id}/cashout
Close a card and return its remaining balance to your wallet.
POST/deposits
Reserve a crypto deposit address.
{ "network": "usdt_trc20", "amount": 25 }
Webhook for 3DS codes
When a purchase asks for a one-time 3DS code, the card provider sends it to us — and we can push it straight to your server, so your script can enter it without a human watching the cabinet.
- In the cabinet → Security → “Webhook for 3DS codes”, save an HTTPS URL. You get a signing secret (shown once). Saving the URL again issues a new secret.
- We
POSTa JSON body to that URL for every code. Respond with any 2xx status within 5 seconds; anything else is retried about once a minute until the code expires (10 minutes).POST {your URL} Content-Type: application/json X-Fynko-Event: card.3ds_code X-Fynko-Signature: t=1757764800,v1=5f1c…e2a9 { "id": 123, "event": "card.3ds_code", "created_at": "2026-09-13T12:00:00+00:00", "data": { "card_id": 7, "otp": "482913", "merchant": "Amazon", "expires_at": "2026-09-13T12:10:00+00:00" } } - Verify the signature before trusting the code: the
X-Fynko-Signatureheader ist=<unix time>,v1=<hex>, wherev1is HMAC-SHA256 of the string<t>.<raw body>using your secret. Reject requests whosetis more than 5 minutes old.// PHP [$t, $v1] = explode(',', $_SERVER['HTTP_X_FYNKO_SIGNATURE']); $t = substr($t, 2); $v1 = substr($v1, 3); $expected = hash_hmac('sha256', $t.'.'.file_get_contents('php://input'), $secret); $valid = hash_equals($expected, $v1) && abs(time() - (int) $t) < 300;
The same code may arrive more than once (retries) — treat id as the deduplication key.
Limits & errors
- Money-moving requests (order/recharge/cash-out a card, reserve a deposit) are limited to 30 per minute per account.
422— invalid input, or the request can't be completed right now (e.g. insufficient balance).403— that card isn't yours.401— missing, expired, or revoked token.
Before retrying a request
If ordering or recharging a card times out, don't resend the same request blindly — check GET /cards first. A new card, or a changed pending_recharge_minor, means it already went through.