Skip to content

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_deposit on /card_configs/list and min_first_deposit_amount on /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_amount keep 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_type value virtual_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: email always required, phone not collected (phone* / use_bound_phone ignored), first_name + last_name required and non-blank; violations return 400 virtual_a_required_fields_missing before any funds are frozen. Non-breaking — no new endpoints, no schema changes; clients that switch on card_type should add the new value.
  • 2026-08-21: New response field kyc_requirement on /card_headers/list and /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. When require_kyc=true and the end account does not meet it, /card/apply returns 400 kyc_required. Non-breaking additive field; shape documented on the header list page.

Changed

  • 2026-09-08: /card/apply enforces the package minimum first deposit. first_deposit_amount must 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 with 400 first_recharge_below_min (also reported by the preview as invalid_reason). Packages without a minimum behave exactly as before. Read min_first_deposit from the configs list (or min_first_deposit_amount from the preview) and always send first_deposit_amount explicitly.
  • 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/list only 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 in total — previously they were always listed and only rejected at apply. /card_configs/list and /card/first_deposit/preview now apply the same check up front and return 400 account_manager_bind_required / account_manager_unavailable / account_manager_open_disabled (the same codes /card/apply already returned). /card_configs/list additionally omits packages an account manager has closed for the calling account. Existing cards are unaffected. Non-breaking for integrations that take header_id / package_id from the list endpoints; integrations that hardcoded header IDs should refresh them. See error codes.
  • 2026-08-21: require_email / require_phone in /card_headers/list are now the effective values. They are resolved the same way the apply endpoint validates them (card-type default → header override → protocol rules: virtual_g both required, virtual_a email required + phone not collected, virtual_v both optional) and are never null. 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/apply now surface as 400 with their message_key. Validation failures such as virtual_a_required_fields_missing and virtual_g_name_invalid carry server-side context and were previously misclassified as 500 openapi_apply_card_failed; they now return 400 + the documented key. No change for integrations that already treat 4xx keys as terminal.
  • 2026-08-21: /card_headers/list no longer returns non-virtual headers. The "virtual cards only" filter is now pushed down to the query (excluded rows are not counted in total); previously, if the platform had configured non-virtual headers (e.g. physical cards) they were listed as-is and only rejected with 400 openapi_card_type_not_supported at /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/info with with_sensitive=true no 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:
  • 2026-08-03: Close Card endpoint documented. POST /api/v1/openapi/card/closeirreversibly close a virtual card (async: accepted → closing(4), completion via card.closed webhook; 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; 0 disables the window; fixed, non-sliding). send_code now returns grace_active so integrations can tell whether codes are currently required. Non-breaking — grace_active is 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 changewith_sensitive=true keeps 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_disabled is no longer returned by /card/info. A non-exempt credential sending with_sensitive=true without codes now gets 403 with the specific missing-factor key (email_code_required / pin_required / 2fa_code_required / sms_code_required), and 403 invalid_* / 429 on failed or locked verification. Integrations that matched openapi_sensitive_card_info_disabled should 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.
  • Transaction objects are strictly desensitized: last_four only (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 return 403.

v1.1

Added

  • 2026-06-15: Custom first-deposit amount on /card/apply via the optional first_deposit_amount, plus a new read-only /card/first_deposit/preview dry-run endpoint. Non-breaking — first_deposit_amount is optional (empty = config base); the preview is a new endpoint and changes no existing one.
  • 2026-05-26: New supported card_type value virtual_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/list
    • POST /api/v1/openapi/card_configs/list
    • POST /api/v1/openapi/cards/list
    • POST /api/v1/openapi/card/apply
    • POST /api/v1/openapi/card/first_deposit/preview
    • POST /api/v1/openapi/card/recharge
    • POST /api/v1/openapi/card/info
    • POST /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/info via with_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_type values are lowercase business codes (e.g. virtual_v).
  • Recharge status uses business codes: 2 success / 3 failed.
  • Open / close webhook status uses 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_key values are permanently stable once published
  • Removing fields or changing semantics bumps major version, with the previous major preserved for at least 6 months

Feedback

Released under MIT-equivalent terms.