API reference
Authentication
Bearer keys, what each kind may do, and the failures that look like authentication and are not.
Authorization: Bearer sk_…
The key selects the project. No project id appears in any URL, so pointing a deploy at a different project is a change to one environment variable.
Key kinds
sk_…, secret. Server-side only. Reads everything the project serves,
can list every release, and can write. Shown once at creation; we store a hash,
so it cannot be recovered.
pk_…, publishable. Safe in a browser. Restricted to the origins listed
on it, cannot list releases, and cannot write, with one deliberate exception:
the knowledge base vote endpoint.
Full comparison in API keys.
Verify a key
/v1/ping curl https://api.zevcontent.net/v1/ping \
-H "Authorization: Bearer $ZEVCONTENT_KEY"
Confirms the key resolves and names its project. Make this call first when something is not behaving. It separates “wrong key” from “wrong request”, which look identical from a 404.
Failures
| Status | code | What it means |
|---|---|---|
| 401 | unauthenticated | Missing, malformed, unknown or revoked key. Revocation is immediate. |
| 403 | origin_not_allowed | A publishable key used from an origin not on its list. |
| 403 | secret_key_required | A write, or a release listing, attempted with a publishable key. |
The origin check
A publishable key with origins listed is refused from any other browser
origin. The check compares the Origin header, ignoring www., so
https://example.com covers https://www.example.com. Scheme and port are
part of an origin: http://localhost:3000 and http://localhost:5173 are not
the same.
It is best-effort by nature. curl sends whatever it likes, so an allow-list
does not make a publishable key secret. It stops your key powering somebody
else’s site, which is the realistic abuse.
What a key can see
A key sees its project’s published content, and nothing outside that project. There is no endpoint that crosses a project boundary, and an id from another project is not found rather than forbidden, because a “forbidden” would confirm the id exists.
Drafts are never served on /v1, whichever key you hold. A draft article
answers blog_article_not_published or kb_article_not_published, which says
what is wrong rather than pretending the slug does not exist.
Updated at, Wednesday, September 2, 2026