Skip to content

Page Lookout API version 1.2.0

Errors and limits

The error body

Every failure - whatever the status - answers the same JSON shape:

{
  "statusCode": 422,
  "error": "Unprocessable Entity",
  "message": "Scanning is disabled for this site.",
  "correlationId": "4f9c2a51-7d0e-4c3b-9a58-2b61f0d3e7aa",
  "path": "/organizations/11111111-1111-4111-8111-111111111111/domains/22222222-2222-4222-8222-222222222222/scans",
  "timestamp": "2026-09-24T10:00:00.000Z",
  "details": { "reason": "scanning_disabled" }
}
FieldWhat it is
statusCodethe HTTP status, repeated
errorthe status's name
messagea sentence for a person. Show it, log it - but do not branch on it: the wording may change
correlationIdthe id this request was logged under, also in the x-correlation-id header. Quote it to support
paththe path that was requested
timestampwhen the failure was answered
detailspresent only on some 4xx answers: the machine-readable half of the refusal. Every member is optional

Branch on details.reason, never on message. The members of details:

MemberWhen
reasonwhy the request was refused, from a closed list - the reasons an API key can receive are below
limit, valuewith organization_limit_exceeded: which of the organization's limits refused (for example maxScanRunsPerMonth) and what it is
activeScanRunIdwith the 409 of a scan start: the run of this site that is already queued or running
fieldErrorswith a 400: messages per query parameter, keyed by the parameter's name
statewith a report download's 409 or 410: pending, failed or unavailable; with an artifact's 410: expired
expiredAtwith expired: when the artifact stopped being kept

Status codes

StatusMeaning for an API keyRetry?
400a path id is not a UUID, or a query parameter is out of range (details.fieldErrors)no - fix the request
401the key is missing, malformed, unknown, revoked or expired, or was issued for another environment. One answer for all of them, on purposeno - check the key
403the key lacks the scope, or no key may make this request (details.reason below)no - use a key with the right scope
404nothing with this id - or it belongs to another organization, which answers exactly the sameno
409a conflict with the current state: a scan already running, a report not ready yet (details.state pending)after the state changes
410gone and not coming back: a report that will never be rendered, an artifact past its retention periodno
422understood but refused: scanning switched off, the site paused, an organization limit reached (details.reason below), or the site's scan policy names only modules that are not available yet (no details.reason)no - not until the limit or setting allows
429the key's per-minute limit (Rate limits)yes - after Retry-After seconds
5xxany other failure - above all a 500, whose message is always "Internal server error"yes - with backoff

Every details.reason an API key can receive

The list of reasons is closed: a new one is an addition to the contract, announced in the changelog. These are the ones the operations an API key can call produce:

details.reasonStatusMeaningWhat to do
api_credential_scope_missing403the key does not hold the scope this operation namescreate a key with that scope
api_credential_not_allowed403no API key may make this request - an operation outside the list, or an artifact that is not a report PDFuse the dashboard for it
api_credential_rate_limited429the key sent more requests this minute than its limitwait Retry-After seconds
scanning_disabled422scanning is switched off in this site's settingsswitch it back on in the dashboard, or skip the site
site_paused422the site is paused by Page Lookout, so no scan of it starts - by hand, with a key or on its scheduleskip the site; contact support to resume it
organization_limit_exceeded422the organization reached one of its limits; details.limit and details.value say which and whatwait for the window to pass, or contact whoever manages your plan

Treat a reason you do not recognise like the status it came with.

The details.reason list in the API reference is longer than this table: it also holds reasons that only the dashboard's own routes answer - an organization at its limit of site tags (site_tag_limit_reached) or of access groups (access_group_limit_reached), for example. No request an API key can make is refused with them, and the changelog says so. Likewise a separate 409 for a tag name that is already taken may carry details.existingTagId; only the session routes answer it, so a key never receives it. Site tags are read-only for a key: a site's tags come with the site list and the site read (at most 500 per organization), and no request a key can make writes one.

A 422 without details.reason means the site's policy names no module this deployment runs; change the policy in the dashboard.

Rate limits

Each API key may make 60 requests per minute, counted in fixed one-minute windows across all of the API. Every response to a key carries three headers:

HeaderValue
RateLimit-Limitthe requests this key may make per window
RateLimit-Remaininghow many are left in the current window
RateLimit-Resetseconds until the current window ends

Past the limit the answer is 429 with details.reason api_credential_rate_limited and a Retry-After header: wait that many seconds before the next request. The headers, not this page, are the authority on your key's limit.

A few habits keep a client well inside it:

Replacing a key

There is no "rotate" button, on purpose: a replacement is create, deploy, then revoke.

  1. Create a new key with the same scopes on the Integrations screen.
  2. Put it where the old one was, and check that requests with it succeed.
  3. Revoke the old key. Revocation is immediate: the next request with it answers 401.

An organization can hold 10 active keys, which leaves room for the overlap. A key that expires is refused the same way as a revoked one, so set a reminder before its expiry date - or replace it the same way, earlier.