Authentication

One key, every platform. Every route but the health check takes it in the Authorization header, as a bearer token.

authorization: Bearer sor_live_<id>_<secret>

What a key is

Two halves after the prefix: a 16-character id and a 43-character secret, both base62. The id is what we look the key up by, so a call is a primary-key hit rather than a scan of every key we hold. The secret is never stored — only its SHA-256, compared in constant time.

It is printed exactly once, at creation. A lost key is reissued, never recovered; there is nothing on our side to recover it from, which is the point.

The prefix is sor_live_ and deliberately not sk_live_, which belongs to Stripe. Sharing a prefix would make every leak scanner, support thread and pair of human eyes disambiguate two unrelated credentials that look identical at a glance.

authorization: Bearer
sor_live_<16-char id>_<43-char secret>
id — what we look it up by, stored plainly
secret — stored as a hash, never as itself

Bearer only

There is no query-parameter form of this, and there will not be one. A credential in a URL is copied into every access log along the path and leaks out again in the Referer header of whatever the page loads next.

# No. It would be logged by every proxy on the path, and land in
# a Referer header on the way out.
curl "https://api.sorina.sh/v1/tiktok/users?key=sor_live_…"

The two refusals

Authentication gives two answers and no more. A malformed key, an unknown id and a wrong secret all return the same 401 unauthenticated and the same sentence: we can tell them apart and deliberately do not, so probing the endpoint teaches you nothing about whether an id exists.

403 key_revoked is the one distinction worth making. It covers both a withdrawn key and a suspended account, and it is the difference between "retry with a better key" and "stop retrying".

401 {"error":"send a Sorina API key as: Authorization: Bearer sor_live_…",
     "code":"unauthenticated"}

403 {"error":"this API key has been revoked, or its account is suspended",
     "code":"key_revoked"}

Revocation takes up to 30 seconds

A successful lookup is cached for 30 seconds and a failed one for 5. A key revoked in the console therefore keeps working for up to that long rather than stopping mid-sentence. That window is the price of not asking the account database on every single request, and it is why revocation is recorded as a timestamp rather than a delete — the key's usage stays readable after it stops working.

If a key is loose in the wild, revoke it and issue another. Do not wait on the window; the new key works immediately.

What a key carries

Keys are issued per account, and a key carries that account's plan, its daily ceiling, its burst limit and its balance. Several keys on one account share all four — a key is a way to tell your own services apart in the usage table, not a way to give one of them its own allowance.

What those ceilings are, and what happens when you reach one, is on billing and limits.