Skip to main content
CanaryVaultsCanaryVaults home
ProductsPricingBlogDocs
Start Free

GET STARTED

OverviewQuickstart

SURFACES

CanaryVaultsCanaryRAGCanaryShieldCanaryHoneypotCanaryAuditCanaryAgent

REFERENCE

API referenceAlerts & webhooksEnterprise & teams

Reference

API reference

Authentication

Product API requests authenticate with a workspace API key sent in the X-API-Key header. Keys look like cv_<id>_<secret> and are minted in the app, at Settings → API keys → Generate API key, on every plan including Free. The full key is shown once at creation and is not recoverable afterwards — copy it there and store it server-side. Five active keys per account; the sixth is a 400.

bash
# Settings → API keys → "Generate API key", then paste it here
export CV_KEY="cv_<id>_<secret>"

# use — every product endpoint accepts the key header
curl -X POST https://api.canaryvaults.com/canaryshield/inspect \
  -H "X-API-Key: $CV_KEY" -H "Content-Type: application/json" \
  -d '{"user_id": "<your-user-uuid>", "user_message": "hello"}'

Revoke on the same card, while the key is still on screen: revocation takes the raw key, not a key id, and there is no list-keys endpoint to recover one from — a key you navigated away from cannot be revoked here. A revoked key stops authenticating immediately; existing sealed records stay valid, and any calls made with the old key remain in the audit trail.

The routes behind that card are POST /api/auth/generate-key and POST /api/auth/revoke-key, and both authenticate with a Supabase session JWT rather than with an API key. That token belongs to the web app — held in memory, with an HttpOnly cookie as its durable half — so it is not something you can export into a terminal. Drive these two from the UI; every other endpoint on this page takes X-API-Key.

Key scopes

Every API key carries a scope list. POST /api/auth/generate-key accepts an optional scopes array (at most 20 entries); omit it and the key is created with ["*"] — access to everything. Scope strings are lower-cased and de-duplicated, entries outside the allowed character set are dropped, and if that leaves nothing the key falls back to ["*"]. The Settings card sends no scopes today, so a key minted there is an ["*"] key; narrowing one needs a scope picker in the UI that does not exist yet.

Scopes are checked on requests that carry X-API-Key. The required scope comes from the path prefix (first match wins, in the order below) and from the HTTP method — POST, PUT, PATCH and DELETE count as writes, every other method as a read.

text
path prefix         read scope           write scope
/api/admin          admin:*              admin:*
/api/audit          profile:read         profile:write
/api/payments       payments:read        payments:write
/api/privacy        privacy:read         privacy:write
/api/threat-events  threats:read         threats:read
/api/threat-log     threats:read         threats:read
/api/canaries       canaries:read        canaries:read
/api/community      community:read       community:read
/api/breaches       breaches:read        breaches:write
/api/dashboard      dashboard:read       dashboard:read
/api/referral       referral:read        referral:write
/api/settings       settings:read        settings:write
/api/workflow-runs  threats:read         threats:read
/api/weekly         threats:read         threats:read
/api/users          profile:read         profile:write
/api/emails         profile:read         profile:write
/api/onboard        profile:write        profile:write
/canaryagent        canaryagent:read     canaryagent:write
/canaryaudit        canaryaudit:read     canaryaudit:write
/canaryshield       canaryshield:read    canaryshield:write
/canaryhoneypot     canaryhoneypot:read  canaryhoneypot:write
/canaryrag          canaryrag:read       canaryrag:write

Two wildcards are accepted: * matches every scope, and <namespace>:* — the part before the first colon, e.g. canaryshield:* — matches both the read and the write scope of that namespace. A path prefix that is not in the table is not scope-gated by this layer; the route still authenticates on its own. A key without the required scope is rejected with 403:

json
{ "detail": "API key does not have required scope." }

Evidence & verification

