Requests per minute
30 requests/minute sustained (burst: 30). Exceeding returns 429 rate_limited with a Retry-After header.
The InstantProof REST API lets you certify any public URL programmatically. Authenticate with a Bearer API key, POST a URL, and receive a signed certificate PDF with a full evidence bundle β the same RFC 3161 timestamp and Ed25519 signature as the web interface.
Some sites serve bot-protection (a captcha or human-verification check) that can block an automated capture β cookie/consent banners are auto-dismissed and do not block it. We detect a real block on every capture and never bill a blocked one (the API returns 422 bot_protection_blocked with an assistedCaptureUrl). A blocked URL can still be captured with assisted capture, where a person clears the challenge before the page is certified. Test a target domain before you batch.
Three steps from zero to a signed certificate PDF.
Log in, go to Developer β API keys, and click Create API key. Copy the key β it is shown only once.
Send a POST request with your URL:
curl -X POST https://secure.instantproof.legal/api/v1/certificates \
-H "Authorization: Bearer ip_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/page-to-certify"}'
Response 201 Created:
{
"certificateId": "abc123β¦",
"recordingId": "def456β¦",
"url": "https://example.com/page-to-certify",
"finalUrl": "https://example.com/page-to-certify",
"status": "ready",
"links": {
"self": "/api/v1/certificates/def456β¦",
"certificate": "/api/v1/certificates/def456β¦/download"
}
}
Follow the links.certificate URL with your API key. The server returns a 302 redirect to a pre-signed download URL:
curl -L \
-H "Authorization: Bearer ip_live_xxxxxxxxxxxxxxxx" \
"https://secure.instantproof.legal/api/v1/certificates/def456β¦/download" \
-o certificate.pdf
The downloaded PDF is the same signed certificate PDF that the web UI produces, verifiable at /certificate.html.
Base URL: https://secure.instantproof.legal
All endpoints return JSON. Authentication: Authorization: Bearer <key>.
Create a new website certificate. The platform captures the URL in a headless browser, produces a HAR network log and screenshot, signs the manifest with Ed25519, and anchors to a qualified RFC 3161 timestamp. The operation takes 10β60 seconds.
| Field | Type | Description | |
|---|---|---|---|
url | string | required | A valid https:// URL to certify. Must be publicly reachable. |
| Field | Type | Description |
|---|---|---|
certificateId | string | Human-readable certificate ID (shown on the PDF). |
recordingId | string | Internal recording UUID. Use in subsequent API calls. |
url | string | The URL you submitted. |
finalUrl | string | The URL after any redirects, as seen by the browser. |
status | string | "ready" β the certificate is immediately available. |
links.self | string | Path to fetch this certificate's metadata. |
links.certificate | string | Path to download the PDF. Requires auth. |
| Status | error | Meaning |
|---|---|---|
| 400 | invalid_url | The url field is missing or not a valid https:// address. |
| 400 | invalid_json | Request body is not valid JSON. |
| 401 | invalid_api_key | Missing or invalid Authorization header. |
| 402 | api_access_required | Your account does not have the Pro plan. Subscribe. |
| 403 | subscription_required | Web certificates require a flat-rate subscription. |
| 403 | insufficient_scope | The API key lacks the certificates:write scope. |
| 413 | payload_too_large | Request body exceeds 64 KB. |
| 429 | quota_exceeded | Daily API capture quota reached. Resets every day. |
| 429 | rate_limited | Too many requests. See Retry-After header. |
| 429 | service_busy | Capture service at capacity. Retry after ~30 seconds. |
| 502 | capture_failed | The browser could not load the URL. |
| 502 | certification_failed | Capture produced no usable evidence (e.g. empty HAR). |
Retrieve metadata for a certificate you previously created.
| Parameter | Description | |
|---|---|---|
recordingId | required | The recordingId returned by POST /api/v1/certificates. |
| Field | Type | Description |
|---|---|---|
certificateId | string | Human-readable certificate ID. |
recordingId | string | Internal recording UUID. |
type | string | Recording type (e.g. "webcapture"). |
status | string | "ready" once the certificate is available. |
url | string | The URL that was certified. |
createdAt | string | ISO 8601 creation timestamp. |
links | object | self and certificate paths. |
Download the signed certificate PDF. Returns 302 Found β follow the redirect to receive the file. Use curl -L or requests.get(..., allow_redirects=True).
All API requests must include:
Authorization: Bearer ip_live_xxxxxxxxxxxxxxxx
Keys are created at Settings β Developer β API keys. A key authenticates as your account β treat it like a password. Revoke immediately if leaked.
Keys are prefixed ip_live_ for live accounts. The prefix helps you identify them in code or environment files.
30 requests/minute sustained (burst: 30). Exceeding returns 429 rate_limited with a Retry-After header.
The Pro plan grants a fixed number of certificate creations per day. The quota resets every day. Exceeding it returns 429 quota_exceeded.
The JSON request body must not exceed 64 KB. In practice, a URL is well under this limit.
import requests
API_KEY = "ip_live_xxxxxxxxxxxxxxxx"
BASE = "https://secure.instantproof.legal"
# Create a certificate
resp = requests.post(
f"{BASE}/api/v1/certificates",
json={"url": "https://example.com"},
headers={"Authorization": f"Bearer {API_KEY}"},
)
resp.raise_for_status()
data = resp.json()
recording_id = data["recordingId"]
# Download the PDF
pdf = requests.get(
f"{BASE}/api/v1/certificates/{recording_id}/download",
headers={"Authorization": f"Bearer {API_KEY}"},
allow_redirects=True,
)
pdf.raise_for_status()
with open("certificate.pdf", "wb") as f:
f.write(pdf.content)
print(f"Certificate saved ({len(pdf.content)} bytes)")
const API_KEY = process.env.INSTANTPROOF_API_KEY;
const BASE = "https://secure.instantproof.legal";
// Create a certificate
const res = await fetch(`${BASE}/api/v1/certificates`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url: "https://example.com" }),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const { recordingId, links } = await res.json();
// Download the PDF
const pdf = await fetch(`${BASE}${links.certificate}`, {
headers: { "Authorization": `Bearer ${API_KEY}` },
redirect: "follow",
});
const buffer = Buffer.from(await pdf.arrayBuffer());
require("fs").writeFileSync("certificate.pdf", buffer);
# Set your key
export INSTANTPROOF_API_KEY="ip_live_xxxxxxxxxxxxxxxx"
# Create
CERT=$(curl -sf -X POST https://secure.instantproof.legal/api/v1/certificates \
-H "Authorization: Bearer $INSTANTPROOF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com"}')
echo "$CERT" | python3 -m json.tool
RECORDING_ID=$(echo "$CERT" | python3 -c "import sys,json; print(json.load(sys.stdin)['recordingId'])")
# Download
curl -sfL \
-H "Authorization: Bearer $INSTANTPROOF_API_KEY" \
"https://secure.instantproof.legal/api/v1/certificates/$RECORDING_ID/download" \
-o certificate.pdf
ls -lh certificate.pdf
Typically 10β60 seconds, depending on the target page's load time. The POST request blocks until the certificate is ready β there is no polling step.
The current API supports website (URL) certification only. File uploads are available via the web interface at secure.instantproof.legal/certificates/new.
Yes. The PDF produced by the API is identical to one created through the web UI. Drag it onto instantproof.legal/certificate.html to verify the Ed25519 signature and RFC 3161 timestamp chain.
The capture service returns a 502 capture_failed error. Your daily quota is not consumed.
Yes. Every certificate created via the API appears in your Certificates dashboard under My Website certificates, alongside any web-interface certificates.