Compatibility & changelog
There is one version: the v1 in every path, in the OpenAPI document's info.version and in every webhook body's apiVersion. Inside it the API only grows; anything else is announced here first and runs beside what it replaces. There is no version header to negotiate and no version pinned per account.
Additions are not announced
Each of these is a minor change, and ships without notice:
- a new field in a response, in a webhook event's
dataor in its envelope; - a new value of an enum the service sends — a job or item
status, an errorcode, a webhooktype, an op or a model in the catalogue; - a new endpoint, a new optional request field or query parameter.
So a client ignores fields it does not know and tolerates enum values it does not know: an unknown code is handled by the retryable that comes with it (error codes), an unknown job status as "not settled yet", an event type it does not handle is answered 2xx and dropped. A typed client that switches exhaustively over a generated union keeps a default branch — the union grows.
Breaking changes are announced, and run side by side
Removing or renaming a field, a code, an event type or a route, changing a field's type or its unit, and making an optional request field required are breaking. Inside v1 one happens only this way:
- The new shape is added beside the old one — a new field next to the field it replaces, a new route next to the route — and the two run side by side for at least 90 days. Where the two cannot coexist, the change is announced 90 days ahead instead.
- For those days a response that still carries the old shape says so:
Deprecation(RFC 9745, the date it was deprecated) andSunset(RFC 8594, the date it goes) headers, withLink: <…/docs/changelog>; rel="deprecation"; the OpenAPI document marks the old field or operationdeprecated. A webhook event is not a response and carries no headers: a key of its data that is going is marked in the OpenAPI document and announced in the changelog. - The change is an entry in the changelog below the day it is announced, with the date the old shape goes. The SDKs' own CHANGELOGs link their breaking entries here.
What you send
A field in a request body that the service does not know is ignored, not refused — a client newer than the service still gets an answer, and the field has no effect until the service knows it. Check a new field with a dry run before relying on it. Two things are checked by name instead: an op's or a model's parameters — an unknown key is 400 invalid_param, because a misspelt parameter would otherwise run the op with its default — and a field that was removed when ignoring it would do something different from what its sender asked (mode on POST /jobs is 400 invalid_param).
Changelog
Newest first.
· deprecated · Asset times become ISO-8601 strings
An asset's createdAt, updatedAt, expiresAt and takenAt, a list row's createdAt and expiresAt, a collection's lastCreatedAt and a preview URL's expiresAt are epoch milliseconds today; every other time in the API is an ISO-8601 string. On the date below they become ISO-8601 date-time strings ("2027-01-12T09:30:00.000Z"): the same names and the same instants, a string instead of a number. The two cannot run side by side under one name, so this is the 90 days' notice. The takenFrom, takenTo, createdFrom and createdTo query parameters of GET /api/v1/assets keep taking both spellings. The SDKs, the CLI, the MCP server and the n8n node switch with the API. Goes on 2027-01-12.
· deprecated · A failed row is an ItemError: stage-upload's failure, an import's failures
POST /api/v1/assets/stage-upload answers a file it will not stage with failure — {code, message, retryable, param}, the fields of an error: unsupported_format, payload_too_large or invalid_param on fileSize. POST /api/v1/presets/import and /api/v1/templates/import list each refused entry in failures, with its index and the same fields. The sentences they had — stage-upload's error, the imports' errors — stay beside them until the date below, then go: read failure and failures. The AssetError schema is now named ItemError (same fields, plus an optional param); the JSON did not change, generated type names did. Goes on 2027-01-12.
· deprecated · Webhook events: the job's names; jobId on a job event, creditsCharged and itemIndex go
Event data now names each fact as GET /api/v1/jobs/{id} does, with the same value: id beside jobId and actualCredits beside creditsCharged on the job events, index beside itemIndex on the item events. New and staying: cancelledItems on the job events, op on all four. The old names go on the date below; an item event keeps jobId, its job. Goes on 2027-01-12.
· deprecated · GET /api/v1/ai-models: camelCase names, params; the snake_case names, parameters, supported_parameters and created go
Each model now carries camelCase names beside the old snake_case ones — providerPrice, providerPriceRange, maxInputEdge, maxInputImages, inputModalities, outputModalities, contextLength, promptPrice, completionPrice, imageRequired; image_price_range is priceRange and support_structured_output is structuredOutput — and params, the parameters it takes in the shape of an op's params (name → type, enum, min, max, default, title, description). The old names, parameters, supported_parameters (the keys of params) and created (a constant, never a date) are deprecated: every answer carries Deprecation and Sunset headers until they go. Goes on 2027-01-12.
· added · Webhook events carry apiVersion
Every webhook body has "apiVersion": "v1" beside its type — the version of the body's shape, the v1 of the paths. Nothing else in the body changed.
· added · The compatibility rules are published
What may change inside /api/v1 without notice, and how a breaking change is announced — the rules at the top of this page.