API Versioning¶
The Partners API uses URL-based versioning to provide a stable integration surface while allowing the API to evolve.
Versioning Scheme¶
The API version is embedded in the URL path:
The current version is v1. When a new version is released, it will be available at /api/v2/ while the previous version continues to operate.
When a New Version Is Created¶
A new API version is created when a change would break existing integrations. Breaking changes include:
- Removing an endpoint or HTTP method
- Removing a response field or changing its type
- Removing or renaming a query parameter
- Changing the meaning of an existing field (e.g., a field that was a string becoming an integer)
- Changing authentication or authorization requirements in a way that invalidates existing tokens or scopes
- Changing error response codes for existing error conditions (e.g., a 400 becoming a 422)
- Changing the default behavior of an endpoint (e.g., default sort order, default page size)
Non-Breaking Changes (No New Version)¶
The following changes are considered backward-compatible and will be made to the current version without creating a new one:
- Adding a new endpoint
- Adding a new optional query parameter
- Adding a new field to a response (your client should ignore unknown fields)
- Adding a new optional field to a request body
- Adding a new scope
- Adding a new error code for a previously-unhandled condition
- Improving error messages (the
detailtext may change) - Performance improvements or bug fixes
Warning
Your integration should be built to tolerate additive changes. Always ignore unknown fields in responses rather than failing on them.
Webhook Events¶
The API version and a webhook event's schema version are independent contracts. Bumping one never implies bumping the other.
Beyond's events are thin: data.attributes carries facts about
something that happened (status, completed-at, base-price), and the domain object it
happened to appears only as a relationship — a {type, id} pair plus a links.related
URL you follow to fetch the current state. No event embeds an API resource
representation. So if GET /listings/ renames a field in /api/v2/, no event body
changes: the event never contained a listing in the first place.
Two consequences worth stating explicitly:
- One thing happening emits exactly one event, regardless of which API version
triggered it. If you create a managed account through
/api/v1/or a future/api/v2/, you receive a singleaccount.created. Webhook subscriptions are configured per application, not per API version, and thewebhook-ididempotency contract depends on one occurrence producing one identifier. - An event can fire with no API request behind it at all.
listing.base_price_changedis emitted whenever a base price changes on any Beyond surface — the web app, an internal pricing job, a PMS sync. There is frequently no triggering API version to speak of.
How events are versioned¶
The version lives in the event type, not the envelope. There is no
meta.schema-version, meta.api-version, or any other version field in a webhook
payload. The identity of an event is its type, so a change that a consumer cannot absorb
becomes a new type.
- Additive changes never create a new type. A new attribute or a new optional relationship is backward-compatible. You must ignore fields you do not recognize, exactly as you would for a REST response body.
- A breaking change ships as a new event type with a version suffix — for example
listing.created.v2alongsidelisting.created. Removing or renaming an attribute, changing its type, or changing what an existing field means are all breaking. - The two run in parallel. When a
v2of an event is introduced, the original keeps firing. You migrate your handler for that one event type on your own schedule, test it in isolation, and can fall back to the old type if the upgrade misbehaves — with no effect on any other event. The original type is then deprecated and eventually retired following the Deprecation Policy below: announced ahead of time, run in parallel through the migration window, then stopped.
This is deliberately per-event versioning, not a global one. A v2 of listing.created
does not touch account.created or any other event, so you are never forced to re-test
every handler because one payload changed.
A new enum value is the classic example
Adding a value to a constrained attribute — for example a third status beyond
succeeded and failed — looks additive but breaks a consumer that exhaustively
matches on the current values. This is exactly the kind of change that warrants a new
event type. Even so, treat unrecognized enum values as a case to handle rather than an
error, so a future value cannot take your handler down before you have migrated.
What your consumer must tolerate¶
To stay compatible across every non-breaking change we make, your handler must:
- Ignore unknown fields in
data.attributesanddata.relationships. - Ignore unknown enum values rather than crash on them (see the warning above).
- Ignore event types you do not recognize. Webhook subscriptions are per application,
not per event type — so when we introduce a new event type (including a
.v2of one you already handle), it is delivered to your endpoint immediately. Route onmeta.typeand silently acknowledge (2xx) any type you have no handler for, so a new event never causes a failed delivery and a retry storm.
The one place the two versions touch¶
links.related URLs point back into the API, and today they are /api/v1/ paths:
Treat this URL as a stable locator, not a version declaration. Because our events are
thin, the link never carried a versioned representation — it only tells you where the
object lives. The v1 in it is a routing prefix, not a promise about the payload you get
back; the shape of that payload is governed by the API version you request when you follow
the link, exactly as it is for any other call you make.
So the link does not need to track the newest API version, and it will not be rewritten per
consumer. links.related stays on /api/v1/ even after /api/v2/ ships, and a partner
who has otherwise migrated to /api/v2/ can still follow it — a GET on a /api/v1/ URL
keeps returning the object for as long as v1 is Active.
Deprecation Policy¶
When a new version is released:
- Both versions run in parallel for a migration period
- Deprecation notice is communicated via email and documented here
- Migration guide is provided with a mapping of changes between versions
- Sunset date is announced at least 6 months in advance
Version Lifecycle¶
| Phase | Description |
|---|---|
| Active | Fully supported, receives bug fixes and non-breaking enhancements |
| Deprecated | Still operational, but a newer version is available. No new features. |
| Sunset | Decommissioned. Requests return 410 Gone. |
The current version, v1, is Active.