Changelog

Routes, request fields, error codes and prices — the things you would have to change something for. Refactors, performance work and everything else that leaves the surface where it was are not here, on the grounds that a changelog you have to skim is one you stop reading.

Everything below predates the first key we issued, so none of it has ever been a migration for anybody. It is here because the shape of an API is easier to trust when you can see how it got that shape. From here on, a breaking change gets a new prefix rather than a new meaning under the old one.

2026-08-18
added Five routes: /videos, /videos/detail, /links/shorten, /feed, /feed/from

Whole video objects for ids you name, a share-link shortener, and the recommendation feed — both cold and seeded from a video. /videos and /links/shorten are the first two batch-class routes; the rest are lookups.

changed Every route moved under /v1

/tiktok/users became /v1/tiktok/users, and so on for every path. The version prefix is where a breaking change will be visible if one ever has to happen; nothing will change shape underneath it.

added API keys, and four codes for refusing one

Every route but /healthz now takes an Authorization: Bearer sor_live_… key. 401 unauthenticated covers every key problem there is; 403 key_revoked is the one worth telling apart.

added Prices, ceilings, and the codes that enforce them

Each route carries a cost class — lookup, batch or search — and each plan a daily ceiling and a burst limit. New codes: 402 insufficient_funds, 403 not_on_plan, 429 rate_limited, 429 daily_limit_reached, 503 metering_unavailable. A call is charged only when it answers 200; a failure is recorded at $0.00 and still counts against the day.

added 502 upstream_too_large

A response bigger than we will pass through now has a code of its own rather than arriving as a generic upstream_error. Not charged.

2026-08-15
added Six search verticals, and the search_id that pages them

/search/videos, /search/users, /search/music, /search/places, /search/photos and /search/live. Page two and later must carry the first page’s x-tt-logid back as search_id, or the call is refused with 400 search_id_required before it costs anything. Videos, places, photos and live page on offset; music and users page on cursor, and the difference is carried out to the caller rather than smoothed over.

changed Responses became the platform’s own bytes

A 200 now carries the upstream body and content type unchanged, marked with x-sorina-shape: upstream, instead of a projection of ours. Anything reading a reshaped field had to move to the platform’s own name for it.

removed The raw pass-through route

There is no longer any way to hand us an arbitrary upstream path. Every endpoint is a named route with a validated body — which is what makes it possible to price one, test one, and say what it returns.

added /search, and its refusal to fake paging

The all-results tab. It accepts offset: 0 and answers 400 offset_unsupported for anything else, because a non-zero offset starts a fresh search rather than continuing one. Its body arrives framed and is handed back as a JSON array of frames.

added Comments, replies, sounds, playlists

/comments, /comments/replies, /music, /music/videos and /playlists. /comments/replies takes both comment_id and aweme_id: a comment does not identify its own video in that request.

changed GET became POST, everywhere

Named POST routes with JSON bodies replaced query-string GETs. A GET against a named route is a 405. Arguments in a body rather than a URL keeps them out of every access log on the path.

What counts as breaking

Removing a route, removing a request field, or changing what an existing code means. Those get a new version prefix. Adding a route, adding an optional field, or adding a new code does not — write your error handling so an unfamiliar code falls through to a sensible default rather than crashing.

The bodies we pass through are not ours, and we do not version them. A platform can change the shape of its own answer without telling either of us. Where that has already happened, or where we have not seen enough to be sure, the endpoint pages say so rather than guessing.