Skip to contentDevelopersPrezly website
API fundamentals

Handling errors

Distinguish empty results from failed requests, inspect error details, and retry deliberately.

Check the HTTP status before reading a response as a successful resource. A 200 response containing "stories": [] is a successful search with no results. A 401, 403, or 422 is a failed request and should not be treated as an empty list.

Start with the status

StatusWhat to do
400 or 422Check the request's JSON, field names, values, operators, and pagination parameters. Read the response details and correct the request before trying again.
401Check the bearer header and whether the credential is invalid, expired, or revoked. See Authentication.
403Check token scopes, endpoint support, account permissions, and newsroom access. Retrying the same request does not grant access.
404Check the resource identifier and your access to its newsroom. A record outside your access may not be visible.
409A write conflicts with the current resource state. Read the endpoint's error and resolve that conflict before retrying.
429Slow down. When present, honor Retry-After before another attempt.
5xxA server or upstream service failed. A read can be retried with a limited backoff; stop and investigate persistent failures.

A transport failure or timeout may have no HTTP response at all. Handle that separately from an API error with a status and JSON body.

Read the error body defensively

Many API errors include status, code, and a human-readable message. Validation errors can also include errors, with details keyed by field name; :global is used for errors not tied to one field.

Not every failure has the same shape. For example, a personal token missing stories:read receives HTTP 403 with this body:

{
  "status": "error",
  "code": "personal_api_token_missing_scope",
  "message": "Personal API token does not grant the required scope.",
  "required_scopes": ["stories:read"]
}

That response has no errors field. Treat optional details as optional, and allow for a non-JSON response from a gateway or an interrupted service. Some older endpoints use numeric error codes; the HTTP status is the first signal, not the type of the body's code field.

For personal tokens:

  • personal_api_token_missing_scope means the token lacks a required scope. Every value in required_scopes must be granted. Create a replacement token with the necessary permissions.
  • personal_api_token_endpoint_not_allowed means the endpoint does not accept personal tokens. Check whether an integration key is appropriate.

Use a machine-readable code for application decisions where available. A message explains the problem to a person and should not be parsed as a stable identifier.

Handle a failed read in JavaScript

This Node.js 22+ example makes one request and reports failures without assuming every response is JSON. Load PREZLY_API_TOKEN as in Your first API request, replace YOUR_STORY_UUID, save as read-story.mjs, and run node read-story.mjs.

const token = process.env.PREZLY_API_TOKEN;
if (!token) throw new Error('Set PREZLY_API_TOKEN before running this script.');

const response = await fetch('https://api.prezly.com/v2/stories/YOUR_STORY_UUID', {
  headers: {
    Authorization: `Bearer ${token}`,
    Accept: 'application/json; content-format=v6',
  },
  signal: AbortSignal.timeout(15_000),
});

const text = await response.text();
let body;
try {
  body = JSON.parse(text);
} catch {
  // An HTTP failure can have a non-JSON body. Still report its status below.
}

if (!response.ok) {
  const code = body?.code ?? 'unknown';
  throw new Error(`Prezly returned HTTP ${response.status} (${code}).`);
}
if (!body?.story) throw new Error('Expected a JSON response containing story.');

console.log(body.story.uuid, body.story.title);

The example intentionally makes no automatic retries. In an application, retain the status and relevant error details so you can decide whether to correct the request, ask for new credentials, or schedule a later attempt.

For cURL, use --fail-with-body to keep the error body visible while returning a nonzero exit code for HTTP failures. Add --include when you need response headers, such as Retry-After. Do not use verbose request logging with a real token in a shared terminal or log.

Retry reads with a bound

For a temporary network failure, 429, or 5xx, retry a GET only a limited number of times, increasing the delay between attempts and adding some randomness. Honor Retry-After when the server supplies it, and reduce concurrency if requests keep being throttled. There is no single request-per-second limit to hard-code for every integration.

Do not automatically retry invalid requests or authentication failures. For writes, a lost response does not prove that the operation failed: it may already have created or changed a resource. Check the endpoint's behavior and the resulting state before repeating a write.

When reporting a problem, include the method, endpoint path, HTTP status, error code, and time of the request. Remove bearer tokens and customer content from logs and screenshots. Keep field validation details only where they can be handled appropriately by your application.

If a list returns no results instead of an error, check filters, pagination, and resource access before treating it as a failure.

On this page