ProofSnap API Documentation
The ProofSnap API loads any URL in a browser on ProofSnap's servers and returns a sealed evidence package: screenshot, page HTML, metadata, an evidence PDF and a SHA-256 manifest signed with RSA-4096 and anchored with OpenTimestamps. Base URL: https://api.getproofsnap.com/v1. Authenticate with an API key as a Bearer token. Documentation updated October 2026.
The examples below read the base URL from a shell variable: export PROOFSNAP_API_BASE=https://api.getproofsnap.com/v1
Getting started
-
1
Create an API key
Sign in to the Dashboard, open Developers, then API keys, and create a key. It is shown only once, so store it safely. Keys start with
ps_live_orps_test_. -
2
Request your first capture
Pass the key as a Bearer token. The call returns
202right away with acapture_idandstatus: "processing".curl -X POST "$PROOFSNAP_API_BASE/captures" \ -H "Authorization: Bearer ps_live_..." \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com"}' -
3
Get the result
Poll
GET /captures/{capture_id}untilstatusiscompletedorfailed. A completed capture includespackage_url(a presigned ZIP link valid for up to 24 hours) andmanifest_hash. To get a fresh link, fetch the capture again. Instead of polling, setoptions.webhook_urlto an HTTPS endpoint to receive a signed (HMAC-SHA256)capture.completedorcapture.failedevent.curl "$PROOFSNAP_API_BASE/captures/cap_..." \ -H "Authorization: Bearer ps_live_..." -
4
Verify the package
POST /captures/{capture_id}/verifyre-checks every declared SHA-256 hash and the RSA-4096 manifest signature against the stored files and returnsmatch,modifiedorinvalid. Anyone can also run the scripts in the package'sverification/folder offline, or look up the SHA-256 ofmanifest.jsonin the public ledger withGET /ledger/{hash}. Neither requires an API key.curl -X POST "$PROOFSNAP_API_BASE/captures/cap_.../verify" \ -H "Authorization: Bearer ps_live_..."
Authentication
Send the API key in the Authorization: Bearer ps_live_... header. Keys start with ps_live_ or ps_test_. A live key creates billable captures; a test key creates complete, watermarked evaluation packages that are not billed. A live key on an account with no linked billing account works as a test key. A missing key returns 401 MISSING_API_KEY; an unknown or revoked key returns 401 INVALID_API_KEY. Website Archive keys are read-only (403 PLAN_API_READ_ONLY). Three routes need no key: GET /health, GET /ledger/{hash} and GET /matter-verify.
A new account starts in the sandbox with 50 free test captures. Test-mode usage is limited to 200 units per account per UTC day (429 TEST_MODE_DAILY_LIMIT), packages are watermarked "TEST - NOT FOR LEGAL USE", and include_eidas requires a live key (403 EIDAS_REQUIRES_LIVE_KEY).
Webhooks
Set options.webhook_url per request, or create account-level webhook subscriptions with POST /webhook-subscriptions. Deliveries follow the Standard Webhooks format: the webhook-id, webhook-timestamp and webhook-signature headers (v1, an HMAC-SHA256 computed over the ID, timestamp and body with a whsec_ secret). Event types: capture.completed, capture.failed, capture.anchor_confirmed, certify.completed, certify.failed, redaction.completed, redaction.failed, monitor.change_detected and schedule.paused. capture.anchor_confirmed and schedule.paused go to account-level subscriptions only. Every event is also retained for 30 days in GET /events. A delivery times out after 10 seconds and is retried after 5 minutes, 30 minutes, 2 hours, 8 hours and 24 hours. When you rotate the secret, both the old and the new secret sign deliveries for 24 hours.
Deliveries to a per-request webhook_url are signed with the secret of the API key that made the request. That secret is shown once, when you create the key under Developers in the Dashboard. A subscription has its own secret, returned once when you create it. Verify the signature over the raw body before parsing, reject any webhook-timestamp that differs from your server time by more than 5 minutes and process each webhook-id once. Any Standard Webhooks library does this for you.
Rate limits and errors
Billable requests (POST /captures, /captures/batch, /compare, /captures/{capture_id}/redact and /certify-hash, plus verify, legal holds, export jobs and imports) are limited per account in fixed 60-second windows, shared across all of the account's API keys and its Dashboard session. A batch or a multi-hash certification uses one unit per URL or hash. Units per window: sandbox 10, Developer 60, Startup 120, Growth 300, Legal Solo 60, Legal Company 120, Website Archive 60, Archive only 30. Responses from these routes carry RateLimit-Policy and RateLimit headers plus the legacy X-RateLimit-* headers; a 429 response also includes Retry-After.
Live captures count toward the plan's monthly limit (402 QUOTA_EXCEEDED); requests from an account with a past-due subscription return 402 PAYMENT_REQUIRED. Each account can run only a limited number of captures at once (429 CONCURRENT_CAPTURE_LIMIT). Send an Idempotency-Key header so that a retry within 24 hours returns the original result with Idempotent-Replay: true instead of creating a second capture. Errors are returned as JSON with error.code, error.message and, where useful, error.details; include the X-Request-ID response header value when you contact support. The full list of codes is in the reference below.
Endpoints at a glance
- Captures:
POST /captures,POST /captures/batch(2 to 50 URLs),GET /captures,GET /captures/hosts,GET /captures/{capture_id},PATCHandDELETE /captures/{capture_id},POST /captures/{capture_id}/verify - Review:
POST /captures/{capture_id}/redact,POST /compare,POST /certify-hash(up to 100 hashes) - Automation:
/scheduled-captures(with/runs),/webhook-subscriptions,GET /webhook-events/{capture_id},GET /events,GET /captures/events - Legal:
/matters(seal, export, share),POST /legal-holds,/imports,/captures/export-jobs - Account and public:
GET /whoami,GET /health,GET /ledger/{hash},GET /matter-verify
Full reference
Every endpoint with its parameters, responses and schemas, generated from the OpenAPI 3 specification. Download the specification as openapi.json. There is no official SDK: generate a client with any OpenAPI 3 generator, and verify webhooks with any Standard Webhooks library.