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
Every error under /api/v1/ is an RFC 9457 Problem Details document with Content-Type: application/problem+json. Requests to unknown paths under /api/ get the same shape. For example:
{
"type": "https://everypage.co/docs/developers/authentication#insufficient-scope",
"title": "Forbidden",
"status": 403,
"detail": "insufficient_scope: requires files:write",
"instance": "https://everypage.co/api/v1/files",
"code": "insufficient_scope",
"hint": "Reconnect with a token that grants files:write. API keys (ep_live_) hold every scope."
}
Branch on status or code, never on detail. detail is the human-readable message and may be reworded; code is stable. type links to the matching section below, instance is the request URL, and hint says what to do next. Rate-limited responses also carry Retry-After and the X-RateLimit-* headers; 401 and 403 responses carry an RFC 6750 WWW-Authenticate: Bearer … challenge.
Codes not listed here are derived from the HTTP reason phrase in lower snake case (for example precondition_required) and may be added without notice.
Missing token
401, code missing_token. No Authorization header, or one that is not Bearer <token>. The response carries WWW-Authenticate: Bearer realm="EveryPage API". Create an API key under Account → API keys.
Invalid token
401, code invalid_token. The token is unknown, revoked, or expired. The challenge is WWW-Authenticate: Bearer realm="EveryPage API", error="invalid_token". Rotate the key, or refresh the OAuth access token.
Insufficient scope
403, code insufficient_scope. An OAuth token without the scope the route needs; detail names it (insufficient_scope: requires files:write) and the challenge is WWW-Authenticate: Bearer error="insufficient_scope", scope="files:write". API keys hold every scope and never see this error.
Plan required
403, code plan_required. The feature is above the account's plan; detail names the plan (This feature requires the pro plan or higher). Upgrade at Pricing.
Forbidden
403, code forbidden. Any other refusal: not the owner, a plan limit reached (file count, webhook count), or a manage token used on a plan-gated field.
Validation error
400, code validation_error. Malformed JSON, a missing field, or an invalid value; detail says which.
Not found
404, code not_found. Unknown id, or a file you do not own on routes where 404 replaces 403 to avoid leaking existence. Ids are the file UUID or its 12-character short id.
Method not allowed
405, code method_not_allowed. The Allow header lists the supported methods.
Conflict
409, code conflict. A vanity slug already in use, a file already claimed by another account, or a concurrent content replacement.
Gone
410, code gone. The link is dead: expired or burned. Settings cannot revive it; a burned link is un-burned by replacing its content.
Payload too large
413, code payload_too_large. The upload, the converted PDF, or a JSON body is above the limit for your plan.
Unsupported media type
415, code unsupported_media_type. Reserved; no route returns it today (an unrecognised upload is a 400).
Unprocessable
422, code unprocessable. A Word or PowerPoint file could not be converted to PDF.
Rate limited
429, code rate_limited. Over the 120-per-minute budget for this token (10 per minute on webhook tests). Wait for the number of seconds in Retry-After before retrying.
Internal error
500, code internal_error. Something failed on our side; retrying is safe for reads. Please report it with the instance URL.
Service unavailable
503, code service_unavailable. A dependency (the document converter, Canva key verification) is down. Retry with backoff.
Outside /api/v1/ the shapes differ: /oauth/token returns the RFC 6749 { "error": "…", "error_description": "…" } object, and the public oEmbed and QR endpoints return plain text.
API reference
This article covers the conventions common to all routes. For the endpoint listing, see:
- OpenAPI schema — the machine-readable specification (also at /openapi.yaml; consumable by Swagger UI, Postman, SDK generators, and LLM function-calling bridges)
- 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