Errors & envelope

Every response — success or failure — uses the same JSON envelope, so a client only ever needs one code path for "did this work."

Success envelope

{
  "success": true,
  "data": { "…": "…" },
  "meta": {
    "request_id": "0198f3a2-…",
    "units_charged": 1,
    "pagination": { "next_cursor": "…", "has_more": true },
    "freshness": { "corpus_last_event_at": "2026-08-01T04:12:09Z" }
  }
}

pagination and freshness are only present where applicable to the endpoint.

Error envelope

{
  "success": false,
  "error": {
    "code": "quota_exceeded",
    "message": "Monthly quota of 500 units used.",
    "details": { "period_end": "2026-08-31", "upgrade": "https://crawlpipe.com/pricing" }
  },
  "meta": { "request_id": "…" }
}

Check success first — never infer failure from HTTP status alone, and never parse error.message for logic (it's for humans; branch on error.code).

Error codes

HTTPCodeWhen
400validation_errorBad params — see details.fields
401invalid_keyMissing, unknown, or revoked API key
402payment_requiredx402 endpoint without payment, or a past-due subscription
403feature_not_in_plane.g. semantic search on the Free plan — see details.required_plan
403insufficient_scopeKey lacks the required scope — see details.required_scope
404not_foundNo matching resource
409idempotency_conflictSame Idempotency-Key, different request body
422unprocessablee.g. an at= date before the document existed
429rate_limitedPer-minute limit hit — see the Retry-After header
429quota_exceededMonthly unit quota exhausted
429spending_cap_reachedOrg spending cap hit
500internal_errorUnexpected server error — never leaks internals

Headers on every response

X-Request-Id, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (unix timestamp). Metered successes additionally return X-CrawlPipe-Units-Charged and X-CrawlPipe-Units-Remaining — see Metering & idempotency.

Errors & envelope — CrawlPipe Docs