Technology and Infrastructure → API Versioning
API versioning
1) Why do you need it
Versioning is a manageable way to change contracts between services and customers without breakdowns. In products with a large number of integrations (payments, KYC/AML, games, billing, reporting), "old" and "new" customers live simultaneously. Correct version policy:- reduces the risk of incidents during releases,
- allows you to schedule improvements and safety,
- gives businesses predictable timelines for partner migrations.
2) Classification of changes
PATCH (not breaking): corrections without changing the contract (adding optional fields, validation fixes).
MINOR: back-compatible extensions (new endpoints, fields with default).
MAJOR (breaking): changing the structure, semantics or deleting fields/endpoints.
SemVer'MAJOR is recommended. MINOR. PATCH 'for artifacts (SDK/schemas), while the "external" API number can be simplified (v1, v2).
3) REST versioning models
1. TO URI:
`GET /v1/payments/{id}`
Pros: transparent, cachable, easy to route. Cons: duplication of documentation, more difficult to subtly evolve.
2. In the headers (content negotiation):
`Accept: application/vnd. company. payments. v2+json`
Pros: flexibility, no "garbage" in the URL, convenient evolution of the media type. Cons: it is more difficult to debug in the browser, you need a disciplined client.
3. In custom header:
`X-API-Version: 2` (или `Api-Version: 2025-09-01`)
Pros: just on the sluice. Cons: no standardness, careful with cache.
4. Date-based version:
Good for fintech/reporting: predictable "cuts" of change (e.g. quarterly).
5. Resource/Model Versioning:
Recommendation: for external integrations - 'URI vN' + Rejection/Sunset headers; for internal - you can'Accept 'or the version header, if the gateway and platform support it.
4) GraphQL
Preference - no global versions. Evolution through addition of fields/types and depriction ('@ deprecated (reason:... "")').
Breaking changes - only in "large" windows (versioned schema namespace) with migration guide.
Watch for "n + 1" and do not change the meaning of existing fields.
5) gRPC / Protobuf
Field numbers are immutable. Mark the deleted fields as' reserved '.
Add fields as optional with safe default.
Use buf breaking/lint for automatic compatibility checking.
Version packages/modules: 'package payments. v1;` → `payments. v2`.
6) Event APIs (EDA)
The event scheme is the same contract. Store it in the Schema Registry (Avro/JSON-Schema/Protobuf).
Topics and versions: 'payments. v1. authorized`, `payments. v2. authorized`.
Breaking changes - a new type of event or a new topic.
Evolution guarantees: backward-compatible for consumers during the LTS period.
7) Depriction Policy and EOL
Implement transparent rules:- Deprecation: labels in changelog and in specifications (OpenAPI/GraphQL SDL), header
- 'Depression: true'and when possible' Sunset: Tue, 31 Mar 2026 00:00:00 GMT '.
- Communications: email/partner portal, webhooks notifications, release notes.
- Terms: MINOR - 3-6 months of support, MAJOR - 9-18 months (depending on criticality).
- Time windows: fix in the "API Versioning Policy."
8) Routing and Releases
Gateway API (Kong/Apigee/Nginx/Envoy): rules by prefix '/v1/', by header or mediatype.
Example route:
if ($http_accept ~ "vnd.company.payments.v2") { proxy_pass http://payments-v2; }
Canary/Blue-Green/Shadow: roll the new version on 1-5% of traffic, compare metrics and logs of contract errors.
Feature Flags: Hide behavior without changing contract.
Zero-downtime migration: with MAJOR, provide dual-write/read of the data schema.
9) Contract testing and compatibility control
OpenAPI Diff (or swagger-diff) - Check that MINOR/PATCH do not break schemas.
Spectral linting - style, required metadata (version, Deprecation).
Consumer-Driven Contracts (Pact) - ensures that the provider does not break customers.
buf breaking для protobuf.
CI should fall in breaking changes without raising MAJOR.
10) Documentation and SDK
Version the specs: '/docs/api/v1/openapi. json`, `/docs/api/v2/…`.
Generate SDK by version (npm/maven/pypi) with SemVer and changelog.
Mark deprecated methods in the SDK with/Deprecated annotations.
11) Observation by version
Collect metrics separately:- RPS/latency/errors per version ('api _ version' label).
- Endpoint usage maps: Who else is on v1?
- Alerts: "> 10% 4xx due to contract mismatch," "old customers> X% after T-date."
12) Caching and versions
The in-transit version improves CDN cachability.
With header/media versions - carefully with Vary:- `Vary: Accept, X-API-Version`.
- Do not change the semantics of the response in MINOR to break cache keys.
13) Safety
Do not encrypt or stitch the version into the JWT - the version is determined by the request, not the token.
Do not reveal internal assembly numbers. Use "v1/v2" for external messages.
In MAJOR, review validation, limits, PII masking.
14) Migrations and auto-helpers
Publish "Migration Guide v1 → v2": field mapping table, sample requests/responses, edge cases.
We offer linters for clients (CLI) that highlight outdated fields.
For large partners - sandbox with two versions and a test dataset.
15) Anti-patterns
"Eternal v1": lack of deadlines and usage metrics.
Hidden breaking changes in MINOR/PATCH.
"Version in query string" ('? v = 2') - breaks cache and readability.
"One endpoint is one hundred flag values": difficult to test/document.
16) Implementation checklist
1. Selected model (URI/Accept/Header) for external and internal clients.
2. SemVer for specifications and SDK, automatic breaking-check in CI.
3. Deprecation/Sunset policy and communication templates.
4. Gateway routing + canaries, dashboards by version.
5. CDC/Contract tests for critical integrations (payments, KYC, reporting).
6. The documentation/SDK/migration guide is published at the same time as the release.
7. EOL plan with dates and responsible.
17) Examples
17. 1 REST (URI + headers)
Request:
GET /v2/withdrawals/12345
Accept: application/json
Idempotency-Key: 4a1c-…-9f
Answer:
json
{
"id": "12345",
"status": "PENDING_REVIEW",
"amount": {"value": "100.00", "currency": "EUR"},
"limits": {"daily": "500.00"},
"created_at": "2025-10-02T10:00:00Z",
"links": [{"rel": "cancel", "href": "/v2/withdrawals/12345/cancel", "method": "POST"}]
}
Depriction headers (on v1):
Deprecation: true
Sunset: Tue, 31 Mar 2026 00:00:00 GMT
Link: </v2/docs>; rel="successor-version"
17. 2 Content Negotiation
GET /payments/987
Accept: application/vnd.company.payments.v2+json
Vary: Accept
17. 3 GraphQL (Field Depriction)
graphql type Payment {
id: ID!
amount: Money!
status: PaymentStatus!
method: PaymentMethod!
legacyCode: String @deprecated(reason: "Use field `method`")
}
17. 4 gRPC (protobuf)
proto package payments.v2;
message Withdrawal {
string id = 1;
Money amount = 2;
string status = 3; // previously enum, now string with documented values reserved 4; // legacy field removed in v1 -> v2
}
17. 5 Event model
Topics:- `wallet. v1. balance. updated`
- `wallet. v2. balance. changed '(new event with extended schema)
Schemes are stored in Registry, the producer does not publish events with a scheme that violates compatibility.
18) Context iGaming/fintech (practice)
Payments: input v2 for new PSPs where 'status '/' decline _ reason' is extended; on the gateway, mapping v1 → v2 for reporting.
KYC: MINOR adds field 'pep _ screening', clients ignore v1, v2 - requires.
Responsible games/limits: MAJOR changes the limits model (daily/weekly). Double export to reporting before EOL v1.
Reporting to regulators: fixed versions-dates: 'reporting-2025-01'.
19) Mini-policy (example for wiki)
Model: for external APIs - 'URI/vN/'; for internal - 'Accept:... vN + json' or 'X-API-Version: N'.
SemVer: Specifications and SDKs are published as'N. minor. patch`. MAJOR requires RFC/ADR.
Compatibility: MINOR/PATCH - no breaking changes. Breaking → only through MAJOR.
Deprecation/EOL: ≥90-day announcement; Sunset-date in headlines; LTS branch for critical customers.
Control: OpenAPI diff/buf breaking in CI, CDC for key integrations.
Observability: metrics/logs with label 'api _ version'.
Releases: canary 5% ≥ 24h, then in stages to 100% with green metrics.
Result
Versioning is not about "/v2 in URL, "but about the process: explicit rules of evolution, automatic compatibility checks, managed releases and respect for integrations. Enter a clear policy, automate monitoring and observability - and changes will no longer be a threat to the product.