ProofQL support
Overview
Semantic search over a business's reviews, served at the edge.
ProofQL API 1.0.0
Section titled “ProofQL API 1.0.0”ProofQL turns a business’s reviews into a semantically searchable corpus so
a website can show the reviews relevant to each page. This document covers
the public /v1 API: pushing reviews in, managing them, and querying them.
Conventions
- JSON everywhere (
Content-Type: application/json). Field names aresnake_case. Timestamps are ISO 8601 / RFC 3339 in UTC. Ids are UUIDs. A request body with any otherContent-Type(or none) is a415 unsupported_media_type, refused before it is read. - Versioned by path prefix (
/v1). - Every response carries an
x-request-idheader. Quote it in a support request; it is also inside every error envelope aserror.request_id. Send your own (up to 128 characters ofA-Z a-z 0-9 . _ : -) to correlate with your logs; anything else is replaced with a fresh id. - Every response also carries
X-Content-Type-Options: nosniff,Referrer-Policy: no-referrer, andCache-Control: no-store— except a successfulGET /v1/query, which isCache-Control: private, max-age=0, must-revalidate: it varies by key, so a shared cache must not hold it; the result cache is server-side (x-cache). - Unknown fields anywhere — body or query string — are a
422 validation_failednaming the field, never silently ignored.
Errors
Every non-2xx response is one envelope:
{ "error": { "code": "validation_failed", "message": "…", "doc_url": "https://docs.proofql.dev/errors#validation_failed",
"request_id": "…", "details": [{ "path": "0.rating", "message": "…" }] } }
code is a short, stable string to switch on (the full list is the
ErrorCode schema); message is for a human and may change; details
is present only for validation failures. A request for a route that does
not exist is a 404 not_found in the same envelope.
Keys
Two kinds, both per project, both prefixed so a leaked key’s blast radius is obvious:
| Prefix | Kind | Can | Lives |
|---|---|---|---|
pq_sk_live_… / pq_sk_test_… |
Secret | Everything: ingest, manage, query | Servers only |
pq_pk_live_… / pq_pk_test_… |
Publishable | /v1/query only, CORS-restricted to the project’s allowed origins |
Browsers, the snippet |
Send either kind as Authorization: Bearer <key>. On GET /v1/query a
publishable key may instead ride in the URL as ?key=pq_pk_… (the
snippet’s form); on POST /v1/query a ?key= is a 401 unauthorized,
and secret keys are never accepted from the URL on any method (URLs land
in logs and referrers). A publishable key on a secret-only route is a
403 forbidden. A test key reads and writes only test rows of its
project; a live key only live rows.
Rate limits
Every authenticated request is counted against its key: 300 requests
per 60 s for a secret key, 120 per 60 s for a publishable key. Every
authenticated response advertises the limit in RateLimit-Policy and
RateLimit-Limit (IETF draft ratelimit headers); a refused request is a
429 rate_limited with Retry-After. Separately, /v1/query is subject
to the project’s monthly quota of uncached queries (free tier:
50,000); at the quota a cache miss is a 429 query_quota_exceeded with
Retry-After set to the seconds until the next UTC month, while cached
answers keep being served.
CORS
A publishable key is public by design, so the page’s origin is what
scopes it: a /v1/query request with a publishable key must carry an
Origin header that is in the project’s allowed origins, compared as a
whole origin (scheme, host, port; no wildcards), or it is a
403 forbidden. OPTIONS /v1/query answers browser preflights. The
snippet’s form — GET /v1/query?key=pq_pk_…&q=… with no custom headers —
is a CORS simple request, so browsers send it without any preflight.
Authentication
Section titled “Authentication”secretKey
Section titled “secretKey”A secret key, Authorization: Bearer pq_sk_live_…. Servers only.
Grants everything: ingest, manage, query.
Security scheme type: http
Bearer format: pq_sk_{live|test}_<32 base62 chars>
publishableKey
Section titled “publishableKey”A publishable key in the Authorization header. Query only; the
request must carry an Origin from the project’s allowed origins.
Security scheme type: http
Bearer format: pq_pk_{live|test}_<32 base62 chars>
publishableKeyQuery
Section titled “publishableKeyQuery”A publishable key in the URL (?key=pq_pk_live_…) — the snippet’s
form, so the browser’s GET needs no custom header and no preflight.
GET /v1/query only: on POST /v1/query any ?key= is a 401
pointing at the Authorization header. A secret key here is a 401.
On GET the Authorization header wins when both are present.
Security scheme type: apiKey
Query parameter name: key