Rustine docs
Get started

Errors

The error format, when to retry, and every code the API can return.

Open in ClaudeOpen in ChatGPT

An error always has the same shape, whatever the call:

{
  "error": {
    "type": "invalid_request",
    "code": "parameter_invalid",
    "message": "Invalid parameter: limit.",
    "param": "limit",
    "doc_url": "https://docs.rustine.io/api/errors#parameter_invalid"
  }
}
  • type: the category, to know who must act (you, your plan, or Rustine).
  • code: the exact case. This is what your code should test.
  • message: a sentence for a human, in the language of the key’s owner. Log it, do not test it: its wording may change.
  • param: with invalid_request, the parameter at fault.
  • doc_url: the line of this page that explains the code.
  • upgrade_url: with plan_limit, where to change plans or buy a pack.

Every response also carries a Request-Id header: give it to support if an error keeps coming back.

When to retry

  • 429: yes, after the number of seconds in the Retry-After header.
  • 500, 502 and 503: yes, a little later. For a write, send the same Idempotency-Key again: the action will not run twice.
  • 409 idempotency_in_progress: yes, in a moment.
  • Other 4xx: no. The same request will get the same answer; fix it first, or change plans for a 402.

Every code

error.codeHTTPWhat it means
body_invalid400The request body is not valid JSON. Check the Content-Type: application/json header.
cursor_invalid400starting_after is not the id of an item of this list.
idempotency_key_invalid400The Idempotency-Key header must be 1 to 255 printable characters.
parameter_invalid400A parameter is missing or invalid; param names it.
reason_required400Marking a false positive or an accepted risk needs a reason, 10 to 500 characters.
target_kind_invalid400The scan kind does not fit the target: repository for a GitHub repository, quick or audit for a site.
url_invalid400The address is not the valid URL of a public site.
url_private400Rustine only scans public sites, never a local or private address.
authentication_required401No key in the request. Pass it in the Authorization: Bearer rst_… header, never in the address.
invalid_api_key401The key or OAuth token is wrong, revoked or expired. Check it is copied in full, or create a new key.
address_limit_reached402The project already follows as many addresses as your plan allows.
api_plan_required402The workspace is on the Free plan. The API comes with Pro, or on a 14-day trial with Solo.
api_trial_ended402Solo's 14-day trial is over. Move to Pro: your keys work again at once.
audit_not_in_plan402The Free plan runs quick scans only; the full audit comes with Solo and Pro.
audit_quota_exceeded402This period's full audits are used up, and no pack credit is left.
domain_taken402On the Free plan, a domain another free account already follows cannot be added or scanned.
fix_quota_exceeded402This period's fixes are used up, and no pack credit is left. A fix already unlocked stays readable.
plan_limit402Your plan does not include this action. upgrade_url leads to the plan that allows it.
project_limit_reached402All your plan's projects are in use. Add an extra project or change plans.
project_paused402The project is paused: your plan covers fewer projects than your workspace has. Its issues stay readable, but nothing new runs.
repositories_not_in_plan402GitHub repository analyses come with Solo and Pro.
scan_quota_exceeded402This period's quick scans are used up, and no pack credit is left.
scope_missing403The OAuth token lacks the permission this route needs (shown on its page). Reconnect the agent to grant it. An API key has every permission.
fix_locked404The fix of this issue is not unlocked yet: POST /issues/{issue_id}/fix unlocks it.
resource_not_found404Nothing with this id in the key's workspace. An object of another workspace answers the same: its existence is never revealed.
route_not_found404This route does not exist. Check the method and the path in the reference.
conflict409The request does not fit the object's current state. Read it again, then retry.
github_unavailable409GitHub repository analyses are not available right now.
idempotency_conflict409This Idempotency-Key was already used for another request (method, path or body). A new action takes a new key.
idempotency_in_progress409A request with this Idempotency-Key is still running. Retry in a moment.
issue_already_fixed409The issue is fixed: there is nothing to mark.
proof_required409The site must first be proved yours (full audit, fix, marking). Prove it in the app: DNS, file or meta tag.
site_excluded409The owner of this site asked not to be scanned. Rustine will not scan it.
target_exists409The project already follows this address.
rate_limited429Too many requests for this key (120 per minute). Wait Retry-After seconds.
recheck_limit_reached429Too many rechecks on this project today (60 per day). Try again tomorrow.
repository_analyses_limit_reached429The workspace started many repository analyses in the last 24 hours. Try again later.
internal_error500An error on our side, reported automatically. Retry later; give the Request-Id to support if it comes back.
recheck_failed502The recheck could not complete (site unreachable?). Check the site answers, then retry.
platform_busy503Rustine is not starting new scans for a few minutes. Retry later; nothing was charged.
service_unavailable503Rustine is unavailable for a moment. Retry with the same Idempotency-Key.

Types

Test type to decide what to do, code to know exactly what happened.

error.typeWhat it means
invalid_requestThe request itself needs fixing.
authenticationThe key or token is not accepted, or lacks the permission.
plan_limitThe plan or the quota does not allow it; upgrade_url says what to do.
not_foundThe object or the route does not exist for this key.
rate_limitedToo many requests, or a ceiling reached: wait a little.
conflictThe action does not fit the current state (unproved site, key already used…).
api_errorA problem on Rustine's side: retry.

↵ Enter to open, Esc to close