Free plan

Authenticating with the API

How to add credentials to API requests and understand the error responses the API returns.

The EveryPage API uses Bearer token authentication: include your API key or OAuth token in the Authorization header of every request. The /api/v1/ prefix is not just a version marker—it is what selects the permissive, credential-less CORS policy (so the API is callable from any origin) and the exemption from the same-origin CSRF check. Nothing under /api/v1/ authenticates by session cookie.

Bearer tokens and token lanes

The API accepts two kinds of bearer tokens, distinguished by their prefix:

API keys begin with ep_live_ and resolve to the wildcard scope *, so they pass every scope check and carry full account access. They cannot be narrowed. Use them for your own scripts and server-side integrations.

OAuth access tokens begin with ep_at_ and carry only the scopes granted at authorization. Use them for third-party apps whose access should be limited—for example, an integration that only uploads documents holds files:write and not readership:read.

Both arrive in the same Authorization: Bearer <token> header, and the prefix is what selects the lane. A token with neither prefix, or one that is unknown, revoked, or expired, is rejected with 401—there is no fallback that could grant unintended access.

Making a request

curl https://everypage.co/api/v1/files \
  -H "Authorization: Bearer ep_live_..."

GET /api/v1/files lists the files on your account and needs the files:read scope. Replace ep_live_... with your own key; OAuth tokens use the same header with the ep_at_... prefix.

HTTP status codes

The API returns standard HTTP status codes. This table covers the most common ones and what they mean in this API:

CodeNameMeaning
200OKRequest succeeded. The response body carries the result. This includes POST /api/v1/files and POST /api/v1/files/import—uploads answer 200, not 201.
201CreatedReturned by POST /api/v1/webhooks and POST /api/v1/files/{uuid}/variants.
400Bad RequestThe request is malformed or violates a constraint (e.g. not a PDF, malformed body, unknown type on the events feed).
401UnauthorizedThe Authorization header is missing or malformed, or the token is unknown, revoked, or expired.
403ForbiddenYour OAuth token lacks the required scope (insufficient_scope: requires <scope>); your plan does not include the feature (This feature requires the pro plan or higher); or you do not own the target file on a write or readership endpoint.
404Not FoundThe identifier does not resolve. It is also returned deliberately in place of 403 where a 403 would confirm that a document exists: GET /api/v1/files/{uuid} answers 404 for a file you do not own, and the manage-token settings and content lane answers 404 once a file has been claimed. Note the asymmetry—write and readership endpoints answer 403 for a file owned by someone else.
409ConflictThe request conflicts with existing state: the slug you asked for is already used by another of your files, the file was already claimed by a different account, or a concurrent change invalidated a design-lane republish (retry).
410GoneThe link is dead—expired, or burned by its view limit. Both refuse settings changes. POST /api/v1/files/{uuid}/content refuses only expired links: replacing the content is the documented way to un-burn a link.
413Payload Too LargeThe upload or converted result exceeds your plan's size limit.
429Too Many RequestsRate limit exceeded. Wait before retrying.

Send Content-Type: application/json with JSON request bodies; multipart file uploads (e.g. POST /api/v1/files) use Content-Type: multipart/form-data instead.

Identifying documents

Endpoints that address a specific document accept either identifier in the path—both resolve to the same file:

  • UUID: the canonical xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx identifier
  • Short ID: a 12-character base62 code (e.g. aB3xY9kQ2mZ7) that appears in share links

Vanity slugs are not accepted by the API. A slug resolves only on its owner's active custom domain, on the viewer surface; API calls must use the UUID or the short ID. See Share links and short IDs for the identifier rules.

Rate limiting

Requests to /api/v1/ are limited to 120 per minute, keyed on the value of the Authorization header—so the bucket is per token, and integrations sharing an egress IP do not share a budget. Over the limit the API returns HTTP 429.

POST /api/v1/webhooks/{uuid}/test carries an additional 10-per-minute limit on the same key.

If a 429 is returned, wait before retrying; exponential backoff (e.g. 1s, 2s, 4s) is a reasonable strategy.

Error responses

Branch on the status code, not the body. Error bodies are not a uniform contract. The authentication, scope, plan, and ownership errors are returned as plain text (Content-Type: text/plain; charset=utf-8) containing a single message line, for example:

insufficient_scope: requires files:write

Some handlers—notably the import, conversion, and claim lanes—return a JSON object instead:

{ "error": "The converted PDF is larger than your plan allows" }

Known messages worth matching on: Missing or malformed Authorization header and Invalid or expired token (401), insufficient_scope: requires <scope> (403, OAuth tokens only), and This feature requires the <plan> plan or higher (403, plan gate).

API reference

This article covers the conventions common to all routes. For the endpoint listing, see:

  • OpenAPI schema — the machine-readable specification (YAML; consumable by Swagger UI, Postman, and SDK generators)
  • Developers page — operation summaries

Next steps