Quick Answer
Keep an unchanged supported client correct, including monetary units, statuses and retries. Choose an explicit selector/default, record API/SDK/event versions separately, test actual consumers and allow one authoritative financial write path during migration. Communicate concrete changes and retirement dates; rollback does not undo money already moved.
Key Takeaways
- Version monetary meaning, errors and retries as well as fields.
- Separate the version selector from its identifier and SDK defaults.
- Additive schema changes require a real compatibility assessment.
- Treat event-destination versions independently from request versions.
- Compare old/new paths without executing duplicate financial writes.
- Retirement and rollback must preserve outstanding financial history.
Keep an unchanged payment client correct#
API versioning lets a payment service evolve while preserving the contract used by existing clients. The contract includes more than JSON field names: amount units, currency, status meanings, errors, pagination, authorization, retry behavior and event delivery can all affect financial correctness. A response can still parse while the client silently records the wrong amount or sends a second payment.
The aim is to make each supported contract selectable, observable and migratable. This guide compares version selectors, explains compatibility with worked examples, and gives a safe rollout sequence. Stripe, J.P. Morgan, GraphQL, Protobuf and HTTP standards provide specific examples checked on October 3, 2026; their release policies should not be generalized to every payment API.
Step 1: Inventory the contracts and their consumers#
Record the synchronous endpoints, webhook destinations, SDKs and schemas used by each integration. Identify the selected/default contract version, account or tenant, client owner and last observed use. Keep internal deployment versions separate from the externally promised contract.
A payment provider’s API version, your public platform API, an SDK package version and a stored-event schema can change independently. Updating a library does not necessarily change a webhook destination’s payload version. Likewise, moving a server to a new deployment does not require a new public API label when the external behavior remains compatible.
Document the source of each default. Stripe’s versioning guide describes account defaults for direct requests, explicit Stripe-Version overrides and SDK-specific version behavior. Recent SDK versions can select the API version associated with their release. Record the effective choice instead of assuming every request always uses the current account default.
Step 2: Choose an explicit version selector#
Choose a mechanism that clients, routing, documentation and observability can apply consistently. Define what happens when a version is absent, unsupported or retired. Treat the selector and the version identifier as separate decisions: a date-based version can be selected through a header.
| Selector | Illustrative request | Tradeoff to handle |
|---|---|---|
| URI path | /v1/payouts | Visible to routing and logs; new paths must still refer to the intended underlying payment resources |
| Custom header | API-Version: 2026-10-01 | Stable URL; forwarding, logs and relevant caches must account for the selector |
| Media type | Accept: application/vnd.example.payout+json;version=2 | Representation negotiation; distinguish response format from the request contract |
| Query parameter | /payouts?api-version=2 | Explicit in the URL; gateways, generated clients and cache keys must preserve it |
These are illustrative choices, not real endpoints or headers promised by Gruv. A header can keep paths stable, while a path can make support traces easier to read. Query selection can be workable where the gateway and clients support it. Select one clear rule per surface and reject contradictory selectors rather than silently choosing whichever component happens to inspect first.
Version labels can be major numbers, semantic versions or named/date-based releases. Semantic Versioning describes major changes for incompatible public-API changes, minor changes for backward-compatible additions and patches for compatible fixes. It is a useful policy when adopted deliberately, not a requirement that every payment provider expose MAJOR.MINOR.PATCH.
Stripe documents named major releases containing breaking changes and monthly compatible versions within those release families. The date alone therefore does not tell you whether a change is breaking. The current guide lists 2026-09-30.endive, but a migration should choose its tested target from the provider’s changelog, not automatically replace every pin with whichever version is newest today.
Step 3: Review both schema and financial behavior#
Compare the promised request, response and event contracts and test the actual consumers. Classify removals, new requirements, type changes and changed meanings as potential breaks. A change is compatible only when supported existing clients remain correct under the published expectations.
| Change | Why an old client can break | Safer path |
|---|---|---|
| Amount changes from minor units to decimal major units | The same numeric value can represent a different monetary amount | New explicit contract with currency/unit semantics and migration |
| Optional request field becomes required | Previously valid requests now fail | Preserve old behavior or provide a new contract |
| New status enum value | An exhaustive client switch can reject it or take an unsafe default | Define unknown-status handling and assess consumer impact |
| Additional response field | Strict validators or signatures over exact payloads can fail | Follow the documented extensibility policy and check consumers |
| Different pagination or filtering default | Clients can miss records without a parsing error | Preserve behavior or expose a deliberate changed contract |
| Changed idempotency scope | A retry can create another financial operation | Assess stored operation identities and provider behavior before rollout |
A genuinely optional field may be a compatible extension for clients that follow the agreed unknown-field policy. That does not mean every addition is harmless: required input, enum values, nullable/default behavior and strict generated clients need attention. Specifications and contract tests help, but they do not prove unchanged settlement or authorization behavior on their own.
Worked example: the same payment through two representations#
Assume a hypothetical v1 response contains amount_minor=1250 and currency=USD, representing $12.50. A proposed v2 response contains amount="12.50", currency=USD and an explicit major-unit definition. Do not rename the field and convert its type inside v1: a client dividing the new value by 100 could treat it as $0.125, while another client might reject the string entirely.
Keep v1’s amount_minor and semantics for v1 clients and expose the deliberate v2 representation to clients choosing v2. Both views should point to the same underlying payment ID and the same $12.50 financial record. Compare their normalized meaning, not byte-for-byte JSON equality. Do not create independent payment objects just because the representation version differs.
Next suppose v2 adds a status named requires_review. A v1 adapter must not translate it to paid to satisfy an old enum. Map only when the old contract can represent the state truthfully; otherwise choose a supported migration or explicit error/availability policy. An adapter that parses correctly while falsely claiming completion is a financial defect.
Currency precision also matters: avoid applying one universal divide-by-100 rule to every currency. State each contract’s monetary unit and currency conventions and preserve exact arithmetic. The example is specifically USD; it is not a provider specification or instruction to convert arbitrary monetary fields without checking their contract.
Step 4: Version events and protect one financial action#
Specify event payload version, identity, object reference, delivery/replay behavior and signature verification for each destination. Preserve the received payload with the version needed to interpret it. Deduplicate deliveries and protect the intended business action across overlapping versions.
Stripe’s upgrade guide separates the server-side SDK version from snapshot event-destination settings; thin event payloads are unversioned. It describes creating and testing a new snapshot destination for a different snapshot version. With both destinations active, subscribed events go to both and handlers need idempotent processing. Do not assume changing an SDK or request header retroactively rerenders every stored event.
For an illustrative payout event delivered through old and new destinations, keep each delivery’s source and schema version but grant one authority to apply the payment’s business effect. Processing the same completed payout twice must not reduce the payable twice. Event IDs alone may not be sufficient if the migration creates different notifications for the same logical operation; retain the appropriate object/action identity and transition context.
Do not suppress every event of one object/type forever. A later refund, return or deliberate state change may be a new legitimate action. Define deduplication for the same delivery and logical effect, while retaining version/revision context. Store sensitive payloads according to appropriate access and retention controls rather than logging bank credentials or raw personal information indiscriminately.
If a callback is late or a request result uncertain, investigate the original operation using the provider’s supported recovery route. Stripe’s idempotency guidance is provider-specific and time-bounded; a durable internal operation record remains important. A new API version does not justify a new key and a new charge for an old unresolved payment.
Step 5: Pilot a read comparison and one authoritative write path#
Validate old and new consumers with representative requests and recorded or synthetic events before routing a controlled cohort. Compare read-only outputs or side-effect-free processing results. Execute each live financial operation through one authoritative path and reconcile its actual outcome.
“Dual run” must not mean issuing the same live charge, refund or payout through both API versions. Replay fixtures without external effects, or compare read-only views of the same underlying record. In the $12.50 example, two representations can be inspected, but there should still be one authorized $12.50 payment and one corresponding financial effect.
Log the requested and effective version, tenant/account, operation ID, provider reference and selected processing path. Monitor parsing failures, unexpected statuses, duplicate-action attempts and reconciliation differences. A low HTTP error rate does not prove that payment amounts and balances are correct. Choose rollout criteria based on the actual failure consequences rather than a universal traffic percentage or thirty-day deadline.
Keep a rollback route for future traffic, but reconcile already-executed operations instead of replaying them after reverting code. An API rollback does not undo a bank transfer, refund, journal or data migration. Preserve identifiers and check old readers can interpret any data written during the new path before claiming rollback is available.
Step 6: Communicate deprecation and retire the right surface#
Publish the affected contract, replacement, breaking changes, migration examples, dates/time zones and support contact. Track client adoption and delayed consumers such as webhook backlogs, batch jobs and reconciliation tools. Retire only under the announced policy with a defined response and recovery path.
J.P. Morgan’s Payments Platform policy uses semantic major/minor/patch versions and active, deprecated and retired states. It says deprecated functionality is typically maintained for eighteen months, while reserving exceptions for critical bugs and legal, security or privacy concerns. This is that provider’s policy, not a universal minimum support period or guarantee that every breaking change waits eighteen months.
Give clients a practical notice: the old and target versions, which requests/events change, the selection method, required SDK changes, example migration, testing options, and the actual last supported time. A retirement notice should distinguish loss of new requests from access to history and outstanding recovery cases. Do not remove evidence needed to reconcile an old payment just because its API version is retired.
RFC 9745 defines the Deprecation response header and links to deprecation information. RFC 8594 defines Sunset for expected future unavailability. They complement human notices; their presence does not automatically migrate a client or prove the exact response after retirement. Deprecation itself does not change the resource’s behavior.
Apply shared compatibility principles with protocol-specific checks#
REST JSON review should cover request/response fields, headers, error/status semantics and version selection. Keep the documented resource identity and authorization stable across representations. Media-type negotiation does not automatically solve a breaking request change, and an API-spec metadata version by itself does not route traffic to another implementation.
GraphQL’s specification supports @deprecated with reasons while deprecated fields can remain selectable. Add a replacement, explain its meaning and observe actual operation use before removal. Review nullability, arguments, enums and resolver behavior against existing queries. A single endpoint or a schema label does not remove the need for compatibility assessment.
Protobuf’s update guidance distinguishes binary wire safety from application-code compatibility and from ProtoJSON. Preserve field numbers and reserve removed numbers/names as appropriate. Adding an enum value can break an exhaustive consumer even when binary decoding remains safe. For gRPC, also review method semantics, errors and generated client behavior; a wire-compatible message change is not proof that an old payment client remains correct.
One owner can maintain shared compatibility and communication rules across these surfaces, while checks remain specific to each protocol. Do not demand one literal versioning mechanism for every interface. Keep examples, consumer evidence and the chosen migration policy together so support can explain what a particular client must change.
A compact release record#
The diagram links the surface, selector, compatibility rule, lifecycle rule and migration evidence. A useful record for one change names the old/target contracts, the actual differences, affected clients, version routing, financial-action protection, pilot result and recovery plan. Update the authoritative docs and changelog alongside the release.
Verify a delayed event, an old SDK request, a refund after the migration and a read of pre-migration history. Those cases exercise time as well as schema shape. Keep operation and financial records linked without treating every request body or personal field as something to retain forever. Versioning succeeds when both the new feature and the old client’s continuing obligations remain explainable.
Frequently Asked Questions
What counts as a breaking change in payment API contracts versus a non-breaking change?
A break can change fields, required inputs, types, amount units, status/error meanings, defaults or retry behavior so an existing supported client no longer remains correct. Additions are compatible only under the published extensibility policy and consumer behavior. An added enum value or strict-validator field can still break a client.
Should we choose URI versioning, header versioning, or query parameter versioning for external clients?
Paths make the selector visible; headers keep URLs stable but require routing/logging and applicable caches to preserve it; query parameters can work with supporting gateways and clients. Media types select representations. Define default, invalid and conflicting-selector handling. Version identifiers, including dates, are separate from the selector choice.
How should we version webhooks so retries and replays remain safe with idempotency?
Record the payload version and destination, verify the delivery and preserve the original event identity. Protect one intended financial action across old/new destinations and deduplicate repeat deliveries without dropping legitimate later transitions. Changing a schema version is not permission to retry a payment as a new operation.
How long should a deprecation window be, and what must a deprecation notice include?
Choose the window from the provider’s policy, contract, client needs and change risk. State the affected and target contracts, concrete differences, selection/SDK changes, migration examples, cutoff with time zone and support route. J.P. Morgan describes a typical eighteen-month period with exceptions; that is not a universal rule.
How do we run REST, GraphQL, and gRPC under one compatibility policy?
Use shared principles for client correctness, ownership and notices, with protocol-specific checks. REST includes fields, headers and behavior; GraphQL includes existing operations, nullability and deprecation; gRPC includes Protobuf wire/code/JSON compatibility and method semantics. Do not force one identical selector or label onto every surface.
What is the minimum governance model we need to avoid versioning debt?
Keep a contract/consumer inventory, owner, compatibility review, supported selection/default behavior, changelog and migration/retirement policy. Protect financial actions through replay and rollout, observe effective versions and reconcile the pilot. Rollback changes future handling; it does not undo already-executed money movement.
Researched and edited by the Gruv editorial team. Gruv builds cross-border billing, payouts, and finance-operations software for global businesses.
Sources
Includes 6 external sources outside the trusted-domain allowlist.
- docs.stripe.com/api/versioningtrusted
- docs.stripe.com/upgradestrusted
- developer.payments.jpmorgan.com/api/versioningexternal
- protobuf.dev/programming-guides/proto3external
- rfc-editor.org/rfc/rfc9745.htmlexternal
- rfc-editor.org/rfc/rfc8594.htmlexternal
- semver.orgexternal
- spec.graphql.org/September2025external
Educational content only. Not legal, tax, or financial advice.
Related Posts

The Freelance Payment Penalty: A Modeled Audit of Platform Fees, FX Spreads, and Payout Delays
The money rarely disappears through a single, easy-to-spot fee. The real loss is stacked. A marketplace takes its commission, a processor adds a charge for international cards, a bank or payment company converts the currency at a spread, a platform holds the funds before release, and a wire sheds a little to intermediaries on the way in. Each layer looks defensible on its own, but the worker feels the combined result as a smaller deposit and a later payday.

How to Respond to a Subpoena for Business Records
Move fast, but do not produce records on instinct. If you need to **respond to a subpoena for business records**, your immediate job is to control deadlines, preserve records, and make any later production defensible.

A US Expat's Guide to Investing in UCITS ETFs to Avoid PFIC Issues
The real problem is a two-system conflict. U.S. tax treatment can punish the wrong fund choice, while local product-access constraints can block the funds you want to buy in the first place. For **us expat ucits etfs**, the practical question is not "Which product is best?" It is "What can I access, report, and keep doing every year without guessing?" Use this four-part filter before any trade:

