Versioning
What we may change without warning, and what we may not.
The version is in the path. Everything served under /ext/v1 keeps its
promises for as long as v1 exists.
https://api.shopdeskbd.com/ext/v1/ordersThere is no version header, no date pinning per request, and no account-level version. One product team and a modest surface do not justify that machinery — a path segment is the whole strategy, and it is legible from a log line.
There is no shorter /v1 alias either. One was planned and never deployed;
it has been dropped, so /ext/v1 is the base path for the life of v1.
What we may change inside v1
These are additive and can ship any time. Your integration must tolerate them.
| Change | Example |
|---|---|
| A new field on an existing object | An order gains delivery_window |
| A new endpoint | GET /ext/v1/returns |
| A new query parameter or filter | updated_after arriving on customers |
| A new value in an existing enum | An order status we do not have today |
A new error code | A more specific failure than the one you get now |
| A new webhook event type | An endpoint subscribed to * starts receiving it |
What we will not change inside v1
These are breaking and require a new major version:
- Removing a field, or renaming one
- Changing a field's type — a money string will never become a number
- Changing what a field means while keeping its name
- Removing an endpoint or a query parameter
- Removing an enum value
- Making an optional parameter required
- Changing the meaning of an HTTP status or an error
code
That last rule is why INSUFFICIENT_STOCK and INVALID_STATUS_TRANSITION
stay 400 — not 422 like other validation failures — for as long as v1
exists. See Errors.
A v2 would mount beside v1 at /ext/v2, never over it. v1 does not change
underneath you the day v2 appears.
Writing an integration that survives
- Ignore fields you do not recognise. Never validate a response against a closed schema that rejects unknown keys.
- Default-branch every enum. See the warning above.
- Do not depend on field order, or on the absence of a field.
- Do not depend on the exact wording of
message. Branch oncode. - Do not parse ids. They are opaque strings. Their format is not a contract, and code that assumes a shape will break when a resource adopts a different one.
- Do not assume a field is missing forever because it is
nulltoday.
Deprecation
If something in v1 ever has to go, it goes slowly and loudly:
- Announced in the changelog with the replacement and a date. Behaviour changes that are not breaking are announced there too.
Deprecation,SunsetandLinkheaders appear on every response from the affected endpoint, so your logs can tell you that you are using something on the way out even if nobody read the changelog.- At least twelve months between the deprecation and the shutdown. The server refuses to start with a shorter window, so this is enforced rather than remembered.
HTTP/1.1 200 OK
Deprecation: @1790812800
Sunset: Fri, 01 Oct 2027 00:00:00 GMT
Link: <https://www.shopdeskbd.com/developers/changelog>; rel="deprecation"; type="text/html"| Header | Format | Meaning |
|---|---|---|
Deprecation | @ + Unix seconds (RFC 9745) | When the endpoint was, or will be, deprecated. |
Sunset | HTTP date (RFC 8594) | After this moment the endpoint may stop answering. |
Link | rel="deprecation" | The changelog entry naming the replacement. |
All three are readable from a browser (they are in
Access-Control-Expose-Headers). A breaking change is only ever delivered as a
new major version, mounted beside v1, with v1 kept running for the whole
overlap.
Nothing is deprecated today.
The version tag
Responses and this documentation carry a date-based version tag — currently 2026-08. For the REST endpoints it is informational: the path segment is what governs compatibility.
For webhooks it is load-bearing. Each webhook endpoint
is pinned to a version when it is created, and nothing afterwards changes
it — not editing the endpoint, not rotating its secret. A change to payload
shape mints a new date tag, and existing endpoints keep receiving the shape
they were built against. Every delivery states its version twice: in the
X-Shopdesk-Api-Version header and as api_version in the body.
Event names are governed by a stricter rule still: they are additive forever. A new event type is a new name, and an existing name is never renamed and never changes meaning — a rename would be a silent outage that no deprecation header could reach, because merchants subscribe by string. See the event catalog.
What is not covered by any of this
Data is not a contract. A store can rename a product, archive a category or change a price at any moment; a status your integration has never seen may appear because a merchant started using a workflow they had not used before. Versioning governs the shape of the API, not the values flowing through it.
Rate limits are also outside the versioning promise — they are plan
configuration, and a higher plan changing your quota is not a breaking change.
Read the limit from X-RateLimit-Limit rather than hard-coding it.