Skip to main content

API Overview

Pry exposes a FastAPI JSON API. All endpoints are documented in the bundled OpenAPI spec (openapi.json in the repo root) and served live at /docs (Swagger UI) when the server is running.

Base URL

EnvironmentBase URL
Local (bare metal)http://localhost:8002
Docker (host)http://localhost:8005
ConfigurablePRY_URL env var

All request/response bodies are JSON. There are 188 registered paths across 46 tag groups.

Authentication

Authentication is enforced by the PryHttpMiddleware and request_authorized. The policy is fail-closed:

  • PRY_API_KEY set → EVERY request (loopback or remote) must send Authorization: Bearer <key> (or an rmi JWT). Requests without a valid credential get 401 Unauthorized.
  • PRY_API_KEY unset → the API is only reachable from the loopback interface (127.0.0.1 / ::1). Every non-loopback request is rejected with 401, so a keyless instance is never exposed to the internet (e.g. when the Docker port mapping is public).
curl -X POST http://localhost:8005/v1/scrape \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-api-key>" \
-d '{"url": "https://example.com"}'

Public paths that skip auth: /health, /live, /ready (liveness/readiness probes).

Proxy/Tor configuration endpoints (/v1/proxy/configure, POST /v1/config, /v1/config/profile/tor) are additionally guarded: remote clients that cannot present the key are rejected.

Rate limits

  • Token bucket per IP, default 120 requests/minute (PRY_RATE_LIMIT_RPM).
  • Exceeding the limit returns 429 Too Many Requests with:
    • Retry-After response header (seconds)
    • x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset headers
    • A body containing retry_after
{
"type": "/errors/rate_limit_exceeded",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit exceeded",
"request_id": "a1b2c3d4e5f6",
"instance": "/v1/scrape",
"timestamp": "2026-08-16T12:00:00.000000+00:00",
"code": "rate_limit_exceeded",
"retry_after": 1
}

Error format

Errors follow RFC 7807 Problem Details, returned by the global exception handler:

{
"type": "/errors/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Invalid or missing API key",
"request_id": "a1b2c3d4e5f6",
"instance": "http://localhost:8005/v1/scrape",
"timestamp": "2026-08-16T12:00:00.000000+00:00",
"code": "unauthorized"
}
FieldMeaning
typeError type URI (/errors/<slug>, or about:blank for 500s)
titleHuman-readable title
statusHTTP status code
detailHuman-readable detail
request_idCorrelation ID (also echoed in the x-request-id response header)
instanceThe request URL that produced the error
timestampISO 8601 UTC timestamp
codeMachine-readable slug of the error

Common status codes:

CodeMeaning
400Bad request (invalid input)
401Unauthorized — missing/invalid API key, or remote client with no key set
403Forbidden
404Not found (unknown path)
409Conflict
422Validation error (Pydantic)
429Rate limit exceeded
500Internal server error (detail is hidden, use request_id)
502 / 503Upstream / service unavailable
402Payment required — only when x402 gating is enabled (see x402 Pay-per-call)

Health & monitoring endpoints

EndpointPurpose
GET /healthService health + cache stats + active sessions
GET /liveLiveness probe
GET /readyReadiness probe
GET /metricsPrometheus metrics
GET /v0/statsBasic stats

Request IDs

Every request gets a request_id. Send your own with the x-request-id header to correlate logs end-to-end; otherwise a UUID is generated.

API groups

The API is organized into tag groups — the most relevant for day-to-day use:

TagKey endpoints
Health/health, /live, /ready
Scraping/v1/scrape, /v1/crawl, /v1/map, /v1/batch, /v1/ultimate-scrape, /v1/detect-block
Extraction/v1/extract, /v1/extract/css, /v1/extract/llm, /v1/parse, /v1/shadow-dom, /v1/schema
Automation/v1/automate, /v1/screenshot, /v1/session/*, /v1/capture/*
x402/v1/x402/pricing, /v1/x402/pay, /v1/x402/verify, /v1/x402/payment, /v1/x402/require-payment
Batch/v1/batch, /v1/batch-file
Monitoring/v1/watch, /v1/monitor, /v1/freshness/*, /v1/diff
Analysis/v1/vision, /v1/summarize, /v1/categorize, /v1/compare
Sessions/v1/session/create, /v1/session/save, /v1/session/restore, /v1/session/destroy, /v1/sessions
MCP/mcp/tools, /mcp/call (see MCP Integration for the supported transports)

Next steps