Versioning

The API version is in every URL: https://api.finscale.dev/v1. Breaking changes only ship in a new version; everything else is additive. This page defines exactly what "additive" means, so you can build an integration that never breaks on a deploy you didn't know about.

One version: v1

The current — and only — version is v1. It's part of the path, so there is no ambiguity about what you're calling. Within v1, Finscale ships continuously: new endpoints, new fields, new payment methods, new event types. None of that changes the version, because none of it breaks a correctly built consumer.

If a change would break existing integrations — removing a field, renaming one, changing a type or the meaning of a status — it ships as a new version with its own path, and v1 keeps working as documented. Versions are retired only after a long, announced migration window.

Pinning with Finscale-Version

You can also pin the version per request with the optional Finscale-Version header. Without it, your account default applies — which today is always v1:

Pinned request
curl https://api.finscale.dev/v1/payments/pay_8Q2mX4nT1cVb \
  -H "Authorization: Bearer sk_test_51FinscaleDemo…" \
  -H "Finscale-Version: v1"

With one version live the header is a no-op, but sending it now buys you a controlled migration later: when a new version exists, an account can move its default while individual services keep pinning the old one until each is ready. Pin in one place — your HTTP client's default headers — not per call.

What changes without a new version

These are compatible changes. They can appear in v1 at any time, and your integration must tolerate all of them:

ChangeExample
New API endpoints/v1/disputes appearing alongside existing resources
New optional request parametersA new filter on a list endpoint
New fields in responsesA risk object appearing on the Payment
New event typesdispute.created added to the catalog
New values in open enumsA new payment method id, a new decline_code, a new error code
Longer opaque stringsIds and cursors growing — never parse structure out of them

What never changes inside v1: existing fields are not removed or renamed, types don't change, documented state machines (payment, dispute, KYB) don't lose or reorder states, and error envelope structure stays fixed.

Building tolerant integrations

  • Ignore unknown fields. Deserialize into structures that skip what they don't recognize — reject-unknown-keys parsing is self-inflicted breakage.
  • Handle unknown event types by acking. Return 2xx for event types you don't handle; log them if you're curious. See Webhooks.
  • Default the enum switch. Every switch on a method, decline code, or error code needs a sane default arm — new values arrive without a version bump.
  • Treat ids as opaque. Prefixes like pay_ are a debugging convenience, not a contract. Compare ids byte-for-byte; never derive meaning from length or content.
The OpenAPI document tracks v1 The machine-readable contract at https://api.docs.finscale.dev/openapi.json always describes current v1. If you generate a client, regenerate on your own schedule — additions are safe to pick up whenever you like.