The evidence log is the spine of the platform. Each record is sealed with a SHA-256 content hash the moment it is written. Re-verify anytime — an edited record fails the hash comparison, and the response shows both hashes so the mismatch is visible.

bash
# export the full sealed log (JSON on all plans; legal PDF export on Pro)
curl "https://api.canaryvaults.com/canaryaudit/export/<your-user-uuid>" \
  -H "X-API-Key: $CV_KEY" -o evidence.json

# re-verify one record by id
curl -X POST https://api.canaryvaults.com/canaryaudit/verify/<log-id> \
  -H "X-API-Key: $CV_KEY"

# → { "verified": true, "tampered": false, "match": true,
#     "stored_hash": "…", "recomputed_hash": "…", "sealed": true, … }

Hand a customer a record id and its hash and they can verify independently — the point is history you can demonstrate, not just assert.

Plan limits, 402s, 429s and the daily backstop

When you exceed a per-month or per-day plan limit, the API returns a structured 402 — never a silent failure. Existing traps keep alerting; only new actions are limited. The body names the metric, your plan, and the limit.upgrade_url is a site-relative path, and per-month quotas also carry used and resets_at (the UTC date the meter rolls over).

json
{
  "detail": {
    "error": "plan_limit_exceeded",
    "metric": "shield_inspections_per_month",
    "plan": "free",
    "plan_display_name": "Free",
    "limit": 10,
    "message": "Your Free plan includes 10 CanaryShield inspections per month and you have used them all. The quota resets at the start of next month, or upgrade at /pricing.",
    "upgrade_url": "/pricing",
    "used": 10,
    "resets_at": "2026-09-01"
  }
}

A metered surface is bounded at three horizons, and only two of them answer 402. The per-month quota and the shorter per-account daily allowance both return the body above; the daily one differs only in carrying resets_at for the next UTC day rather than the first of next month. The per-minute burst limit answers 429 instead, with burst_limit_exceeded as its error, a retry_after_seconds field and a matching Retry-After header. That it is not a 402 is deliberate: you are not out of quota, you are going too fast, and because the burst check runs before either meter a request it turns away has spent nothing and needs no refund.

The daily allowance is also the one meter here that fails closed. Everything else on this page waves a request through when metering itself is unavailable, on the grounds that a metering outage should not take the product down; the daily backstop exists for exactly the case where the others have stopped enforcing, so it refuses instead — 503, with daily_quota_unavailable as its error. It is a 503 rather than a 402 because you are not over any limit: your usage could not be checked, and reporting that as a quota refusal would be untrue. Retry shortly.

Errors & rate limits

Errors use standard HTTP status codes with a JSON detail body carrying a human-readable message (structured bodies, like the 402 above, name a stable error code). Rate-limited endpoints return 429.

text
401  — missing or invalid API key / session token
402  — plan limit reached (see the structured 402 body)
403  — key or token does not own the requested resource
404  — unknown record, honeypot, or endpoint
422  — malformed body (message names the field)
429  — rate limited; slow down and retry
5xx  — transient; retry with backoff

Every response includes a request id in the X-Request-ID header (send your own X-Request-ID to correlate) — include it when contacting support.

Next

Alerts & webhooks →Quickstart →
CanaryVaults

Deception-based AI security. Decoys, trap facts, honeypots, prompt defense, and tamper-evident audit trails — one workspace.

Plant your first canary

PRODUCT

ProductsCanaryAgentDashboardPricingReferralGet started

RESOURCES

DocumentationQuickstartShieldEvidence formatAPIBlog

COMPANY

AboutSecurityReport a vulnerabilityContact

TRUST

Trust centerVerify evidenceStatusChangelogIncidentsDPA

COMPARE

vs Thinkst Canaryvs CanaryTokensFor SaaS teams

LEGAL

TermsPrivacyCookiesSubprocessorsSupport
deception-based AI security© CanaryVaults · canaryvaults.comsha-256 sealed · tamper-evident

CANARYVAULTS