Skip to main content
The content endpoints do not use your organization API key. They take a content key, a fourth credential type alongside the three on Authentication: You create, rotate and revoke content keys in the console, on the integrations page, along with the list of origins each key may be used from.

The key is publishable

The key ships in your website’s source, where anybody can read it. That is intended, not an oversight: a browser fetching articles on your public site cannot hide a secret, so the key is not treated as one. It is returned in full at creation and remains viewable in the console afterwards. What makes that safe is the per-key origin allowlist. A request is served only when its Origin matches an origin you registered for that key, so a copy of the key lifted from your page is of no use anywhere else. Rate limiting is the second control. Key secrecy is not a control at all.
Do not put an org_ organization API key in a web page in order to read articles. It would not work here (the content endpoints accept ck_live_ keys and nothing else) and it would expose your whole partner API surface.

Presenting the key

The key travels as the key query parameter, the same transport POST /v1/track uses, because a <script> tag can build a URL and cannot always set a header:
There is no organization id anywhere in the request. The key resolves to exactly one organization, so a key can only ever read its own club’s articles.

Naming a reader

Add user_id to either article endpoint when the response should be evaluated for a member:
The value is the member’s platform user id, not an id from your own database. It must be a UUID. An empty or whitespace-only value is treated as if user_id was not sent. Reader naming is an opt-in on each content key and is off by default. A platform operator enables it for the key that should receive member-specific answers. A key with the setting off treats user_id as absent, so the response is the strictest answer for a gated article. The platform enforces the tier decision and withholds the article body when the resolved reader does not qualify. The identity is asserted by the integrator: the platform does not verify that the caller is the person represented by the supplied id. It only resolves that id to an active member of the key’s organization. A missing reader, an unknown id, a member in another organization, or an inactive member receives the strictest answer, which is the locked response for a gated article. When a request names a reader, a successful response is sent with Cache-Control: no-store, including when reader naming is disabled or the id does not resolve. This keeps one member’s tier result out of another response’s cache. Anonymous successful responses keep Cache-Control: private, max-age=60; refusals carry no cache header.

The Origin header is required

Every request must carry an Origin header naming a registered origin. This holds for server-side callers too: there is no exemption for a request that is not from a browser, because an exemption would make every published key readable from anywhere. Browsers set Origin themselves. If you call these endpoints from your own backend, set it explicitly, as the curl example above does. Matching is on the whole origin (scheme, host and port), after lowercasing and dropping default ports. https://www.yourclub.example and https://yourclub.example are different origins; register both if you serve both. There are no wildcards. A development origin is an entry like any other, so register it too while you are building: http://localhost:5173 is http, not https, and its port is part of it, so it matches nothing you registered for the live site. Add the one your dev server actually prints, port included, and drop it from the allowlist when you are done.

Rotation takes effect immediately

Rotating a key revokes the previous token in the same operation. The old token stops working on the next request, with no grace period. Deploy the new key to your site before you rotate, or expect a gap.

Cross-origin requests

The endpoints answer a CORS preflight from any origin and echo the request origin back on the real GET, including on refusals. A preflight carries no key, so there is nothing to enforce it against; the allowlist is applied to the actual read. The practical consequence is a good one: a request from an unregistered origin fails as a readable 403 your code can log, rather than as an opaque browser CORS error.

What each failure looks like

Every response below is the standard error envelope, and code is the stable part. Refusals carry no Cache-Control header.

No key, an unknown key, a revoked key, or a key of another type

All four are the same 401, on purpose: a prober cannot learn which check failed, or whether a given token ever existed.

An origin that is not on the key’s allowlist

403, whether or not the key itself was valid. A missing Origin header, an empty allowlist and a non-matching origin all land here.

The content module is not installed

Also a 403, with a different message. The club’s articles still exist; the API is switched off until the module is reinstalled.

Too many requests

Rate limiting is per key, shared across both endpoints, at 600 requests per minute in a fixed window.
The full error list, including validation and not-found responses, is on Articles.