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:
| Code | Name | Meaning |
|---|---|---|
| 200 | OK | Request succeeded. The response body carries the result. This includes POST /api/v1/files and POST /api/v1/files/import—uploads answer 200, not 201. |
| 201 | Created | Returned by POST /api/v1/webhooks and POST /api/v1/files/{uuid}/variants. |
| 400 | Bad Request | The request is malformed or violates a constraint (e.g. not a PDF, malformed body, unknown type on the events feed). |
| 401 | Unauthorized | The Authorization header is missing or malformed, or the token is unknown, revoked, or expired. |
| 403 | Forbidden | Your 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. |
| 404 | Not Found | The 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. |
| 409 | Conflict | The 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). |
| 410 | Gone | The 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. |
| 413 | Payload Too Large | The upload or converted result exceeds your plan's size limit. |
| 429 | Too Many Requests | Rate 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-xxxxxxxxxxxxidentifier - 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
- API keys and scopes — create and manage your credentials
- OAuth and oEmbed — grant narrowed permissions to third-party apps
- Webhooks — subscribe to file events via HTTP callbacks
- Events feed — fetch view sessions, downloads, and gate responses
- Share links and short IDs — understand document identifiers