Changelog

Changes to the API contract, newest first. breaking marks a change that can stop an integration that works today; review those before each release.

2026-10-10

  • breakingAPI keys created before scopes existed (no scope list) are now read-only: payout:read, payin:read, balances:read, statements:read and prices:read. Calls outside these scopes return 403 scope_denied.
  • breakingWebhooks no longer carry the X-IPN-Secret header. Verify X-Bifrost-Signature.
  • breakingEvery /v1 error now has the same shape: error.code, error.message and, when useful, error.details. Branch on error.code.
  • breakingCodes that named the external processor are now returned as external_processor_error.
  • breakingGET /v1/statements: amount is now a string with 8 decimals instead of a JSON number. GET /v1/statements/summary sums total_amount without floating-point rounding.
  • breakingGET /v1/statements and /v1/statements/summary return only movements caused by API operations: DEPOSIT, WITHDRAWAL, RATE, FEE, WITHDRAWAL_REFUND and DEPOSIT_REVERSAL. EXCHANGE and ROYALTY are no longer returned or accepted in type.
  • breakingFixed-wallet success messages are now snake_case: fixed_wallets_supported_success, fixed_wallets_list_success, fixed_wallets_config_success, fixed_wallets_config_update_success, fixed_wallets_assign_success, fixed_wallets_already_assigned.
  • breakingWebhook payment_reversed: data.status is now reversed instead of success.
  • addedPOST /v1/payout and POST /v1/payin accept network aliases (eth, erc20, bnb, bsc, bep20, arb, trx, trc20, matic, sol, btc and others; see Network aliases). Case, spaces, hyphens and underscores are ignored. Payouts and payins are stored and returned with the canonical network name; list filters still take the canonical name.
  • addedGET /v1/summary/tokens and the accepted_tokens of GET /v1/summary: balance_key, the key of the token in GET /v1/balances and in the balance filter of GET /v1/statements.
  • addedGET /v1/check-payin and GET /v1/list-payin: status reversed and the reversal field (reversed_at, partial, amounts) when the network undid a credited payment. list-payin accepts status=reversed and its summary has total_reversed; status=completed excludes reversed payins.
  • changedGET /v1/get-price: prices below 1 keep 8 significant digits instead of 2 decimals, so low-value tokens are no longer quoted as 0,00. A quote stored as zero now answers 404 price_not_found.
  • changedPOST /v1/payin: when the account has no minimum_payment set, the payin requires 100% of crypto_amount to be completed.
  • removedinvalid_expires_at is no longer returned: an expires_at above 86400 answers 400 invalid_parameters with details.fields.expires_at.