Changelog
Breaking changes (removed fields, changed semantics, changed types) bump the major version with advance notice. New fields are non-breaking.
v1.4 (current)
Added
- 2026-09-08: Minimum first deposit decoupled from the fee-free base. New response fields
min_first_depositon/card_configs/listandmin_first_deposit_amounton/card/first_deposit/preview: the effective minimum total first deposit (max(initial_deposit / base_amount, the package-or-header minimum), base included).initial_deposit/base_amountkeep their meaning (the 1:1 fee-free part). Non-breaking additive fields; equal to the base for packages that set no minimum. - 2026-08-21: New supported
card_typevaluevirtual_a(Virtual card class A, same provider family as V / R / G). Available on every existing endpoint — header list / configs / preview / apply / recharge / info (incl. sensitive fields) / freeze / unfreeze / close / transactions — and in every outbound webhook (card.opened,card.open_failed,card.recharged,card.recharge_failed,card.closed,card.status_changed). Protocol-specific apply rules are documented in Virtual-A specific constraints:emailalways required, phone not collected (phone*/use_bound_phoneignored),first_name+last_namerequired and non-blank; violations return400 virtual_a_required_fields_missingbefore any funds are frozen. Non-breaking — no new endpoints, no schema changes; clients that switch oncard_typeshould add the new value. - 2026-08-21: New response field
kyc_requirementon/card_headers/listand/card_configs/list(platform KYC requirement for opening cards:require_kyc/kyc_type/kyc_level). The per-package value is the effective requirement (header > package > card-type three-level merge — exactly what apply validates); the per-header value is a preview before a package is chosen. Whenrequire_kyc=trueand the end account does not meet it,/card/applyreturns400 kyc_required. Non-breaking additive field; shape documented on the header list page.
Changed
- 2026-09-08:
/card/applyenforces the package minimum first deposit.first_deposit_amountmust be ≥min_first_deposit; when a package sets that minimum above its base, the field becomes required — an omitted / empty amount (which still defaults to the base) is rejected with400 first_recharge_below_min(also reported by the preview asinvalid_reason). Packages without a minimum behave exactly as before. Readmin_first_depositfrom the configs list (ormin_first_deposit_amountfrom the preview) and always sendfirst_deposit_amountexplicitly. - 2026-08-21: Account-manager-controlled headers are now filtered per account. Headers the platform hands over to account managers (opened per customer by the manager) are returned by
/card_headers/listonly when your account is bound to an active account manager who has opened the header for you (per-account setting beats the manager-wide one); otherwise they are filtered server-side and not counted intotal— previously they were always listed and only rejected at apply./card_configs/listand/card/first_deposit/previewnow apply the same check up front and return400 account_manager_bind_required/account_manager_unavailable/account_manager_open_disabled(the same codes/card/applyalready returned)./card_configs/listadditionally omits packages an account manager has closed for the calling account. Existing cards are unaffected. Non-breaking for integrations that takeheader_id/package_idfrom the list endpoints; integrations that hardcoded header IDs should refresh them. See error codes. - 2026-08-21:
require_email/require_phonein/card_headers/listare now the effective values. They are resolved the same way the apply endpoint validates them (card-type default → header override → protocol rules:virtual_gboth required,virtual_aemail required + phone not collected,virtual_vboth optional) and are nevernull. Previously they mirrored only the raw header configuration and could disagree with apply. Non-breaking (same field names and types). - 2026-08-21: Wrapped business errors on
/card/applynow surface as 400 with theirmessage_key. Validation failures such asvirtual_a_required_fields_missingandvirtual_g_name_invalidcarry server-side context and were previously misclassified as500 openapi_apply_card_failed; they now return400+ the documented key. No change for integrations that already treat 4xx keys as terminal. - 2026-08-21:
/card_headers/listno longer returns non-virtual headers. The "virtual cards only" filter is now pushed down to the query (excluded rows are not counted intotal); previously, if the platform had configured non-virtual headers (e.g. physical cards) they were listed as-is and only rejected with400 openapi_card_type_not_supportedat/card_configs/list//card/apply. Invisible to integrations that only consume virtual headers.
v1.3
Added
- 2026-08-03: Self-service sensitive card info via user second-factor verification.
/card/infowithwith_sensitive=trueno longer requires admin-granted credential access: pass the account's transaction-auth codes (email_code/pin/two_fa_code/sms_code) — the same verification flow as viewing the CVV on the web app (single-use codes, 10-minute validity, brute-force lockout). New companion endpoint:POST /api/v1/openapi/card/sensitive/send_code— sends the email/SMS code and reports which factors are required (fixed purpose, 60 s per-account cooldown withRetry-After).
- 2026-08-03: Close Card endpoint documented.
POST /api/v1/openapi/card/close— irreversibly close a virtual card (async: accepted →closing(4), completion viacard.closedwebhook; balance refunded after platform review). The endpoint has been live since v1.2 but undocumented ("preview"); v1.3 makes it part of the official contract. No behavior change. - 2026-08-03: Grace window (verify once, reuse for a while). After one successful second-factor verification, further sensitive retrievals for the same account need no verification fields for an admin-configured duration (default 30 min;
0disables the window; fixed, non-sliding).send_codenow returnsgrace_activeso integrations can tell whether codes are currently required. Non-breaking —grace_activeis a new response field.
Changed
- Admin-granted sensitive access is now a verification exemption for unattended server-to-server automation (still off by default, still approval-gated). Credentials that already have it see no behavior change —
with_sensitive=truekeeps working without codes. - Administrative ban: the platform can force-disable sensitive info access per card or per account. A ban overrides both authorization paths (second-factor codes and exempt credentials) and returns
403 card_sensitive_access_banned; an account-level ban also blocks/card/sensitive/send_code. 403 openapi_sensitive_card_info_disabledis no longer returned by/card/info. A non-exempt credential sendingwith_sensitive=truewithout codes now gets403with the specific missing-factor key (email_code_required/pin_required/2fa_code_required/sms_code_required), and403 invalid_*/429on failed or locked verification. Integrations that matchedopenapi_sensitive_card_info_disabledshould switch to these keys — see Error Codes.
v1.2
Added
- 2026-07-07: Card freeze / unfreeze and transaction details endpoints (4 new). Non-breaking — no existing endpoint changed.
POST /api/v1/openapi/transactions/list— transaction details across all your virtual cardsPOST /api/v1/openapi/card/transactions/list— transaction details for one cardPOST /api/v1/openapi/card/freeze— freeze an active virtual cardPOST /api/v1/openapi/card/unfreeze— unfreeze a user-frozen card
- Transaction objects are strictly desensitized:
last_fouronly (never the full PAN), no cardholder PII, no provider-side / internal order references. - Freeze/unfreeze require no
Idempotency-Key— they carry no monetary effect and are guarded by the card state machine (repeat freeze →card_already_frozen; repeat unfreeze →card_not_frozen). Only user-initiated freezes are reversible via/card/unfreeze; risk/admin/system freezes return403.
v1.1
Added
- 2026-06-15: Custom first-deposit amount on
/card/applyvia the optionalfirst_deposit_amount, plus a new read-only/card/first_deposit/previewdry-run endpoint. Non-breaking —first_deposit_amountis optional (empty = config base); the preview is a new endpoint and changes no existing one. - 2026-05-26: New supported
card_typevaluevirtual_g(Virtual card class G). Non-breaking — no new endpoints, no schema changes; existing integrations that don't onboard G see no impact. - 8 OpenAPI endpoints:
POST /api/v1/openapi/card_headers/listPOST /api/v1/openapi/card_configs/listPOST /api/v1/openapi/cards/listPOST /api/v1/openapi/card/applyPOST /api/v1/openapi/card/first_deposit/previewPOST /api/v1/openapi/card/rechargePOST /api/v1/openapi/card/infoPOST /api/v1/openapi/webhook_events/list
- HMAC-SHA256 authentication (4 headers)
- Idempotency-Key support (
/card/apply//card/recharge) - Webhook events:
webhook.test/card.opened/card.open_failed/card.recharged/card.recharge_failed/card.closed/card.status_changed - Opt-in sensitive card fields on
/card/infoviawith_sensitive=true— returns full PAN / CVV / expiry / cardholder name when access is granted to the credential and the card is active. Off by default; enablement is approval-gated.
Field-encapsulation rules
- All public IDs are prefixed strings (
card_/pkg_/hdr_/txn_/evt_); use them as opaque tokens. - Asset references use ISO 4217 currency codes / asset symbols (strings, never numeric IDs).
card_typevalues are lowercase business codes (e.g.virtual_v).- Recharge
statususes business codes:2success /3failed. - Open / close webhook
statususes strings:opened/open_failed/closed. - Internal-only fields (DB identifiers, provider-side order references, intermediate computation values, internal labels) are never returned.
Scope
- Virtual cards only:
virtual_l/virtual_p/virtual_v/virtual_r/virtual_g - No physical card / transfer endpoints (planned for later)
Planned (future)
Subject to change
- Independent sandbox environment
- Expose
GET /openapi.json(auto-generated OpenAPI 3.0 spec) - Expose
GET /openapi.postman.json(auto-generated Postman Collection)
Compatibility Promise
- Within the same major version (v1.x): fields are added, never removed
- Defaults & constraints (length, type) never change in a breaking way
message_keyvalues are permanently stable once published- Removing fields or changing semantics bumps major version, with the previous major preserved for at least 6 months
Feedback
- Email: [email protected]