The live, auto-generated HTTP reference for the Aardvark cloud gateway — rendered inline by the openapi directive on a wide-mode page.
The reference below is the real, user-facing API of the Aardvark cloud
gateway — the metered OpenRouter proxy and dashboard backend behind the
reader assistant. Chat, reader telemetry, dashboard analytics, account and API-key
management, team, billing, and magic-link auth are all here, rendered inline by the
{% openapi %} directive on an ordinary Markdown page set to
mode: wide — no dedicated page generator, just a component.
It also doubles as the headline demonstration of that directive: every operation below is wired into the left-hand nav, with parameter and response tables, multi-language request samples, and a Try it now form. To splice a single endpoint into a page instead of the whole spec, see OpenAPI under Components.
The spec it renders, openapi/aardvark-gateway.json, isn’t hand-written: it’s
extracted from the gateway’s own source — every route’s auth, request fields,
query params, response shape, and error codes — and regenerated on every change, so
this reference can’t drift from the code it documents. (That’s the same drift-proof
loop you’d wire up for your own API.)
Aardvark Gateway API
User-facing HTTP API of the Aardvark cloud gateway — the metered OpenRouter proxy and dashboard backend. Operator-only endpoints (/admin/*, /operator-auth/*, /operator-api/*) and the dashboard / operator SPA shells (/dashboard*, /operator*) are excluded by design.
This document is GENERATED from the gateway source: scripts/gen-openapi.mjs extracts every route’s auth, request fields, query params, response shape, and error codes directly from the handlers, then renders them. Do NOT edit openapi.json (or hand-author its structure) — change the code, and regenerate. Only prose lives in scripts/openapi/descriptions.mjs.
https://gateway.aardvarkdocs.comAuthorization
Public widget key, Authorization: Bearer aardvark_live_… . Origin-scoped. Used in the request samples and Try it now below. Held in memory for this session only.
Metered chat completions.
https://gateway.aardvarkdocs.com/v1/chat/completionsOpenAI-compatible chat-completions endpoint. The gateway authorizes the key, reserves the input cost against the account balance, forwards the request to the configured upstream model, and streams the response back as Server-Sent Events while metering actual spend. System-prompt handling depends on the key mode: for public keys (origin-gated browser/reader-widget keys) the gateway always injects its own system prompt and strips any client-supplied system message; for secret keys (server/CLI/automation credentials) a nonblank client-supplied system message is honored verbatim — so tools such as vark author set their own instructions — and the gateway’s default prompt is used only when the request supplies no system message. The sampling fields (temperature/top_p/frequency_penalty/presence_penalty) are clamped to valid ranges.
Request body
model | string | yes | Upstream model id to forward to. |
messages | array<any> | yes | OpenAI-style message array; must include at least one user message. |
tools | array<any> | no | Tool/function definitions, forwarded verbatim. |
plugins | array<any> | no | Server-side plugins, forwarded verbatim. |
tool_choice | object | no | Tool-choice directive, forwarded verbatim. |
max_tokens | integer | no | Max output tokens (clamped to ≥ 1). |
stop | array<any> | no | Up to 4 stop sequences (string or array); excess is truncated. |
reasoning | object | no | Reasoning controls (effort/enabled/exclude/max_tokens), validated and forwarded. |
temperature | number | no | Sampling temperature forwarded upstream, clamped to [0, 2]; dropped if non-numeric or NaN. |
top_p | number | no | Nucleus-sampling probability mass forwarded upstream, clamped to [0, 1]; dropped if non-numeric. |
frequency_penalty | number | no | Repetition penalty by token frequency, clamped to [-2, 2]; dropped if non-numeric. |
presence_penalty | number | no | Penalty for tokens already present, clamped to [-2, 2]; dropped if non-numeric. |
Responses
Headers
X-Stop-Truncated | string (true) | Present (value true) only when excess stop sequences were dropped to fit the upstream’s 4-sequence cap (the request is served rather than rejected); ABSENT otherwise. Listed in Access-Control-Expose-Headers, so a cross-origin browser client can read it. |
Body
A single string value.
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/chat/completions' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "openai/gpt-4o-mini",
"messages": [
{
"role": "user",
"content": "How do I install the CLI?"
}
],
"max_tokens": 512,
"temperature": 0.3
}'Response examples
"string"Reader telemetry ingest.
https://gateway.aardvarkdocs.com/v1/authoring-telemetryScaffold ingest for a future authoring client. Public-key authed like the other reader beacons; event_type is restricted to letters/digits/‘.’/‘_’/‘-’. Best-effort over the per-account daily cap.
Request body
event_type | string | yes | Event name (≤100 chars). |
detail | string | no | Free-text payload (≤2000 chars). |
Responses
Body
ok | boolean | no | Always true; best-effort ack even when the row is dropped over the daily cap. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/authoring-telemetry' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"event_type": "draft.generated",
"detail": "page=quickstart"
}'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/commentStores a free-text reader comment, optionally tied to a page path and an island-generated survey/question id. Best-effort over the per-account daily cap. page_url must be a safe site-relative pathname or it is stored as null.
Request body
comment | string | yes | Comment text (≤2000 chars). |
page_url | string | no | Site-relative pathname starting with / (≤200 chars). |
survey_id | string | no | Island-generated survey id (≤100 chars). |
question_id | string | no | Island-generated question id (≤100 chars). |
Responses
Body
ok | boolean | no | Always true on accept; best-effort, so true even when the daily cap drops the row. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/comment' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"comment": "The quickstart was great.",
"page_url": "/docs/quickstart"
}'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/engagementPublic-key beacon (migration 0027): the escalation/contact link was SHOWN under a downvoted answer (escalation_shown) or CLICKED (escalation_click). Decoupled from the transcript and subject to a per-account daily row cap; drives the dashboard’s support-deflection metric.
Request body
conversation_id | string | yes | Conversation the event belongs to (≤100 chars). |
kind | string | yes | escalation_shown or escalation_click. |
turn | integer | no | Answer index within the conversation (default 0). |
Responses
Body
ok | boolean | no | Always true on accept; a deduped or over-cap beacon still ACKs 200. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/engagement' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"conversation_id": "c_abc123",
"kind": "escalation_click",
"turn": 0
}'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/feedbackStores a reader's vote on a specific answer turn. Best-effort: over the per-account daily cap the vote is silently dropped but still returns 200. Deduplicated on (account, conversation_id, turn).
Request body
vote | string (up | down) | yes | Thumbs direction. |
conversation_id | string | yes | Client conversation id (≤100 chars). |
question | string | no | The rated user question (≤1000 chars). |
turn | integer | no | Answer index within the conversation (0–10000); out-of-range coerces to 0. |
Responses
Body
ok | boolean | no | Always true; the vote is best-effort, so an over-cap drop still ACKs 200. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/feedback' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"vote": "up",
"conversation_id": "c_abc123",
"question": "How do I deploy?",
"turn": 0
}'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/mcp-telemetryThe docs MCP server posts one beacon per tool call. A short args summary is either supplied (args_summary) or derived from args. Server-side callers (no Origin header) bypass the origin allowlist; browsers must pass it. Best-effort over the per-account daily cap.
Request body
tool | string | yes | Tool name (≤100 chars). |
args_summary | string | no | Explicit one-line args summary (≤200 chars). |
args | object | no | Raw args; summarized when args_summary is absent. |
Responses
Body
ok | boolean | no | Always true on a 200; the beacon was accepted (also when silently dropped over the daily cap). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/mcp-telemetry' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"tool": "search_docs",
"args_summary": "query=install cli"
}'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/ratingPublic-key capture of a reader star rating for a page (migration 0036), optionally with a comment. Best-effort over the per-account daily cap.
Request body
rating | string | yes | Star rating (e.g. 1-5). |
comment | string | no | Optional free-text comment. |
page_url | string | no | Site-relative pathname the rating is for. |
Responses
Body
ok | boolean | no | Always true on accept; best-effort, so true even when the daily cap drops the row. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/rating' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/reach-eventPublic-key beacon (migration 0091): one page-view’s worth of SECTION-level visibility and interaction evidence, posted by /_aardvark/reach.js. Records which of a page’s own semantic sections (heading slugs, target-tag ids, and the synthetic __intro) became at least 50% visible for at least 1 second, how long each was the section under the reader’s trigger line, and counts for a closed five-value action taxonomy. It carries no coordinates, scroll offsets, DOM snapshots, element text, or query text, and no identifier durable beyond one browser tab — so it is visibility and interaction evidence, never a measure of gaze, comprehension, or attention. Unlike the other reader-write endpoints this one is PLAN-GATED to Business/Enterprise (403 plan_required); the gateway is authoritative because a static build holds only the public key and cannot read the account’s plan. Repeat posts of the same (session_id, session_seq) are expected — the client flushes on tab-hide and again on pagehide — and are idempotent, only ever moving stored values forward.
Request body
session_id | string | yes | Per-tab random id from the client’s sessionStorage — NOT a durable visitor id, and deliberately distinct from the search session id so reach data cannot be joined to query text. Rejected rather than truncated above 100 chars, because it is part of the dedup identity. |
session_seq | integer | yes | Page-view ordinal within the tab session (0–10000000). Rejected rather than floored when out of range, for the same dedup-identity reason. |
page_url | string | yes | Site path of the page. Normalized with safePathname, which rejects an off-origin URL and strips query and hash. |
visible_ms | integer | no | Foreground, non-idle time on the page, clamped to 3600000. Excludes time while the tab was hidden and time after 60s without interaction. |
sections_total | integer | no | How many sections the page has — the denominator for reach completion. |
sections | array<object> | no | Sections that qualified OR carried an action, in document order (≤40 per beacon; extras and malformed entries are dropped without failing the beacon). Each entry carries id, ordinal, kind (heading | target | intro), reached (true only after the ≥50%/≥1s hold — action-only rows are false), dwell_ms, and a count for each of copy_code, cta, toc_jump, search_click, expand. The exit proxy is derived server-side from the furthest qualified stored section, not sent. |
sections[]. | string | no | |
sections[]. | integer | no | |
sections[]. | string (heading | target | intro) | no | |
sections[]. | boolean | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
catalog | array<object> | no | Optional. The page’s section CATALOGUE — every measurable section, reached or not, as id/ordinal/kind with no metrics (≤40, same alphabet as sections). sections carries only what happened, so it can never say which sections nobody reached; this can. Sent on a page view’s FIRST flush only, because it describes the page rather than the visit and is stored per (page, section). Omitting it is a no-op, never an error. |
catalog[]. | string | no | |
catalog[]. | integer | no | |
catalog[]. | string (heading | target | intro) | no |
Responses
Body
ok | boolean | no | Always true on accept; a deduped, refreshed, over-cap, or empty beacon still ACKs 200. Two refusals are actionable to the shipped client: 403 plan_required latches Content Reach off for the browser tab, and 429 rate_limited pauses posting for Retry-After (the shared reader-ingest limiter, which every public-key ingest endpoint carries). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/reach-event' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"session_id": "r_abc",
"session_seq": 3,
"page_url": "/guide/install/",
"visible_ms": 41200,
"sections_total": 12,
"sections": [
{
"id": "install-the-cli",
"ordinal": 3,
"kind": "heading",
"reached": true,
"dwell_ms": 9800,
"copy_code": 1,
"cta": 0,
"toc_jump": 1,
"search_click": 0,
"expand": 0
}
],
"catalog": [
{
"id": "overview",
"ordinal": 1,
"kind": "heading"
},
{
"id": "install-the-cli",
"ordinal": 3,
"kind": "heading"
}
]
}'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/search-eventPublic-key batch beacon (migration 0040): the header search box reports settled queries, result clicks, and Ask-AI escalations. Body is { events: [...] }, each event a query, click, or ask_ai. Subject to a per-account daily row cap and dedup; only AI-enabled sites emit. Powers the dashboard’s Search Analytics.
Request body
events | array<any> | yes | Batch of search-activity events (≤20 per request); each is a query, click, or ask_ai beacon. Malformed events are dropped and the batch still ACKs 200. |
Responses
Body
ok | boolean | no | Always true on accept; a deduped, over-cap, or empty batch still ACKs 200. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/search-event' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"events": [
{
"kind": "query",
"session_id": "s_abc",
"session_seq": 0,
"term": "install",
"results": 3,
"latency_ms": 5
},
{
"kind": "click",
"session_id": "s_abc",
"session_seq": 1,
"term": "install",
"position": 1,
"page_url": "/guide/install/"
}
]
}'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/surveyPublic-key capture of a structured reader survey answer (migration 0037) — a single/multi choice or a rating — that the Survey island previously sent only to analytics. Best-effort over the per-account daily cap.
Request body
question_type | string | yes | Answer kind: single, multi, rating, or text. |
answer_value | string | no | The chosen option(s) or text answer (a JSON array string for multi). |
rating_value | string | no | Numeric value for a rating question; ignored for other types. |
survey_id | string | no | Island-defined survey id (≤100 chars). |
question_id | string | no | Island-defined question id (≤100 chars). |
page_url | string | no | Site-relative pathname the survey was answered on. |
Responses
Body
ok | boolean | no | Always true on accept; best-effort, so true even when the daily cap drops the row. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/survey' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/transcriptUpserts one conversation turn (question + answer, optionally the model’s reasoning) keyed on (key, conversation_id, turn). At least one of question/answer is required. Best-effort over the per-account daily cap; an out-of-range turn is rejected rather than coerced.
Request body
conversation_id | string | yes | Client conversation id (≤100 chars). |
turn | integer | no | Answer index within the conversation (0–10000). |
question | string | no | The user's question (≤2000 chars); at least one of question/answer is required. |
answer | string | no | The model's answer (≤16000 chars); at least one of question/answer is required. |
reasoning | string | no | Reasoning/chain-of-thought (≤32000 chars). |
sources | object | no | Doc-page URLs this answer cited; deduped, capped at 20 per turn, fanned out to source_events. |
Responses
Body
ok | boolean | no | Always true; returned on a stored turn or a best-effort ack over the daily cap. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/transcript' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"conversation_id": "c_abc123",
"turn": 0,
"question": "How do I build my site?",
"answer": "Run `vark build`."
}'Response examples
{
"ok": true
}Dashboard analytics.
https://gateway.aardvarkdocs.com/v1/activityHeadline metrics over the last days (default 30, capped at 365): conversation/answer/feedback counts, verdict mix, uncertainty rate, engagement, support-deflection rate, and top languages.
days | query | integer | no | Window length in days (default 30, capped at 365). |
Responses
Body
window_days | integer | no | Resolved look-back window in days (default 30, capped at 365). |
since | integer | no | Window start, epoch-ms (inclusive); until minus window_days. |
until | integer | no | Window end, epoch-ms (exclusive); the request time. |
conversations | number | no | Distinct conversations with at least one stored turn in the window. |
answers | number | no | Total stored answer turns (transcript rows) in the window. |
feedback | object | no | Reader thumbs vote tallies and the derived satisfaction rate. |
feedback. | string | no | Count of thumbs-up votes on answers in the window. |
feedback. | string | no | Count of thumbs-down votes on answers in the window. |
feedback. | string | no | up / (up + down) in [0,1], or null when no votes. |
verdicts | object | no | Analysis-pass answer-quality classification distribution. |
verdicts. | number | no | Turns classified confident by the analysis pass. |
verdicts. | number | no | Turns classified unconfident by the analysis pass. |
verdicts. | number | no | Turns classified not_found (no answer in the docs). |
verdicts. | number | no | Turns classified doc_gap (a documentation coverage gap). |
analyzed | string | no | Turns with any verdict: sum of the four verdicts counts. |
uncertainty_rate | string | no | Flagged (unconfident+not_found+doc_gap) over analyzed, or null. |
engagement | object | no | Escalation/contact-link beacon counts driving deflection. |
engagement. | number | no | Times the escalation/contact link was shown under a downvoted answer. |
engagement. | number | no | Times a reader clicked the escalation/contact link. |
deflection_rate | string | no | 1 − escalation_click / answers, clamped [0,1]; null when no escalations or answers. |
languages | array<object> | no | Top query languages by turn count (max 12, descending). |
languages[]. | string | no | ISO query-language code from the analysis pass. |
languages[]. | integer | no | Turns analyzed in this language during the window. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/activity?days={days}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"window_days": 0,
"since": 0,
"until": 0,
"conversations": 0,
"answers": 0,
"feedback": {
"up": "string",
"down": "string",
"satisfaction_rate": "string"
},
"verdicts": {
"confident": 0,
"unconfident": 0,
"not_found": 0,
"doc_gap": 0
},
"analyzed": "string",
"uncertainty_rate": "string",
"engagement": {
"escalation_shown": 0,
"escalation_click": 0
},
"deflection_rate": "string",
"languages": [
{
"language": "string",
"count": 0
}
]
}https://gateway.aardvarkdocs.com/v1/authoring-analyticsPer-type counts and the most recent authoring events over the last 90 days. Returns clean empty shapes when no rows exist.
Responses
Body
events | array<object> | no | Per-event_type counts over the last 90 days, busiest type first (≤500 types). |
events[]. | string | no | Client-defined authoring event name, e.g. suggestion_accepted. |
events[]. | integer | no | Number of events of this event_type recorded within the 90-day window. |
recent | array<object> | no | The most recent authoring events, newest first (≤50), within the 90-day window. |
recent[]. | string | no | Client-defined authoring event name for this row. |
recent[]. | string | no | Optional free-text payload sent with the event; null when omitted. |
recent[]. | integer | no | Epoch-ms time the event was recorded. |
total | integer | no | Total events over the last 90 days, summed from the per-type events counts. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/authoring-analytics' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"events": [
{
"event_type": "string",
"count": 0
}
],
"recent": [
{
"event_type": "string",
"detail": "string",
"ts": 0
}
],
"total": 0
}https://gateway.aardvarkdocs.com/v1/conversationsRecent turns grouped into conversations, each with the reader vote and (when available) an automated analysis verdict. filter=needs_attention restricts to low-confidence / doc-gap / not-found turns; verdict/intent/vote/q/tag narrow it further.
verdict | query | string | no | Restrict to a single analysis verdict. |
filter | query | string | no | Set to needs_attention to restrict the result (default all). |
intent | query | string | no | Restrict to a single detected intent. |
vote | query | string | no | Restrict to up/down votes. |
q | query | string | no | Free-text search over question/answer. |
tag | query | string | no | Restrict to a custom tag. |
since | query | integer | no | Epoch-ms lower bound; keeps turns with ts >= this (inclusive). |
until | query | integer | no | Epoch-ms upper bound; keeps turns with ts < this (exclusive). |
Responses
Body
conversations | array<object> | no | Recent turns grouped by conversation_id, newest conversation first, turns ascending within. |
truncated | boolean | no | true when more matching turns exist beyond the 100-turn list cap. |
filter | string | no | Back-compat toggle echo: needs_attention when that legacy filter applied, else all. |
filters | array<string> | no | Active-filter chips, e.g. verdict:doc_gap, intent:troubleshooting, vote:up, tag:<name>, q, date, needs_attention. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/conversations?verdict={verdict}&filter={filter}&intent={intent}&vote={vote}&q={q}&tag={tag}&since={since}&until={until}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"conversations": [
{}
],
"truncated": true,
"filter": "string",
"filters": [
"string"
]
}https://gateway.aardvarkdocs.com/v1/conversations/export.csvCSV of the conversation turns matching the same filters as GET /v1/conversations (every cell formula-injection-guarded). An X-Aardvark-Export-Truncated: true response header signals the export cap was hit.
verdict | query | string | no | Restrict to a single analysis verdict. |
filter | query | string | no | Set to needs_attention to restrict the result (default all). |
intent | query | string | no | Restrict to a single detected intent. |
vote | query | string | no | Restrict to up/down votes. |
q | query | string | no | Free-text search over question/answer. |
tag | query | string | no | Restrict to a custom tag. |
since | query | integer | no | Epoch-ms lower bound; keeps turns with ts >= this (inclusive). |
until | query | integer | no | Epoch-ms upper bound; keeps turns with ts < this (exclusive). |
Responses
Headers
X-Aardvark-Export-Truncated | string (true) | Present (value true) only when the 5,000-row export cap was hit and older turns were dropped; ABSENT otherwise, never false. Readable same-origin only — it is not listed in Access-Control-Expose-Headers, so a cross-origin browser fetch reads null. |
Body
A single string value.
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/conversations/export.csv?verdict={verdict}&filter={filter}&intent={intent}&vote={vote}&q={q}&tag={tag}&since={since}&until={until}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
"string"https://gateway.aardvarkdocs.com/v1/digestThe account’s insight-digest opt-in: whether enabled, the cadence, and when it was last_sent_ts.
Responses
Body
enabled | boolean | no | Whether the account is opted into the periodic emailed insights digest; false by default. |
cadence | string | no | Digest frequency, one of week or month; defaults to week. |
last_sent_ts | integer | no | Epoch-ms watermark of the last digest send; 0 when never sent. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/digest' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"enabled": true,
"cadence": "string",
"last_sent_ts": 0
}https://gateway.aardvarkdocs.com/v1/digestOpt the account owner into (or out of) a weekly/monthly emailed insights digest. Owner only. Owner only.
Request body
enabled | boolean | yes | Whether the digest is on. |
cadence | string (month | week) | yes | Digest frequency. |
Responses
Body
ok | boolean | no | Always true; the digest preferences were saved. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/digest' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/feedbackThe owner-facing READ of reader thumbs votes — the capture POST is POST /v1/feedback. Returns up/down counts, the satisfaction rate, and recent rated answers. Dashboard-authed (session OR secret key); a public key is rejected at the door.
Responses
Body
up | number | no | Count of thumbs-up votes in the window. |
down | number | no | Count of thumbs-down votes in the window. |
total | integer | no | Total votes (up + down). |
up_rate | string | no | up / (up + down) in [0,1], or null when there are no votes. |
recent | array<object> | no | Recent rated answer turns, newest first. |
recent[]. | integer | no | Epoch-ms time the vote was recorded. |
recent[]. | string | no | Conversation the rated answer belongs to. |
recent[]. | integer | no | Answer index within the conversation. |
recent[]. | string | no | The reader’s verdict, up or down. |
recent[]. | string | no | The rated user question. |
recent[]. | string | no | The rated assistant answer. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/feedback' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"up": 0,
"down": 0,
"total": 0,
"up_rate": "string",
"recent": [
{
"ts": 0,
"conversation_id": "string",
"turn": 0,
"vote": "string",
"question": "string",
"answer": "string"
}
]
}https://gateway.aardvarkdocs.com/v1/feedback/summaryOne cross-stream snapshot of the account's reader feedback over a recent 30-day window — thumbs, page ratings, survey responses, and conversation sentiment — powering the metric tiles at the top of the dashboard Feedback panel. Each sub-stream degrades to zeros if its backing table isn't present yet.
Responses
Body
window_days | integer | no | Look-back window in days for the snapshot (fixed at 30, matching the Insights tab). |
since | integer | no | Epoch-ms start of the window (now - 30 days). |
ratings | string | no | Page star-rating aggregates over the window; zeros until that stream's table lands. |
thumbs | array<any> | no | Thumbs-vote totals over the window (always present — the feedback table ships on main). |
surveys | string | no | Structured survey-response aggregates over the window; zeros until that stream's table lands. |
sentiment | array<any> | no | Conversation-sentiment distribution over the window; zeros until that stream's table lands. |
recent_activity | string | no | A small recent-activity feed across the streams for the panel header. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/feedback/summary' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"window_days": 0,
"since": 0,
"ratings": "string",
"thumbs": [],
"surveys": "string",
"sentiment": [],
"recent_activity": "string"
}https://gateway.aardvarkdocs.com/v1/insight-statusMark a clustered insight (by label) as e.g. triaged/resolved with an optional note — drives the dashboard’s coverage-gap workflow.
Request body
label | string | yes | The insight cluster label. |
status | string | yes | New triage status. |
note | string | no | Optional free-text note. |
Responses
Body
ok | boolean | no | Always true; the gap’s triage status (and note) was recorded. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/insight-status' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/insightsThe cron-clustered analytics surface: live metrics plus Top Questions and Coverage Gaps for the selected period, with prior-period deltas when available.
days | query | integer | no | Rolling window in days. |
period_kind | query | string | no | Named period bucket (e.g. week / month). |
period_start | query | integer | no | Period start, epoch ms. |
Responses
Body
window_days | integer | no | Length of the live-metrics window in days; from ?days=, default 30, capped at 90. |
bucket_ms | integer | no | Volume-series bucket width in ms: 3600000 (hourly) when window <=2 days, else 86400000 (daily). |
since | integer | no | Inclusive start of the live-metrics window, epoch ms (now - window_days*day). |
until | integer | no | Exclusive end of the live-metrics window, epoch ms (request time). |
generated_ts | integer | no | Epoch-ms write time of the shown cluster snapshot (max row ts); null if never clustered. |
period | object | no | The calendar period this Top Questions / Coverage Gaps snapshot covers; null if never clustered. |
period. | string | no | Period granularity: one of week, month, or quarter (legacy for pre-versioning rows). |
period. | string | no | Inclusive start of the period, epoch ms (week = Monday 00:00 UTC). |
period. | string | no | Exclusive end of the period, epoch ms (0 for legacy rows). |
periods | array<object> | no | Navigable history of clustered periods for this kind, newest first. |
periods[]. | string | no | Period granularity of this history entry: week, month, or quarter. |
periods[]. | string | no | Inclusive start of this history period, epoch ms. |
periods[]. | string | no | Exclusive end of this history period, epoch ms. |
has_prior | boolean | no | True when the immediately prior period has clusters to compute per-cluster trends against. |
metrics | object | no | Live engagement metrics over the ?days= window (computed on demand, not snapshotted). |
metrics. | number | no | Count of answer turns (transcripts) in the window. |
metrics. | number | no | Count of distinct conversations in the window. |
metrics. | object | no | Reader thumbs-up/down tallies over the window. |
metrics. | number | no | Number of thumbs-up votes in the window. |
metrics. | number | no | Number of thumbs-down votes in the window. |
metrics. | object | no | Distribution of analysis classifications over turns in the window. |
metrics. | number | no | Turns classified confident by the analysis pass. |
metrics. | number | no | Turns classified unconfident by the analysis pass. |
metrics. | number | no | Turns classified not_found (no answer found) by the analysis pass. |
metrics. | number | no | Turns classified doc_gap (a documentation gap) by the analysis pass. |
metrics. | array<object> | no | Turns-per-time-bucket volume series (sparse; client fills gaps), oldest first. |
metrics. | integer | no | Bucket start, epoch ms, floored to bucket_ms. |
metrics. | integer | no | Number of turns falling in this bucket. |
metrics. | object | no | Escalation/contact-link beacon counts driving the support-deflection metric. |
metrics. | number | no | Times the escalation/contact link was shown under a downvoted answer. |
metrics. | number | no | Times the escalation/contact link was clicked. |
metrics. | array<object> | no | Reader query-language distribution, most-frequent first (top 12). |
metrics. | string | no | Detected query language (from conversation_analysis.language). |
metrics. | integer | no | Number of turns in this language within the window. |
top_questions | array<object> | no | Clustered Top Questions for the period, biggest cluster first. |
top_questions[]. | string | no | Short human label naming the question theme. |
top_questions[]. | integer | no | Approximate number of reader questions in this cluster. |
top_questions[]. | string | no | Up to 3 representative example questions for this cluster. |
coverage_gaps | array<object> | no | Clustered Coverage Gaps (flagged turns grouped into doc-gap topics), biggest first. |
coverage_gaps[]. | string | no | Short human label naming the coverage-gap topic. |
coverage_gaps[]. | string | no | What readers asked and why the assistant struggled (may be null). |
coverage_gaps[]. | string | no | Concrete documentation change that would fix the gap (may be null). |
coverage_gaps[]. | integer | no | Approximate number of flagged turns in this cluster. |
coverage_gaps[]. | string | no | Up to 3 representative example questions for this gap. |
coverage_gaps[]. | string | no | Triage state set via /v1/insight-status; defaults to open when untouched. |
coverage_gaps[]. | string | no | Optional triage note attached to this gap; null when none. |
coverage_gaps[]. | integer | no | Epoch-ms time the gap's triage status was last set; null when untouched. |
sources | object | no | Doc-page citation analytics over the metrics window. |
sources. | array<object> | no | Most-cited doc pages in the window, busiest first (up to 20). |
sources. | string | no | Site-relative path of the cited documentation page. |
sources. | number | no | Times this page was cited as a source in the window. |
sources. | number | no | Of those citations, how many sat on a downvoted answer. |
sources. | integer | no | Total source-citation events recorded across all pages in the window. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/insights?days={days}&period_kind={period_kind}&period_start={period_start}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"window_days": 0,
"bucket_ms": 0,
"since": 0,
"until": 0,
"generated_ts": 0,
"period": {
"kind": "string",
"start": "string",
"end": "string"
},
"periods": [
{
"kind": "string",
"start": "string",
"end": "string"
}
],
"has_prior": true,
"metrics": {
"turns": 0,
"conversations": 0,
"votes": {
"up": 0,
"down": 0
},
"verdicts": {
"confident": 0,
"unconfident": 0,
"not_found": 0,
"doc_gap": 0
},
"series": [
{
"bucket_ts": 0,
"count": 0
}
],
"engagement": {
"escalation_shown": 0,
"escalation_click": 0
},
"languages": [
{
"language": "string",
"count": 0
}
]
},
"top_questions": [
{
"label": "string",
"count": 0,
"examples": "string"
}
],
"coverage_gaps": [
{
"label": "string",
"finding": "string",
"recommendation": "string",
"count": 0,
"examples": "string",
"status": "string",
"note": "string",
"status_updated_at": 0
}
],
"sources": {
"pages": [
{
"page": "string",
"citations": 0,
"downvoted": 0
}
],
"total": 0
}
}https://gateway.aardvarkdocs.com/v1/insights/assistantNatural-language Q&A over the account's analytics. Metered against the account balance (it calls the model), so it can return 402/429/502/503 like the chat endpoint.
Request body
question | string | yes | The natural-language analytics question. |
Responses
Body
answer | string | no | Natural-language reply about the account's analytics; a canned message when no data exists yet. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/insights/assistant' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"answer": "string"
}https://gateway.aardvarkdocs.com/v1/mcp-analyticsTop tools, recent calls, and a bucketed time series over a window of days (default 7, max 90). Buckets are hourly for ≤2 days, daily otherwise.
days | query | integer | no | Window in days (1–90). |
Responses
Body
window_days | integer | no | Resolved look-back window in days (?days=, default 7, capped at 90). |
bucket_ms | integer | no | Time-series bucket width in ms: hourly (3600000) for windows ≤2 days, else daily (86400000). |
since | integer | no | Epoch-ms start of the window (inclusive); until minus window_days. |
until | integer | no | Epoch-ms end of the window (exclusive); the request time now. |
tools | array<object> | no | Per-tool call counts in the window, ordered by count descending then tool name. |
tools[]. | string | no | MCP tool name as beaconed by the docs MCP server. |
tools[]. | integer | no | Number of calls to this tool within the window. |
recent | array<object> | no | Most recent individual tool calls, newest first, up to 100. |
recent[]. | string | no | MCP tool name for this individual call. |
recent[]. | string | no | Short human-readable summary of the call’s arguments; null when none was recorded. |
recent[]. | integer | no | Epoch-ms time the tool call was recorded. |
series | array<object> | no | Sparse per-bucket call counts over the window; only non-empty buckets, ascending by time. |
series[]. | integer | no | Epoch-ms floored start of the bucket (ts floored to bucket_ms). |
series[]. | integer | no | Number of tool calls falling in this bucket. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/mcp-analytics?days={days}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"window_days": 0,
"bucket_ms": 0,
"since": 0,
"until": 0,
"tools": [
{
"tool": "string",
"count": 0
}
],
"recent": [
{
"tool": "string",
"args_summary": "string",
"ts": 0
}
],
"series": [
{
"bucket_ts": 0,
"count": 0
}
]
}https://gateway.aardvarkdocs.com/v1/page-ratingsThe dashboard READ of reader star ratings: the overall average, total count, and a per-page breakdown. Dashboard-authed like /v1/insights.
Responses
Body
overall_avg | number | no | Mean star rating across all pages, or null when there are no ratings. |
total | integer | no | Total number of ratings submitted. |
pages | array<any> | no | Per-page rating rollups (path, average, count), busiest first. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/page-ratings' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"overall_avg": 0,
"total": 0,
"pages": []
}https://gateway.aardvarkdocs.com/v1/reach-analyticsAggregate Content Reach over a window of days (default 30, max 90): page-view and session totals, average foreground-visible time, average sections reached, totals for each of the five tracked actions, and a per-page table with reach completion. Plan-gated to Business/Enterprise (403 plan_required). Averages are clamped means — the clamp is applied at ingest, so a tab left open cannot drag them. Everything is aggregate: there is no endpoint returning an individual reader’s path, because there is no durable visitor identity to build one from.
days | query | integer | no | Window in days (1–90; default 30). |
Responses
Body
window_days | number | no | Resolved look-back window in days (?days=, default 30, capped at 90). |
since | integer | no | Epoch-ms start of the window (inclusive). |
until | integer | no | Epoch-ms end of the window (exclusive). |
totals | object | no | |
totals. | integer | no | Page views recorded in the window. Counts views that produced a measurement: a visit with no foreground time and no section reached sends no beacon, so this runs slightly below a page-tag analytics count rather than matching it. |
totals. | integer | no | Distinct pages with at least one recorded page view. |
totals. | integer | no | Distinct tab sessions. NOT unique visitors — a session ends with the browser tab. |
totals. | number | no | Mean foreground-visible time per page view, in ms. |
totals. | number | no | Mean number of sections that qualified per page view. |
totals. | number | no | Mean number of sections the viewed pages contained. |
actions | object | no | Totals for the closed action taxonomy across the window. |
actions. | integer | no | Times a code-block copy control was used. |
actions. | integer | no | Times a link or button inside a marked high-value region was clicked. |
actions. | integer | no | Times an On-this-page link jumped to a section. |
actions. | integer | no | Times a reader arrived at a section from the search box. |
actions. | integer | no | Times an accordion or tab control inside a section was used. |
pages | array<object> | no | Per-page rows, busiest first (≤50). Each carries page_url, pageviews, avg_visible_ms, sections_total, avg_sections_reached, and completion — the fraction of the page’s sections reached, averaged over its page views (0–1), or 0 for a page with no anchored sections. |
pages[]. | string | no | |
pages[]. | integer | no | |
pages[]. | number | no | |
pages[]. | integer | no | |
pages[]. | number | no | |
pages[]. | number | no | |
pages_truncated | boolean | no | True when more distinct pages had traffic in the window than pages returns, so its tail is missing. Compare with totals.pages for the true count. Without this, a page absent because it ranked 51st is indistinguishable from a page nobody visited. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/reach-analytics?days={days}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"window_days": 0,
"since": 0,
"until": 0,
"totals": {
"pageviews": 0,
"pages": 0,
"sessions": 0,
"avg_visible_ms": 0,
"avg_sections_reached": 0,
"avg_sections_total": 0
},
"actions": {
"copy_code": 0,
"cta": 0,
"toc_jump": 0,
"search_click": 0,
"expand": 0
},
"pages": [
{
"page_url": "string",
"pageviews": 0,
"avg_visible_ms": 0,
"sections_total": 0,
"avg_sections_reached": 0,
"completion": 0
}
],
"pages_truncated": true
}https://gateway.aardvarkdocs.com/v1/reach-pagePer-page Content Reach drill-in — the data behind the dashboard’s section heat strip. Returns one row per section in document order with its reach rate, median foreground dwell, and action counts, plus the distribution of last-reached sections. Reach counts and action totals are exact over the window; the dwell statistic is a MEDIAN over a bounded sample, so one long-parked tab cannot skew it. Plan-gated to Business/Enterprise (403 plan_required).
path | query | string | yes | Site path of the page to inspect, normalized the same way the ingest normalized it. |
days | query | integer | no | Window in days (1–90; default 30). |
Responses
Body
window_days | number | no | Resolved look-back window in days (?days=, default 30, capped at 90). |
since | integer | no | Window start, epoch-ms (inclusive). |
until | integer | no | Window end, epoch-ms (exclusive); the request time. |
page_url | string | no | The normalized path that was inspected. |
pageviews | integer | no | Page views of this page in the window — the denominator for each section's reach rate. |
avg_visible_ms | number | no | Mean foreground-visible time on this page, in ms. |
sections_total | integer | no | The largest section count observed for this page in the window. |
exits | array<object> | no | Last-reached section counts, most common first (≤10). An exit PROXY, not a drop-off measurement. |
exits[]. | string | no | |
exits[]. | integer | no | |
sections | array<object> | no | One row per section the page HAS, in document order — including sections nobody reached, which come back with reached: 0 rather than being omitted, so “nobody got here” is distinguishable from “no such section”. Membership comes from the page’s catalogue (see the ingest catalog field); a section with recorded history but no catalogue entry (a renamed anchor) is still listed, flagged current: false. Each carries section_id, ordinal, kind, current, reached (page views in which the section qualified), reach_rate (reached over pageviews, 0–1), median_dwell_ms (median foreground time with the section under the reader’s trigger line), and actions. |
sections[]. | string | no | |
sections[]. | integer | no | |
sections[]. | string | no | |
sections[]. | boolean | no | True when the page's CURRENT catalogue still names this section; false for an id only history remembers, such as a heading renamed during the window. Count completion against the current rows alone — a historical id is real recorded reach, but it is not a gap in the page as it stands today. |
sections[]. | integer | no | |
sections[]. | number | no | |
sections[]. | integer | no | |
sections[]. | object | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections[]. | integer | no | |
sections_truncated | boolean | no | True when the page has more distinct sections than sections returns, which is capped. Compare sections.length against sections_total to see how much is missing; without this flag a truncated list is indistinguishable from a complete one. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/reach-page?path={path}&days={days}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"window_days": 0,
"since": 0,
"until": 0,
"page_url": "string",
"pageviews": 0,
"avg_visible_ms": 0,
"sections_total": 0,
"exits": [
{
"section_id": "string",
"count": 0
}
],
"sections": [
{
"section_id": "string",
"ordinal": 0,
"kind": "string",
"current": true,
"reached": 0,
"reach_rate": 0,
"median_dwell_ms": 0,
"actions": {
"copy_code": 0,
"cta": 0,
"toc_jump": 0,
"search_click": 0,
"expand": 0
}
}
],
"sections_truncated": true
}https://gateway.aardvarkdocs.com/v1/search-analyticsOn-site search analytics over a window of days (default 30, max 90): top searches, zero-result queries, click-through, average clicked position, searches-per-session, no-click rate, Ask-AI escalation rate, top clicked pages, a language split, and a bucketed volume series (hourly for ≤2 days, daily otherwise). The response also includes the latest durable calendar-period search-theme/content-gap snapshot, which is independent of the requested live-event window.
days | query | integer | no | Window in days (1–90; default 30). |
Responses
Body
window_days | integer | no | Resolved look-back window in days (?days=, default 30, capped at 90). |
bucket_ms | integer | no | Time-series bucket width in ms: hourly (3600000) for windows ≤2 days, else daily (86400000). |
since | integer | no | Epoch-ms start of the window (inclusive). |
until | integer | no | Epoch-ms end of the window (exclusive); the request time now. |
totals | object | no | |
totals. | number | no | Number of search queries in the window. |
totals. | number | no | Number of result clicks in the window. |
totals. | number | no | Number of Ask-AI escalations from search. |
totals. | number | no | Distinct search sessions in the window. |
totals. | number | no | Number of queries that returned no results. |
ctr | number | no | Clicks divided by queries (a ratio; can exceed 1 when a reader opens several results for one search). |
askAiRate | number | no | Ask-AI escalations divided by queries. |
searchesPerSession | number | no | Queries divided by distinct sessions. |
noClickSessionRate | number | no | Fraction of searching sessions that never clicked a result. |
avgPosition | number | no | Mean 1-based rank of clicked results; omitted when there are no clicks. |
avgLatencyMs | number | no | Mean client-side scorer time in ms; omitted when no latency was reported. |
topTerms | array<object> | no | |
topTerms[]. | string | no | A representative raw query term for the group. Searches are grouped by an accent-folded/lowercased key (so "café"/"Cafe"/"CAFÉ" count as one), but the displayed term is a real raw variant, not the folded key. |
topTerms[]. | number | no | Number of searches for this term (across all accent/case variants of it). |
topTerms[]. | number | no | How many of those searches returned no results. |
zeroResultTerms | array<object> | no | |
zeroResultTerms[]. | string | no | A representative raw query term that returned nothing (a content gap), grouped by the same accent-folded/lowercased key as topTerms. |
zeroResultTerms[]. | number | no | Number of zero-result searches for this term. |
topClickedPages | array<object> | no | |
topClickedPages[]. | string | no | A clicked result page path. |
topClickedPages[]. | number | no | Number of clicks to this page from search. |
byLang | array<object> | no | |
byLang[]. | string | no | Reader/page language tag. |
byLang[]. | number | no | Number of queries in this language. |
series | array<object> | no | |
series[]. | number | no | Epoch-ms floored start of the bucket. |
series[]. | number | no | Number of queries in this bucket. |
insights | object | no | Latest durable, deterministic per-normalized-term search themes and content gaps. This calendar-period snapshot is independent of the days live-event window and retains representative query-term text after raw search-event rows expire. Before grouping, the scheduled pass samples at most the latest 50,000 stored query rows and the latest 50,000 click candidates considered for the source period. Each click candidate follows the nearest preceding stored-term query in the same tab session and need not duplicate that query’s term. It contributes only when that exact owner is also in the capped query sample; an omitted or out-of-period owner remains as an attribution barrier so retention cannot lend the click to an older sampled query. A click affects a durable snapshot only when its raw beacon timestamp falls inside the owning query’s calendar period plus the five-minute boundary/reordering window; later same-tab clicks remain part of live analytics but do not reopen or extend that snapshot. Anonymous queries stay outside this durable term-insight attribution, and theme/gap counts are sample counts above those bounds. If that source period’s click-candidate lane reaches its cap and a sampled query has no attributed click, or a click candidate for the same normalized term belongs to a same-period owner outside the capped query sample, that click count is treated as unknown rather than manufacturing a no-click content gap. The same conservative unknown applies when a delayed query takes ownership of a click below its new period’s five-minute window: that older click is not counted in the new period, but it cannot manufacture an exact no-click gap there. SEARCH_EVENT_RETENTION_DAYS is the base raw-row window. Beyond it, the active calendar period keeps only those two 50,000-row lanes plus at most one stored-query owner per retained click, bounding extended source storage to 150,000 rows per retained source period and normally fewer. At most one recently completed pending period keeps its own bounded sample while the fair queue finalizes activity that arrived after its last refresh; later expired backlog periods are dropped, so active plus pending samples cap transient extended storage at 300,000 rows per account. The active-period snapshot receives the same floor; after the period closes, snapshots whose generation time falls outside that duration are swept. They can survive /admin/delete-account, which archives rather than hard-deletes account data, only until that cutoff; a physical account deletion removes them immediately. After a rebuilt shipped widget enables store_terms: false, newly emitted queries contain no term text and cannot seed term summaries; termless clicks can still attach to a preceding stored-term query. The setting does not erase previously received term-bearing rows or existing snapshots, so eligible earlier rows can still be summarized before they expire and snapshots remain until their normal active-period/retention cutoff. |
insights. | integer | no | Epoch-ms time the search-insights snapshot was generated, or null before the first pass. |
insights. | object | no | Calendar period covered by the latest snapshot, or null before the first pass; it does not follow the days query parameter. |
insights. | string | no | Calendar period kind (week, month, or quarter). |
insights. | integer | no | Inclusive UTC start of the calendar period, epoch-ms. |
insights. | integer | no | Exclusive UTC end of the calendar period, epoch-ms. |
insights. | array<object> | no | Highest-volume normalized search-term summaries, biggest first. |
insights. | string | no | Representative display term retained for the normalized search-term bucket. |
insights. | string | no | Deterministic query, click-through, and zero-result summary for the term. |
insights. | string | no | Optional documentation recommendation for the theme; it may quote the representative term. |
insights. | integer | no | Approximate query count behind the theme. |
insights. | array<string> | no | Representative query-term text retained for the theme. |
insights. | array<object> | no | Deterministic search-driven content gaps derived from zero-result or repeated no-click normalized terms. |
insights. | string | no | Representative display term retained for the gap's normalized search-term bucket. |
insights. | string | no | Deterministic summary explaining the missing/no-click signal. |
insights. | string | no | Suggested documentation change; it may quote the representative term. |
insights. | integer | no | Approximate severity count behind the gap. |
insights. | array<string> | no | Representative query-term text retained for the gap. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/search-analytics?days={days}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"window_days": 0,
"bucket_ms": 0,
"since": 0,
"until": 0,
"totals": {
"queries": 0,
"clicks": 0,
"askAi": 0,
"sessions": 0,
"zeroResults": 0
},
"ctr": 0,
"askAiRate": 0,
"searchesPerSession": 0,
"noClickSessionRate": 0,
"avgPosition": 0,
"avgLatencyMs": 0,
"topTerms": [
{
"term": "string",
"searches": 0,
"zeroResults": 0
}
],
"zeroResultTerms": [
{
"term": "string",
"count": 0
}
],
"topClickedPages": [
{
"page": "string",
"clicks": 0
}
],
"byLang": [
{
"lang": "string",
"count": 0
}
],
"series": [
{
"bucket_ts": 0,
"count": 0
}
],
"insights": {
"generated_ts": 0,
"period": {
"kind": "string",
"start": 0,
"end": 0
},
"themes": [
{
"label": "string",
"finding": "string",
"recommendation": "string",
"count": 0,
"examples": [
"string"
]
}
],
"gaps": [
{
"label": "string",
"finding": "string",
"recommendation": "string",
"count": 0,
"examples": [
"string"
]
}
]
}
}https://gateway.aardvarkdocs.com/v1/sentimentThe positive/neutral/negative distribution of analyzed conversations over a recent window, plus recent example messages, for the reader-feedback panel. Dashboard-authed like /v1/insights.
Responses
Body
positive | integer | no | Count of conversations the analysis pass classified positive. |
neutral | integer | no | Count classified neutral. |
negative | integer | no | Count classified negative. |
total | integer | no | Total classified conversations (positive + neutral + negative). |
recent_positive | string | no | A few recent example messages classified positive. |
recent_negative | string | no | A few recent example messages classified negative. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/sentiment' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"positive": 0,
"neutral": 0,
"negative": 0,
"total": 0,
"recent_positive": "string",
"recent_negative": "string"
}https://gateway.aardvarkdocs.com/v1/surveysThe dashboard READ of structured survey answers: per-question aggregates (choice bars + rating averages) plus recent open-ended survey comments. Dashboard-authed like /v1/usage.
Responses
Body
surveys | array<object> | no | Per-survey question aggregates. |
surveys[]. | string | no | Island-defined question id. |
surveys[]. | string | no | Question kind: single, multi, rating, or text. |
surveys[]. | integer | no | Number of respondents to the question. |
surveys[]. | integer | no | Number of rating answers folded into rating_avg. |
surveys[]. | array<object> | no | Per-option counts for a choice question, most-picked first. |
surveys[]. | string | no | The chosen option label. |
surveys[]. | integer | no | How many respondents picked this option. |
surveys[]. | string | no | Mean of the rating answers, or null for a non-rating question / no ratings. |
comments | array<object> | no | Recent open-ended survey comments (the survey-scoped page_comments rows). |
comments[]. | integer | no | Epoch-ms time the comment was submitted. |
comments[]. | string | no | Site-relative path the comment was left on, or null. |
comments[]. | string | no | Reader-supplied open-ended comment text (escaped before display). |
truncated | boolean | no | true when more comments exist beyond the returned cap. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/surveys' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"surveys": [
{
"question_id": "string",
"question_type": "string",
"total": 0,
"rating_count": 0,
"choices": [
{
"value": "string",
"count": 0
}
],
"rating_avg": "string"
}
],
"comments": [
{
"ts": 0,
"page_url": "string",
"comment": "string"
}
],
"truncated": true
}https://gateway.aardvarkdocs.com/v1/tagsThe account’s custom tag vocabulary (tags) and the per-account cap (max).
Responses
Body
tags | array<object> | no | The account’s active (non-deleted) custom tags, sorted alphabetically by name. |
tags[]. | string | no | Opaque UUID identifying the tag. |
tags[]. | string | no | Display label of the tag, unique per account; no semicolons or control characters. |
tags[]. | string | no | Optional guidance steering how the analysis pass applies this tag; null if unset. |
tags[]. | integer | no | Epoch-ms time the tag was created. |
tags[]. | number | no | Count of conversations currently labeled with this tag. |
max | number | no | Maximum active tags allowed per account (default 20). |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/tags' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"tags": [
{
"id": "string",
"name": "string",
"description": "string",
"ts": 0,
"uses": 0
}
],
"max": 0
}https://gateway.aardvarkdocs.com/v1/tagsAdd a custom tag to the account vocabulary. Owner/admin only; 409 on a duplicate name or when the per-account cap is reached. Owner only.
Request body
name | string | yes | Tag name (unique per account). |
description | string | no | Optional human description. |
Responses
Body
ok | boolean | no | Always true once the tag is created and added to the account vocabulary. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/tags' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/tags/{id}Edit a tag’s description and/or soft-delete it (deleted: true hides it from the vocabulary without dropping the labels already applied to conversations). Owner/admin only; at least one of description/deleted must be supplied, and 404 if no tag matches the id. Owner only.
id | path | string | yes | Tag id — the trailing path segment after /v1/tags/ (≤100 chars). |
Request body
description | string | no | New human description for the tag; null clears it. |
deleted | boolean | no | true soft-deletes the tag; false restores it. |
Responses
Body
ok | boolean | no | Always true once the update (or soft-delete) is applied. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/tags/{id}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/v1/threadsA flat, cursor-paged feed of answer turns in ascending (ts, conversation_id, turn) order (oldest first) — built for forward incremental sync. Page with next_cursor / has_more.
since | query | integer | no | Cursor: return turns at or after this epoch-ms timestamp (inclusive lower bound), or pass a prior page’s next_cursor. |
limit | query | integer | no | Max turns to return. |
Responses
Body
turns | array<object> | no | Page of recent answer turns, ascending by the (ts, conversation_id, turn) sort key. |
turns[]. | string | no | Conversation this turn belongs to; the reader-island session/thread id. |
turns[]. | integer | no | Zero-based turn index within the conversation. |
turns[]. | string | no | The reader's question text for this turn; null if not stored. |
turns[]. | string | no | The assistant's answer text for this turn; null if not stored. |
turns[]. | string | no | Full model reasoning for the turn (not truncated); null if absent. |
turns[]. | integer | no | Epoch-ms time the transcript turn was recorded; the pagination sort key. |
turns[]. | string | no | Reader feedback: up, down, or null when no vote was cast. |
turns[]. | string | no | Analysis verdict: confident, unconfident, not_found, or doc_gap; null until analyzed. |
turns[]. | string | no | One-sentence analysis summary of the turn; null until analyzed. |
turns[]. | string | no | Conversation kind: troubleshooting, product_discovery, unsupported_feature, competitor, or off_topic; else null. |
turns[]. | string | no | Reader question’s language as a short ISO code (e.g. en, ja, pt-BR); null if unknown. |
count | integer | no | Number of turns returned on this page. |
next_cursor | string | no | Opaque continuation token to pass as since; null when no further page remains. |
has_more | boolean | no | True when another non-empty page exists beyond this one. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/threads?since={since}&limit={limit}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"turns": [
{
"conversation_id": "string",
"turn": 0,
"question": "string",
"answer": "string",
"reasoning": "string",
"ts": 0,
"vote": "string",
"classification": "string",
"summary": "string",
"intent": "string",
"language": "string"
}
],
"count": 0,
"next_cursor": "string",
"has_more": true
}https://gateway.aardvarkdocs.com/v1/transcriptsReturns the account’s stored transcripts grouped into conversations (newest first), each turn carrying its vote. Capped at ~300 turns; truncated signals older history exists.
Responses
Body
conversations | array<object> | no | Stored conversations, newest first; each holds its turns (turn, question, answer, vote) ascending. |
truncated | boolean | no | true when older turns exist beyond the ~300-turn cap and were omitted. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/transcripts' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"conversations": [
{}
],
"truncated": true
}https://gateway.aardvarkdocs.com/v1/usageThe dashboard overview payload: account status, balance, recent usage rows, top-ups, reader feedback/comments, account events, and the payment/auto-top-up configuration. Readable even when the account is suspended.
Responses
Body
account | object | no | Account identity and current standing block. |
account. | string | no | The caller's account id. |
account. | string | no | Billing-account owner’s email from the accounts row (not a member’s address). |
account. | string | no | Account state, e.g. active, suspended, closed, or unknown if the row is missing. |
account. | object | no | Active-suspension summary when status is suspended; otherwise null. |
account. | string | no | Why the account was paused: cost_unavailable, operator, or self_serve. |
account. | integer | no | Epoch-ms time the suspension was recorded. |
account. | string | no | Request id that triggered the suspension, for support correlation. |
account. | boolean | no | Whether the dashboard Reactivate button applies; true only for a cost_unavailable pause. |
balance | object | no | Current balance snapshot from the Durable Object, in USD. |
balance. | number | no | Total account balance in USD. |
balance. | number | no | Funds reserved against in-flight requests, in USD. |
balance. | number | no | Spendable balance in USD (balance_usd minus reserved_usd). |
anomaly_paused | boolean | no | Whether the spend-velocity circuit breaker has paused paid AI (free models keep serving). Visible to every caller; resuming is owner/admin via POST /v1/billing/resume-ai. |
subscription | object | no | The account’s live subscription plan + included-AI grant meter (the same object GET /v1/billing returns), or null on the free pay-as-you-go plan. Its always-present free_mode object reports { active, until }; an active complimentary grant covers AI usage only, sets max_bill_usd to 0, and leaves GitHub Automations compute billed to prepaid balance. Present only for owner/admin callers; omitted for members. |
usage | array<object> | no | Up to 50 most recent metered-request ledger rows, newest first. |
usage[]. | integer | no | Epoch-ms time the usage row was written. |
usage[]. | string | no | Upstream model slug billed for the request. |
usage[]. | integer | no | Input token count for the request. |
usage[]. | integer | no | Output token count for the request. |
usage[]. | number | no | Published OpenRouter list cost in USD (pre-markup; not the operator's backend cost). |
usage[]. | number | no | Amount charged to the account in USD (list cost times markup). |
usage[]. | string | no | Upstream generation id used to reconcile the final cost. |
usage[]. | string | no | How the cost was derived: inline, generation_api, or provisional. |
usage[]. | string | no | |
topups | array<object> | no | Up to 20 most recent balance credits, newest first. Present only for owner/admin callers; omitted for members. |
topups[]. | integer | no | Epoch-ms time the top-up was credited. |
topups[]. | number | no | Credited amount in USD. |
topups[]. | string | no | Origin of the credit, e.g. stripe, auto_topup, or an operator grant. |
topups[]. | string | no | Optional free-text note attached to the credit. |
feedback | array<object> | no | Up to 50 most recent reader thumbs votes, newest first. |
feedback[]. | integer | no | Epoch-ms time the vote was recorded. |
feedback[]. | string | no | Conversation the rated answer belongs to. |
feedback[]. | string | no | Reader’s verdict, up or down. |
feedback[]. | string | no | The reader question that the rated answer addressed. |
comments | array<object> | no | Up to 50 most recent reader page comments, newest first. |
comments[]. | integer | no | Epoch-ms time the comment was submitted. |
comments[]. | string | no | Site-relative path the comment was left on, or null. |
comments[]. | string | no | Reader-supplied open-ended comment text (escaped before display). |
events | array<object> | no | Up to 20 most recent account decision-log entries, newest first. |
events[]. | integer | no | Epoch-ms time the event was recorded. |
events[]. | string | no | Decision type: suspended, reactivated, or closed. |
events[]. | string | no | Reason code: cost_unavailable, operator, or self_serve. |
events[]. | string | no | Who made the change: system, operator, owner, or admin. |
events[]. | string | no | Request id correlated with the event, if any. |
payment | object | no | Card-on-file and auto-top-up configuration for the Billing section. Present only for owner/admin callers; omitted for members. |
payment. | boolean | no | Whether the gateway has a Stripe secret key and can accept card payments at all. |
payment. | boolean | no | Whether a card is saved on file for the account. |
payment. | object | no | Display-only details of the saved card, or null when none. |
payment. | string | no | Card brand, e.g. visa. |
payment. | string | no | Last four digits of the saved card. |
payment. | integer | no | Card expiry month, 1-12. |
payment. | integer | no | Card expiry year, four digits. |
payment. | boolean | no | Whether auto top-up is turned on. |
payment. | number | no | Amount charged per auto top-up in USD, or null when unset. |
payment. | integer | no | Consecutive auto-top-up charge failures since the last success. |
payment. | string | no | Message from the most recent auto-top-up failure, or null. |
payment. | integer | no | Available-balance threshold in USD that triggers an auto top-up. |
payment. | number | no | Minimum allowed auto-top-up charge amount in USD. |
payment. | number | no | Maximum allowed top-up amount in USD (Stripe per-charge technical limit). |
payment_events | array<object> | no | Up to 20 most recent billing-activity entries (card lifecycle, declined charges), newest first. Present only for owner/admin callers; omitted for members. |
payment_events[]. | integer | no | Epoch-ms time the payment event was recorded. |
payment_events[]. | string | no | Event type, e.g. card saved/removed or a charge succeeded/declined. |
payment_events[]. | number | no | Charge amount in USD, or null for non-charge events. |
payment_events[]. | string | no | Free-text detail about the event, e.g. a decline reason. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/usage' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"account": {
"id": "string",
"owner_email": "string",
"status": "string",
"suspension": {
"reason": "string",
"ts": 0,
"request_id": "string",
"self_serviceable": true
}
},
"balance": {
"balance_usd": 0,
"reserved_usd": 0,
"available_usd": 0
},
"anomaly_paused": true,
"subscription": {},
"usage": [
{
"ts": 0,
"model": "string",
"prompt_tokens": 0,
"completion_tokens": 0,
"openrouter_usd": 0,
"billed_usd": 0,
"generation_id": "string",
"cost_source": "string",
"source": "string"
}
],
"topups": [
{
"ts": 0,
"amount_usd": 0,
"source": "string",
"note": "string"
}
],
"feedback": [
{
"ts": 0,
"conversation_id": "string",
"vote": "string",
"question": "string"
}
],
"comments": [
{
"ts": 0,
"page_url": "string",
"comment": "string"
}
],
"events": [
{
"ts": 0,
"event": "string",
"reason": "string",
"actor": "string",
"request_id": "string"
}
],
"payment": {
"stripe_enabled": true,
"has_card": true,
"card": {
"brand": "string",
"last4": "string",
"exp_month": 0,
"exp_year": 0
},
"auto_topup_enabled": true,
"auto_topup_amount_usd": 0,
"auto_topup_failures": 0,
"auto_topup_last_error": "string",
"low_balance_usd": 0,
"min_usd": 0,
"max_usd": 0
},
"payment_events": [
{
"ts": 0,
"type": "string",
"amount_usd": 0,
"detail": "string"
}
]
}https://gateway.aardvarkdocs.com/v1/usage/membersOwner/admin billing usage grouped by the team member who minted each key, over an optional [since, until) window. Account-owned secret/admin/CLI usage is listed as one row per key with safe key metadata.
since | query | integer | no | Inclusive lower bound, epoch ms (default: 30 days ago). |
until | query | integer | no | Exclusive upper bound, epoch ms (default: now). |
Responses
Body
since | integer | no | Inclusive start of the resolved [since, until) window, epoch-ms. |
until | integer | no | Exclusive end of the resolved [since, until) window, epoch-ms (clamped to now). |
members | array<object> | no | Usage groups, sorted by spend descending with member rows before account-owned key rows on ties. |
members[]. | string | no | User who minted the keys, or null for an account-owned key row. |
members[]. | string | no | Member’s email, or null for an account-owned key row or a since-deleted user. |
members[]. | string | no | Id of the account-owned key this row aggregates, or null for a member-attributed row. |
members[]. | string | no | Non-secret prefix of the account-owned key, or null for a member-attributed row. |
members[]. | string | no | Display label of the account-owned key, or null for a member-attributed row. |
members[]. | string | no | public or secret for an account-owned key row, or null for a member-attributed row. |
members[]. | boolean | no | true when this row aggregates an account-owned key (user_id is null) rather than a member. |
members[]. | boolean | no | Back-compat alias for is_account_key; true when user_id is null. |
members[]. | string | no | Display name: key label/prefix for account-owned key rows, else the member email, else (member <id8>) for a deleted user. |
members[]. | integer | no | Number of usage-ledger rows (requests) attributed to this member or account-owned key. |
members[]. | integer | no | Summed prompt (input) tokens across this row's requests. |
members[]. | integer | no | Summed completion (output) tokens across this row's requests. |
members[]. | integer | no | Sum of prompt_tokens and completion_tokens for this row. |
members[]. | number | no | Total amount billed to this row over the window, in USD. |
totals | object | no | Grand-total summary across all rows for the window. |
totals. | integer | no | Total requests across all rows over the window. |
totals. | integer | no | Total prompt (input) tokens across all rows. |
totals. | integer | no | Total completion (output) tokens across all rows. |
totals. | integer | no | Sum of prompt_tokens and completion_tokens across all rows. |
totals. | number | no | Total amount billed across all rows over the window, in USD (summed in micro-USD, converted once). |
support | object | no | |
support. | array<object> | no | |
support. | string | no | |
support. | string | no | |
support. | string | no | |
support. | integer | no | |
support. | integer | no | |
support. | integer | no | |
support. | integer | no | |
support. | number | no | |
support. | object | no | |
support. | integer | no | |
support. | integer | no | |
support. | integer | no | |
support. | integer | no | |
support. | number | no |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/usage/members?since={since}&until={until}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"since": 0,
"until": 0,
"members": [
{
"user_id": "string",
"email": "string",
"key_id": "string",
"key_prefix": "string",
"key_label": "string",
"key_mode": "string",
"is_account_key": true,
"is_cli": true,
"label": "string",
"requests": 0,
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0,
"billed_usd": 0
}
],
"totals": {
"requests": 0,
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0,
"billed_usd": 0
},
"support": {
"users": [
{
"user_id": "string",
"email": "string",
"label": "string",
"requests": 0,
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0,
"billed_usd": 0
}
],
"totals": {
"requests": 0,
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0,
"billed_usd": 0
}
}
}Support tickets.
https://gateway.aardvarkdocs.com/v1/supportLists tickets for the account. Plain members see only their own; owners/admins/secret-key callers see the whole account. Capped at 100 (newest first).
Responses
Body
items | array<object> | no | Support tickets for the account, newest first, capped at 100. |
items[]. | string | no | Ticket's UUID, assigned at submission. |
items[]. | string | no | Ticket kind: one of bug, feature, question, or other. |
items[]. | string | no | Submitter's free-text message, capped at 4000 characters. |
items[]. | string | no | Triage state; defaults to open at creation. |
items[]. | integer | no | Epoch-ms time the ticket was submitted. |
truncated | boolean | no | true when more than 100 tickets exist beyond those returned. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/support' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"items": [
{
"id": "string",
"category": "string",
"message": "string",
"status": "string",
"ts": 0
}
],
"truncated": true
}https://gateway.aardvarkdocs.com/v1/supportFiles a ticket to the gateway operator. Fail-hard over the per-account daily cap (429). Sends a best-effort operator email; the stored row is the source of truth.
Request body
category | string (bug | feature | question | other) | yes | Ticket category (bug | feature | question | other). |
message | string | yes | Ticket body (≤4000 chars). |
Responses
Body
ok | boolean | no | Always true once the ticket row is stored. |
id | string | no | Server-minted UUID of the stored support ticket. |
status | string | no | Initial triage status of a new ticket; always open. |
ts | integer | no | Epoch-ms time the ticket was stored. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/support' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"category": "bug",
"message": "The usage chart is blank on Safari."
}'Response examples
{
"ok": true,
"id": "string",
"status": "string",
"ts": 0
}In-dashboard support assistant.
https://gateway.aardvarkdocs.com/v1/assistant/chatOne metered turn of the dashboard support assistant. The gateway injects the system prompt (identity, plan-and-approve behavior, the docs index) and the account context, forces the latest Sonnet model, and forwards the conversation to the upstream model. Billed to the account (tagged as support spend), so it can return 402/429/503 like the chat endpoint. The reply may include tool_calls the dashboard renders for the user to approve before running.
Request body
messages | array<any> | yes | The running conversation (user/assistant/tool messages). Any client-supplied system message is dropped; tool_calls are filtered to the known tool menu. |
Responses
Body
role | string | no | Always assistant. |
content | string | no | The assistant's reply text (may be null on a pure tool-call turn). |
tool_calls | array<object> | no | Proposed tool calls from the known menu, for the user to approve; empty on a final answer. |
billed_usd | number | no | What this turn cost the account, in USD (published rate). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/assistant/chat' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"role": "string",
"content": "string",
"tool_calls": [
{}
],
"billed_usd": 0
}https://gateway.aardvarkdocs.com/v1/assistant/docServer-side fetch of one Aardvark documentation page (Markdown) for the assistant’s fetch_doc grounding tool. The path is validated to a same-origin .md page and the body is size-capped.
path | query | string | no | The docs page’s .md path (relative, no scheme/traversal), e.g. ai-gateway.md. |
Responses
Body
path | string | no | The resolved page path. |
text | string | no | The page's Markdown, truncated to the size cap. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/assistant/doc?path={path}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"path": "string",
"text": "string"
}https://gateway.aardvarkdocs.com/v1/assistant/escalateFile a support ticket (a GitHub issue in the operator’s repo) with the chat history, attempted actions, and account details, for a human to handle. Per-account rate-limited. Records the escalation and mirrors it to the support list; if GitHub filing is unavailable it still records + mirrors and reports filed: false.
Request body
summary | string | no | A one-line summary of what the user needs help with. |
transcript | array<any> | no | The conversation so far (role/content messages). |
actions | array<any> | no | The actions the assistant proposed/ran and their outcomes. |
Responses
Body
ok | boolean | no | Always true once the escalation is recorded. |
filed | boolean | no | Whether a GitHub issue was actually created. |
issue_number | integer | no | The created issue number, or null if not filed. |
issue_url | string | no | The created issue URL, or null if not filed. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/assistant/escalate' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true,
"filed": true,
"issue_number": 0,
"issue_url": "string"
}Account self-service.
https://gateway.aardvarkdocs.com/v1/reactivateLifts the gateway's automatic cost-unavailable suspension. Operator-set holds and closed accounts cannot be reactivated here. Idempotent. Owner/admin only.
Responses
Body
status | string | no | Account status after the call; active on every success path. |
changed | boolean | no | true if this call lifted the pause; false when already active (no-op). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/reactivate' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"status": "string",
"changed": true
}API key management.
https://gateway.aardvarkdocs.com/v1/keysReturns metadata for every key on the account (prefix, mode, label, allowed origins, revoked flag) — never the hash or secret value.
Responses
Body
keys | array<object> | no | Every API key on the account, ordered by mode then created_at; metadata only. |
keys[]. | string | no | Opaque key identifier, used as :id in the per-key management routes. |
keys[]. | string | no | Key class: public (origin-gateable reader key) or secret (account master credential). |
keys[]. | string | no | Short non-secret prefix of the key value, shown to identify the key. |
keys[]. | string | no | Human-set display nickname, or null if unnamed. |
keys[]. | array<string> | no | Origin allowlist for a public key (null means any origin); always null for secret keys. |
keys[]. | boolean | no | Whether the key has been revoked and can no longer authenticate. |
keys[]. | integer | no | Epoch-ms time the key was minted. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/keys' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"keys": [
{
"id": "string",
"mode": "string",
"key_prefix": "string",
"label": "string",
"allowed_origins": [
"string"
],
"revoked": true,
"created_at": 0
}
]
}https://gateway.aardvarkdocs.com/v1/keysCreates a public or secret key. The full key value is returned ONCE. Secret keys are owner-only and capped at one active per account (rotate to replace). Public keys may be origin-scoped.
Request body
mode | string (public | secret) | no | Key mode: public (default) or secret. |
label | string | no | Display label (≤64 chars). |
allowed_origins | array<any> | no | Allowed origins for a public key; null/omitted = any origin. |
Responses
Body
key_id | string | no | UUID row id of the newly minted key, for later rotate/revoke/update calls. |
api_key | string | no | The full key value — shown ONCE. |
key_prefix | string | no | First 20 chars of the key (aardvark_live_ or aardvark_secret_ plus a slice), shown for identification. |
mode | string | no | Key class: public (origin-gated, site-embedded) or secret (full account/CLI credential). |
label | string | no | Display nickname stored for the key; defaults to aardvark <mode> when none given. |
warnings | array<string> | no | Advisory notices, e.g. an unscoped public key accepting any origin or a risky wildcard origin. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/keys' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"mode": "public",
"label": "docs site",
"allowed_origins": [
"https://docs.example.com"
]
}'Response examples
{
"key_id": "string",
"api_key": "string",
"key_prefix": "string",
"mode": "string",
"label": "string",
"warnings": [
"string"
]
}https://gateway.aardvarkdocs.com/v1/keys/{id}Updates a key's label and/or a public key's allowed origins. At least one field is required; an omitted field is left unchanged. Non-owners may only update keys they created.
id | path | string | yes | Identifier of the key to update. |
Request body
label | string | no | New label (≤64 chars); omit to leave unchanged. |
allowed_origins | array<any> | no | New origin list for a public key; omit to leave unchanged, null to open to all. |
Responses
Body
allowed_origins | array<any> | no | Origin allowlist now set on the public key; null means any origin is accepted. |
warnings | array<string> | no | Non-fatal advisories, e.g. unrestricted-origin or shared-wildcard cautions about the new config. |
label | string | no | New display nickname after the rename; null when the label was cleared or omitted. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/keys/{id}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"allowed_origins": [],
"warnings": [
"string"
],
"label": "string"
}https://gateway.aardvarkdocs.com/v1/keys/{id}/revokePermanently revokes a PUBLIC key. Secret keys cannot be bare-revoked (rotate them instead) to avoid locking the owner out.
id | path | string | yes | Identifier of the public key to revoke. |
Responses
Body
revoked | boolean | no | Always true on success; a missing or non-public key returns a 404 error instead. |
key_id | string | no | Id of the public key that was revoked, echoing the path {id}. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/keys/{id}/revoke' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"revoked": true,
"key_id": "string"
}https://gateway.aardvarkdocs.com/v1/keys/{id}/rotateRevokes the key and mints a same-mode replacement atomically. The new value is shown once. Non-owners may only rotate keys they created; a demoted member cannot rotate the account secret key.
id | path | string | yes | Identifier of the key to rotate. |
Responses
Body
key_id | string | no | Id of the freshly minted replacement key (a new UUID). |
api_key | string | no | The full replacement key value — shown ONCE. |
key_prefix | string | no | Display prefix of the new key value (mode-dependent: public vs secret prefix). |
mode | string | no | Mode carried over to the replacement: public or secret. |
rotated_from | string | no | Id of the now-revoked original key this replacement supersedes. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/keys/{id}/rotate' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"key_id": "string",
"api_key": "string",
"key_prefix": "string",
"mode": "string",
"rotated_from": "string"
}Team & invites.
https://gateway.aardvarkdocs.com/v1/teamReturns the account's members. Owners/admins also see pending invites; plain members see members only.
Responses
Body
members | array<object> | no | Active members on the shared billing account, oldest membership (the owner) first. |
members[]. | string | no | Stable id of the member's user record. |
members[]. | string | no | Member’s login email, joined from the users table. |
members[]. | string | no | Member’s tier on the account: owner, admin, or member. |
members[]. | string | no | Membership state; always active here (invited/removed rows are excluded). |
members[]. | integer | no | Epoch-ms time the membership was created (account join). |
invites | array<object> | no | Pending unconsumed invites; present only for owner/admin callers, else empty. |
invites[]. | string | no | Email the invite was sent to (not yet accepted). |
invites[]. | string | no | Role the invite will grant on accept: member or admin. |
invites[]. | integer | no | Epoch-ms time the invite link expires (~7 days after issue). |
invites[]. | integer | no | Epoch-ms time the invite was issued; newest invites listed first. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/team' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"members": [
{
"user_id": "string",
"email": "string",
"role": "string",
"status": "string",
"created_at": 0
}
],
"invites": [
{
"email": "string",
"role": "string",
"expires_at": 0,
"created_at": 0
}
]
}https://gateway.aardvarkdocs.com/v1/team/inviteOwner/admin only. Emails a magic invite link (valid ~7 days). Owners may invite admins; admins may invite members only. Invites never grant owner. Returns 409 without sending when the plan's editor seats are already in use; acceptance rechecks the snapshotted allowance atomically. Otherwise the response is a neutral 200 regardless of delivery.
Request body
email | string | yes | Invitee email. |
role | string (member | admin) | yes | Offered role (member | admin). |
Responses
Body
ok | boolean | no | Always true; the neutral success acknowledgment (returned regardless of email delivery). |
email | string | no | Normalized email address the invite link was sent to. |
role | string | no | Role the invitee will hold on accepting; member or admin (never owner). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/team/invite' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"email": "teammate@example.com",
"role": "member"
}'Response examples
{
"ok": true,
"email": "string",
"role": "string"
}https://gateway.aardvarkdocs.com/v1/team/invite/revokeOwner/admin only. Cancels an unconsumed invite for an email. Idempotent (revoked: 0 when none pending).
Request body
email | string | yes | Invitee email to cancel. |
Responses
Body
ok | boolean | no | Always true once the request validates; the cancel ran (even if nothing matched). |
email | string | no | Normalized invitee email whose pending invite was targeted, echoed back. |
revoked | number | no | Count of pending (unconsumed) invite tokens deleted; 0 when none were pending. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/team/invite/revoke' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"email": "teammate@example.com"
}'Response examples
{
"ok": true,
"email": "string",
"revoked": 0
}https://gateway.aardvarkdocs.com/v1/team/removeOwner/admin only, with a last-owner guard. Admins may remove non-owners. Removal revokes the member's keys and deletes their invites first.
Request body
user_id | string | yes | Target member id. |
Responses
Body
ok | boolean | no | true once the member is removed and their keys/invites revoked. |
user_id | string | no | Echoes back the removed member's user id. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/team/remove' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"user_id": "u_abc123"
}'Response examples
{
"ok": true,
"user_id": "string"
}https://gateway.aardvarkdocs.com/v1/team/roleOwner/admin only, with a last-owner guard. Non-owners cannot grant or alter owner/admin. Demotions revoke the member's keys before the change.
Request body
user_id | string | yes | Target member id. |
role | string (owner | admin | member) | yes | New role (owner | admin | member). |
Responses
Body
ok | boolean | no | Always true when the role change was applied successfully. |
user_id | string | no | Identifier of the member whose role was changed. |
role | string | no | The member’s new role: owner, admin, or member. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/team/role' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"user_id": "u_abc123",
"role": "admin"
}'Response examples
{
"ok": true,
"user_id": "string",
"role": "string"
}Card & top-ups.
https://gateway.aardvarkdocs.com/v1/billingThe subscription-plan catalog (Free/Pro/Business/Enterprise — operator-editable data), the account's live subscription with its included-AI grant meter (dollars used, the account's own trailing burn rate, an estimated depletion date), the anomaly-breaker state, and recent subscription events. Owner/admin only, like the other billing surfaces.
Responses
Body
plans | array<object> | no | The plan catalog, cheapest first. |
plans[]. | string | no | Stable plan slug: free, pro, business, enterprise (operator may add more). |
plans[]. | string | no | Display name. |
plans[]. | number | no | Monthly platform price in USD (0 for Free and custom-only plans). |
plans[]. | number | no | Annual price for 12 months in USD (20% off the platform fee, with the grant funded monthly at par — an effective ~12% off the yearly total, up to ~13% on plans whose bundled allowance is a smaller share of the fee), or null when annual isn't offered. |
plans[]. | number | no | Included AI per month, in dollars of BILLED usage (the same units the ledger bills — never opaque credits). |
plans[]. | integer | no | The plan's published member markup over OpenRouter list cost, ×100 (150 = ×1.50 Free baseline, 140 = ×1.40 Pro, 130 = ×1.30 Business, 120 = ×1.20 Enterprise). |
plans[]. | integer | no | Editor seats included with the plan. |
plans[]. | number | no | Per-seat monthly price of an add-on editor seat on this plan, in USD (0 = the plan sells no add-on seats). Annual subscriptions bill seats at this rate ×12 at par. Exposed so a plan-change confirmation can disclose the seat-charge delta a switch imposes on an account already holding add-on seats. |
plans[]. | boolean | no | Whether the plan is open in the catalog (a retired plan keeps existing subscribers but takes no new ones). |
plans[]. | boolean | no | Whether the plan can be subscribed to directly (the Free/PAYG row is the 'no subscription' state and is never self-serve). |
subscription | object | no | The live subscription + grant meter: plan/status/interval (+ cancel_at when a cancellation is scheduled), grant (monthly/remaining/rollover/available USD + period bounds), overflow (mode/cap/used + the 2× acknowledgment), seats (add-on editor seats: included/addon/used/limit counts + seat_price_usd per-seat monthly price), burn (last-30-days USD, per-day rate, estimated depletion date), and max_bill_usd — the single worst-case-bill number. free_mode is always present as { active, until }; while active, complimentary AI usage is never charged or balance/grant-gated and max_bill_usd is 0, while GitHub Automations compute still bills prepaid balance. until is the exact epoch-ms cutoff or null for an indefinite grant. Null on the free pay-as-you-go plan. |
anomaly_paused | boolean | no | Whether the spend-velocity circuit breaker has paused paid AI (free models keep serving). |
events | array<object> | no | Up to 20 most recent subscription lifecycle events, newest first. |
events[]. | string | no | Event kind: subscribed, plan_changed, canceled, cancel_unscheduled, grant_reset, overflow_changed, payment_failed, payment_recovered, downgraded, paused, resumed, seats_changed. |
events[]. | string | no | Who performed it: owner, admin (a team admin acting for the account), operator, or system. |
events[]. | string | no | Event-specific JSON detail, or null. |
events[]. | integer | no | Epoch-ms time of the event. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/billing' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"plans": [
{
"id": "string",
"name": "string",
"price_usd": 0,
"price_annual_usd": 0,
"monthly_grant_usd": 0,
"markup_x100": 0,
"seats_included": 0,
"seat_price_usd": 0,
"active": true,
"self_serve": true
}
],
"subscription": {},
"anomaly_paused": true,
"events": [
{
"event": "string",
"actor": "string",
"detail": "string",
"ts": 0
}
]
}https://gateway.aardvarkdocs.com/v1/billing/cancelA Stripe-billed subscription cancels at PERIOD END (the customer keeps what they paid for; the webhook performs the downgrade at the boundary) — the scheduled end date is surfaced as the subscription’s cancel_at until then. Pass resume: true to UNDO a scheduled cancellation (409 no_pending_cancel when none is scheduled). An operator-granted subscription downgrades immediately. The prepaid balance is never touched by a lapse.
Request body
resume | boolean | no |
Responses
Body
resumed | boolean | no | true when a scheduled cancellation was undone (resume: true). |
subscription | object | no | The refreshed subscription payload (carries the updated cancel_at). |
canceled | boolean | no | true when a cancellation was scheduled (or performed immediately). |
at_period_end | boolean | no | true when the plan stays active until the paid period ends; false when the downgrade was immediate (operator-granted). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/billing/cancel' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"resumed": true,
"subscription": {},
"canceled": true,
"at_period_end": true
}Switch the live subscription to another plan (upgrades apply immediately; downgrades at the next boundary)
https://gateway.aardvarkdocs.com/v1/billing/change-planSwitches the live subscription to another plan. An UPGRADE (a higher-priced plan) applies IMMEDIATELY — the Stripe price is swapped with the difference prorated onto the next invoice, and the grant/markup/seats re-snapshot now. A DOWNGRADE (a lower-priced plan) is SCHEDULED for the next billing boundary with NO current-period proration: the current plan’s entitlement and billing continue unchanged until then, and the switch applies at that period’s invoice.paid (the response reports the scheduled plan via pending_plan, and switching back before the boundary unschedules it). At most ONE off-cycle re-grant applies per grant period regardless of how many times plans are swapped (swap-proof grant minting). Operator-managed (non-Stripe) subscriptions are refused — the operator re-plans via the admin surface.
Request body
plan | string | yes | Catalog plan id to switch to (must be self-serve). |
Responses
Body
changed | boolean | no | Always true on success. |
effective | string | no | |
subscription | object | no | The updated subscription + grant meter (same shape as GET /v1/billing’s subscription). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/billing/change-plan' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"changed": true,
"effective": "string",
"subscription": {}
}https://gateway.aardvarkdocs.com/v1/billing/overflowWhat happens when the monthly included AI runs out: cap_hold (default — paid AI pauses; the plan price is the worst-case bill), payg_fallback (overflow draws the prepaid balance at the plan’s member markup, up to the cap), or shutoff. Raising the cap past 2× the monthly grant requires the explicit acknowledgment.
Request body
mode | string (cap_hold | payg_fallback | shutoff) | yes | One of cap_hold, payg_fallback, shutoff. |
cap_usd | number | no | Per-period overflow ceiling in USD (omitted keeps the current cap; the default is 1× the monthly grant). |
ack_2x | boolean | no | Set true to acknowledge that overflow past 2× the grant bills at the member markup (sticky once given). |
Responses
Body
ok | boolean | no | Always true on success. |
mode | string | no | The saved overflow mode. |
cap_usd | number | no | The saved overflow cap in USD. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/billing/overflow' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true,
"mode": "string",
"cap_usd": 0
}https://gateway.aardvarkdocs.com/v1/billing/resume-aiLifts the spend-velocity circuit breaker's pause and prevents the same tripped UTC-day spend bucket from immediately re-triggering it; spend attributed to any other UTC day is evaluated normally. Works on every plan including Free — the breaker guards the pay-as-you-go tier too.
Responses
Body
resumed | boolean | no | Always true. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/billing/resume-ai' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"resumed": true
}https://gateway.aardvarkdocs.com/v1/billing/seatsSets the ABSOLUTE number of purchased add-on editor seats on a Stripe-billed subscription (migration 0045). The plan’s seats_included are free; each add-on seat bills at the plan’s per-seat monthly rate. Seats are block-and-buy — invites are refused with 403 seat_limit at the limit until more are bought here, so the bill never grows without this call. A REDUCTION can’t drop below the seats already occupied (members + pending invites). Operator-managed (non-Stripe) subscriptions are refused. A positive purchase on a plan that sells no add-on seats is refused with 400 seats_not_available, but a REMOVAL (seats: 0) is NOT blocked by that guard even after a plan’s per-seat price has been zeroed — so a customer holding a still-billing seat item can shed it rather than be trapped. (A removal is still subject to the same 400 seats_in_use floor as any reduction — it can’t drop the limit below the seats already occupied by members + pending invites — and to the suspended/closed-account guards.)
Request body
seats | integer | yes | The TOTAL add-on seat count (0–100, integer). Absolute, not a delta; 0 removes all add-on seats. |
Responses
Body
seats_included | integer | no | The plan's included seats (free). |
seats_addon | integer | no | The purchased add-on seat count now in effect. |
seat_price_usd | number | no | The current per-add-on-seat monthly price. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/billing/seats' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"seats_included": 0,
"seats_addon": 0,
"seat_price_usd": 0
}https://gateway.aardvarkdocs.com/v1/billing/subscribeCreates the Stripe subscription for a self-serve plan and grants the first month’s included AI immediately. Requires a card on file (see POST /v1/payment/checkout). Overflow defaults to cap-and-hold at 1× the grant, so the plan price is also the worst-case bill until the customer opts into fallback.
Request body
interval | string (month | year) | no | month (default) or year (annual discounts the platform fee only; the grant funds at par monthly). |
plan | string | yes | Catalog plan id to subscribe to (must be self-serve, e.g. pro or business). |
Responses
Body
subscribed | boolean | no | Always true on success. |
subscription | object | no | The new subscription + grant meter (same shape as GET /v1/billing’s subscription). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/billing/subscribe' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"subscribed": true,
"subscription": {}
}https://gateway.aardvarkdocs.com/v1/payment/autotopupSets the auto-top-up on/off state, charge amount, and low-balance trigger. At least one field is required; the trigger must be below the charge amount. Enabling requires a saved card and an amount. Owner/admin only.
Request body
enabled | boolean | no | Enable/disable auto top-up; omit to leave unchanged. |
amount_usd | number | no | Charge amount per top-up (≥ min, whole cents). |
low_balance_usd | number | no | Balance threshold that triggers a top-up (> 0). |
Responses
Body
auto_topup_enabled | boolean | no | Post-write on/off state of auto top-up after this update. |
auto_topup_amount_usd | number | no | Amount charged per auto top-up, in USD; null when none is stored. |
low_balance_usd | number | no | Low-balance trigger threshold in USD that arms an auto top-up. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/payment/autotopup' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"amount_usd": 50,
"low_balance_usd": 20
}'Response examples
{
"auto_topup_enabled": true,
"auto_topup_amount_usd": 0,
"low_balance_usd": 0
}https://gateway.aardvarkdocs.com/v1/payment/checkoutCreates (if needed) a Stripe customer and a hosted SetupIntent Checkout Session, returning the redirect URL. No body required. Owner/admin only.
Responses
Body
url | string | no | Redirect URL of the hosted Stripe SetupIntent Checkout Session for card entry. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/payment/checkout' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"url": "string"
}https://gateway.aardvarkdocs.com/v1/payment/methodServer-side re-reads the completed Checkout Session, verifies it belongs to this account, and stores the card on file. Idempotent on a given session_id. Owner/admin only.
Request body
session_id | string | yes | The Stripe Checkout Session id from the redirect. |
Responses
Body
card | object | no | Non-sensitive details of the card now saved on file, for display. |
card. | string | no | Card network brand (e.g. visa, mastercard); null if Stripe omitted it. |
card. | string | no | Last four digits of the saved card; null if unavailable. |
card. | integer | no | Card expiry month, 1–12; null if unavailable. |
card. | integer | no | Card expiry year, four-digit; null if unavailable. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/payment/method' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"session_id": "cs_test_abc123"
}'Response examples
{
"card": {
"brand": "string",
"last4": "string",
"exp_month": 0,
"exp_year": 0
}
}https://gateway.aardvarkdocs.com/v1/payment/methodClears the card on file (also disabling auto-top-up) and best-effort detaches it at Stripe. Idempotent; allowed even when card payments are disabled. Owner/admin only.
Responses
Body
removed | boolean | no | Always true; confirms the card on file was cleared and auto-top-up disabled. |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/payment/method' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"removed": true
}https://gateway.aardvarkdocs.com/v1/payment/topup-nowImmediately charges the saved card for amount_usd and credits the balance. Use a client idempotency_key to make retries safe. A pending charge returns { pending: true } and is credited by the webhook. Set reactivate: true to lift a self-serviceable (cost-unavailable) suspension before charging, so one call reactivates and tops up. Owner/admin only.
Request body
reactivate | boolean | no | When true, lift a self-serviceable cost-unavailable pause before charging (reactivate + top up in one call). |
amount_usd | number | yes | Amount to charge (≥ min, whole cents). |
idempotency_key | string | no | Client idempotency key (≤200 printable-ASCII chars). |
Responses
Body
pending | boolean | no | Present when the charge is still settling. |
balance_usd | number | no | New balance after the credit (on a synchronous charge). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/payment/topup-now' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"amount_usd": 50,
"idempotency_key": "topup-2026-06-25-1"
}'Response examples
{
"pending": true,
"balance_usd": 0
}Magic-link sign-in.
https://gateway.aardvarkdocs.com/auth/logoutDeletes the session row and clears the cookie. Requires the session cookie and the X-Aardvark-Dashboard CSRF header. Idempotent.
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
ok | boolean | no | Always true; the session row was deleted and the __Host-av_session cookie cleared. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/auth/logout' \
-H 'Cookie: __Host-av_session=YOUR_API_KEY'Response examples
{
"ok": true
}https://gateway.aardvarkdocs.com/auth/meReturns the authenticated user, the active account, the role there, and all memberships. Returns 401 { authenticated: false } when there is no valid session.
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
authenticated | boolean | no | true for a valid session; the 401 body instead carries false. |
user | object | no | The signed-in user identity (id and login email). |
user. | string | no | Stable user id of the signed-in account holder. |
user. | string | no | Login email of the signed-in user. |
active_account | string | no | Account id the session is currently scoped to for billing and /v1/* access. |
role | string | no | Caller’s role in active_account: one of owner, admin, or member. |
memberships | array<object> | no | All accounts the user is an active member of, for the account switcher. |
memberships[]. | string | no | Account id of this membership. |
memberships[]. | string | no | User’s role on that account: owner, admin, or member. |
memberships[]. | string | no | Owner email of that account, shown to identify it in the switcher. |
sso_confined | boolean | no |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/auth/me' \
-H 'Cookie: __Host-av_session=YOUR_API_KEY'Response examples
{
"authenticated": true,
"user": {
"id": "string",
"email": "string"
},
"active_account": "string",
"role": "string",
"memberships": [
{
"account_id": "string",
"role": "string",
"owner_email": "string"
}
],
"sso_confined": true
}https://gateway.aardvarkdocs.com/auth/request-linkEmails a single-use magic link to the address. Neutral 200 regardless of whether the email exists (no account enumeration). Rate limited per IP and per email.
Request body
email | string | yes | Email to send the sign-in link to. |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
ok | boolean | no | Always true; the response is neutral and never signals whether the email exists. |
message | string | no | Neutral confirmation prose shown regardless of outcome, avoiding account enumeration. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/auth/request-link' \
-H 'Content-Type: application/json' \
-d '{
"email": "user@example.com"
}'Response examples
{
"ok": true,
"message": "string"
}https://gateway.aardvarkdocs.com/auth/switchRotates the session to a different account the user belongs to. Requires the session cookie and the X-Aardvark-Dashboard CSRF header. Rate limited per user.
Request body
account_id | string | yes | Target account id to switch to. |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
ok | boolean | no | Always true once the session is rotated to the target account. |
active_account | string | no | Account id the session is now active on, matching the requested account_id. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/auth/switch' \
-H 'Cookie: __Host-av_session=YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"account_id": "a_abc123"
}'Response examples
{
"ok": true,
"active_account": "string"
}https://gateway.aardvarkdocs.com/auth/verifyServes a tiny nonce-CSP HTML page that reads the token from the URL fragment and POSTs it to /auth/verify. The token never reaches the server as a query string.
Try it now unavailable
This endpoint serves the magic-link verification HTML page, not a cross-origin JSON API request. Open the magic link in your browser or start the flow from the dashboard instead.
Responses
Body
A single string value.
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/auth/verify'Response examples
"string"https://gateway.aardvarkdocs.com/auth/verifyThe token in the body is the credential. On success sets the __Host-av_session cookie. NOTE: this endpoint’s responses use the non-standard shape { ok, error } (read by the landing page’s script), not the usual error envelope.
Request body
token | string | yes | The magic-link token from the URL fragment. |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
ok | boolean | no | true when the token was consumed and the __Host-av_session cookie was minted; false carries an error code. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/auth/verify' \
-H 'Content-Type: application/json' \
-d '{
"token": "<base64url-token>"
}'Response examples
{
"ok": true
}Enterprise SSO & provisioning.
https://gateway.aardvarkdocs.com/auth/saml/acsThe Assertion Consumer Service (HTTP-POST binding). Strictly validates the signed SAMLResponse against the account’s pinned certificate (single signed assertion; enveloped-signature; exclusive-c14n digest; RSA-SHA256; audience/recipient/InResponseTo; replay cache), then mints the session. Only served when the gateway has SAML enabled — that disabled surface is the one failure here answered with the JSON error envelope (404); every other failure a browser can land on renders the styled SSO page instead.
Request body
SAMLResponse | string | yes | Base64 signed SAML Response from the IdP (HTTP-POST binding). Capped at 1,000,000 characters; an oversized value is rejected as a 400, while a raw request body over 1,100,000 bytes is a 413. |
RelayState | string | yes | The single-use state key minted at POST /auth/sso/begin, echoed back by the IdP. Matched against the browser binder cookie, then consumed. |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
A single string value.
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/auth/saml/acs'Response examples
"string"https://gateway.aardvarkdocs.com/auth/saml/metadataThe SP EntityDescriptor XML the customer uploads to their IdP. Only served when the gateway has SAML enabled. The SP entity id is <origin>/auth/saml/metadata?account=<id>; the ACS is <origin>/auth/saml/acs.
account | query | string | yes | The account id whose SP metadata to render. |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
A single string value.
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/auth/saml/metadata?account={account}'Response examples
"string"https://gateway.aardvarkdocs.com/auth/sso/beginResolve the enabled IdP by the email’s domain and return the next hop: for OIDC, redirect_url (an authorization URL with state + nonce + S256 PKCE); for SAML, handoff_url (a same-origin gateway page that auto-POSTs the AuthnRequest to the IdP under an IdP-scoped CSP). No session required — this is the pre-login surface.
Request body
email | string | yes | The user's email; its domain selects the account's IdP. |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
type | string | no | |
redirect_url | string | no | |
handoff_url | string | no |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/auth/sso/begin'Response examples
{
"type": "string",
"redirect_url": "string",
"handoff_url": "string"
}https://gateway.aardvarkdocs.com/auth/sso/callbackThe OIDC redirect_uri. Consumes the single-use state, exchanges the code (client secret + PKCE), verifies the id_token (RS256 via JWKS; iss/aud/exp/iat/nonce; verified email), then mints the dashboard session and redirects to /dashboard. Renders an HTML result page.
code | query | string | no | |
state | query | string | no |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
A single string value.
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/auth/sso/callback?code={code}&state={state}'Response examples
"string"https://gateway.aardvarkdocs.com/auth/sso/saml-handoffThe gateway-hosted SAML handoff page (SAML-enabled deployments only). The dashboard’s form-action 'none' CSP can’t POST the AuthnRequest to the IdP, so begin returns a handoff_url here; this page is a fresh document whose CSP permits form-action only to the configured IdP’s SSO URL, and it auto-submits the AuthnRequest (SAMLRequest + RelayState). Reads the state without consuming it (the ACS consumes it on the IdP postback). Renders HTML.
rs | query | string | no |
Try it now unavailable
This auth endpoint is same-origin to the gateway dashboard, so browser calls from this docs page are blocked by CORS. Use a generated request sample or the dashboard instead.
Responses
Body
A single string value.
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/auth/sso/saml-handoff?rs={rs}'Response examples
"string"https://gateway.aardvarkdocs.com/v1/audit/export.csvA CSV of the account’s lifecycle audit trail — account status changes, subscription events, payment events, API-key created/revoked, and SSO/SCIM security events (category sso: config saves, domain verifications, SCIM token mint/revoke, provisioning) — unioned into ts,category,event,actor,detail, newest first, capped at 10k rows (X-Aardvark-Export-Truncated when hit). Billing-manager + Business/Enterprise plan.
Responses
Headers
X-Aardvark-Export-Truncated | string (true) | Present (value true) only when the 10,000-row export cap was hit and older rows were dropped; ABSENT otherwise, never false. Readable same-origin only — it is not listed in Access-Control-Expose-Headers, so a cross-origin browser fetch reads null. |
Body
A single string value.
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/audit/export.csv' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
"string"https://gateway.aardvarkdocs.com/v1/sso/configThe account’s identity-provider configuration with the OIDC client secret masked, plus saml_enabled (whether this gateway exposes the SAML option). Dashboard-authed and owner-only (an admin/billing-manager is refused with 403 forbidden). The read is NOT plan-gated: a downgraded or lapsed account still receives 200 with plan_gated: true (anti-lockout) so it can view — and DELETE — an existing config; a GET never returns 403 plan_required. Owner only.
Responses
Body
configured | boolean | no | Whether an IdP is configured for this account. |
plan_gated | boolean | no | True when the account's plan can't manage SSO config (Free/lapsed) — the dashboard shows upgrade guidance while still allowing an existing config to be removed. (The handler returns a boolean; the extractor otherwise infers it as a string.) |
saml_enabled | boolean | no | Whether this gateway exposes the SAML option at all (server-wide toggle). |
type | string | no | oidc or saml, or null when unconfigured. |
enabled | boolean | no | Whether the IdP participates in login and domain resolution. |
routing_active | boolean | no | |
enforce_sso | boolean | no | Whether non-owner members of this account must sign in via SSO. |
jit_provisioning | boolean | no | Whether an unknown but domain-matching email is auto-provisioned as a member on first SSO login. |
email_domain | string | no | The corporate login domain bound to this IdP, or null when unconfigured. |
issuer | string | no | OIDC: the discovery issuer (validated to equal the id_token iss), or null. |
discovery_url | string | no | OIDC: the configured .well-known/openid-configuration URL, or null. |
client_id | string | no | OIDC client id, or null. |
client_secret_masked | string | no | The OIDC client secret masked (•••• + last 4, or fully masked when short) — NEVER the clear value. |
authorization_endpoint | string | no | OIDC authorization endpoint captured from discovery, or null. |
token_endpoint | string | no | OIDC token endpoint captured from discovery, or null. |
jwks_uri | string | no | OIDC JWKS URI captured from discovery (id_token signature verification), or null. |
idp_entity_id | string | no | SAML: the IdP EntityID, or null. |
idp_sso_url | string | no | SAML: the IdP SingleSignOnService URL, or null. |
has_saml_cert | boolean | no | SAML: whether a pinned signing certificate is stored (the PEM itself is never returned). |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/sso/config' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"configured": true,
"plan_gated": true,
"saml_enabled": true,
"type": "string",
"enabled": true,
"routing_active": true,
"enforce_sso": true,
"jit_provisioning": true,
"email_domain": "string",
"issuer": "string",
"discovery_url": "string",
"client_id": "string",
"client_secret_masked": "string",
"authorization_endpoint": "string",
"token_endpoint": "string",
"jwks_uri": "string",
"idp_entity_id": "string",
"idp_sso_url": "string",
"has_saml_cert": true
}https://gateway.aardvarkdocs.com/v1/sso/configConfigure the account’s IdP. For type: "oidc" the gateway fetches the discovery document server-side (HTTPS-only, private hosts refused) and captures the issuer + endpoints. For type: "saml" (only when the gateway has SAML enabled) it stores the pinned entity id, SSO URL, and signing certificate. Which provider fields are mandatory depends on type: only type and email_domain are required of every request, and the body is a oneOf over one complete schema per type, selected by the type discriminator, each requiring the extra fields that type demands. Omitting client_secret/idp_cert_pem on an edit preserves the stored value — which is why neither branch REQUIRES them even though a FIRST save of that type does. Owner-only, Business/Enterprise plan (403 plan_required otherwise). Owner only.
Request body
Exactly one of these shapes:
type | string (oidc) | yes | oidc or saml. |
email_domain | string | yes | The corporate login domain, e.g. acme.com — a sign-in email in this domain resolves to this IdP. |
enabled | boolean | no | Whether the IdP participates in login and domain resolution. |
enforce_sso | boolean | no | Require SSO for non-owner members of this account (owners keep magic-link as the anti-lockout escape hatch). |
jit_provisioning | boolean | no | Auto-provision an unknown but domain-matching email as a member on first SSO login. |
discovery_url | string | yes | OIDC: the .well-known/openid-configuration URL (fetched + validated server-side). |
client_id | string | yes | OIDC client id. |
client_secret | string | no | OIDC client secret (write-only; masked on read). Required on the first OIDC configuration; omit it on later edits to preserve the stored value. |
idp_entity_id | string | no | SAML: the IdP EntityID (the Response/Assertion Issuer). |
idp_sso_url | string | no | SAML: the IdP SingleSignOnService URL. |
idp_cert_pem | string | no | SAML: the pinned signing certificate (PEM). The ONLY trust anchor for assertion signatures. Required on the first SAML configuration; omit it on later edits to preserve the stored certificate. |
Responses
Body
ok | boolean | no | True when the config was saved. |
configured | boolean | no | Whether an IdP is now configured. |
type | string | no | The saved IdP type (oidc or saml). |
enabled | boolean | no | Whether the IdP is enabled for login/domain resolution. |
enforce_sso | boolean | no | Whether SSO is enforced for non-owner members. |
jit_provisioning | boolean | no | Whether just-in-time member provisioning is on. |
email_domain | string | no | The corporate login domain bound to this IdP. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sso/config' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true,
"configured": true,
"type": "string",
"enabled": true,
"enforce_sso": true,
"jit_provisioning": true,
"email_domain": "string"
}https://gateway.aardvarkdocs.com/v1/sso/configRemove the account’s IdP configuration (also clears enforce_sso). Owner-only. Unlike the POST upsert, DELETE is PLAN-EXEMPT (anti-lockout): a downgraded or lapsed account can always tear down its IdP config, so a lapsed plan can never leave a team locked into an enforce_sso config it can’t remove. Owner only.
Responses
Body
deleted | boolean | no |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/sso/config' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"deleted": true
}https://gateway.aardvarkdocs.com/v1/sso/domainList the account’s SSO domain-ownership records and their verification status (migration 0056). A domain must be verified before an IdP can be ENABLED for it. UNVERIFIED (including EXPIRED — proofs age out) rows also echo the DNS TXT challenge (record_name/record_type/record_value, same as the POST) so the record survives a dashboard reload; currently-verified rows omit it. Owner-only. PLAN-EXEMPT (anti-lockout teardown): listing stays available after a downgrade — alongside the domain DELETE — so a lapsed-plan owner can still see and remove a domain proof; only ADDING/verifying a domain (and configuring an IdP) requires the Business/Enterprise plan. Owner only.
Responses
Body
domains | array<object> | no | The account's domain-verification records. |
domains[]. | string | no | The claimed login domain, e.g. acme.com. |
domains[]. | boolean | no | Whether the DNS TXT challenge is currently confirmed AND unexpired (a proof older than the max age is reported unverified, and its challenge is re-echoed). |
domains[]. | integer | no | Epoch-ms verification time, or null if not yet verified. |
domains[]. | string | no | UNVERIFIED rows only: the DNS record name to create, e.g. _aardvark-verify.acme.com. |
domains[]. | string | no | UNVERIFIED rows only: the DNS record type to create (TXT). |
domains[]. | string | no | UNVERIFIED rows only: the exact TXT value to publish (carries the verification token). |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/sso/domain' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"domains": [
{
"domain": "string",
"verified": true,
"verified_at": 0,
"record_name": "string",
"record_type": "string",
"record_value": "string"
}
]
}https://gateway.aardvarkdocs.com/v1/sso/domainMint (or return the existing) DNS TXT challenge the account must publish to prove it controls domain before SSO can be enabled for it (migration 0056). The token is stable across re-requests. Owner-only, Business/Enterprise plan. Owner only.
Request body
domain | string | yes | The login domain to claim, e.g. acme.com. |
Responses
Body
domain | string | no | The normalized domain the challenge applies to. |
verified | boolean | no | Whether this domain is already verified. |
record_name | string | no | The DNS record name to create, e.g. _aardvark-verify.acme.com. |
record_type | string | no | The DNS record type to create (TXT). |
record_value | string | no | The exact TXT value to publish (carries the verification token). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sso/domain' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"domain": "string",
"verified": true,
"record_name": "string",
"record_type": "string",
"record_value": "string"
}https://gateway.aardvarkdocs.com/v1/sso/domainRemove a domain-ownership record by domain (query parameter). Owner-only. PLAN-EXEMPT (anti-lockout teardown): a downgraded or lapsed account can always remove a domain proof — alongside the domain GET listing — so it’s never locked into an enforced config it can’t dismantle. Removing the proof also disables any IdP still enabled for that domain, so the enabled ⟹ verified invariant holds. Owner only.
domain | query | string | yes |
Responses
Body
deleted | boolean | no | True if a matching domain record was removed. |
idp_disabled | boolean | no | True if an IdP that was enabled for this domain got disabled as a result (removing the ownership proof can't leave SSO routing for an unverified domain). |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/sso/domain?domain={domain}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"deleted": true,
"idp_disabled": true
}https://gateway.aardvarkdocs.com/v1/sso/domain/verifyResolve the DNS TXT challenge for domain and, if the issued token is present, mark the domain verified (migration 0056). Idempotent; a missing/mismatched record returns 400 verification_failed (retry after DNS propagates). Owner-only, Business/Enterprise plan. Owner only.
Request body
domain | string | yes | The domain to verify (a challenge must have been requested first). |
Responses
Body
domain | string | no | The domain that was verified. |
verified | boolean | no | True when the TXT challenge matched and the domain is now verified. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sso/domain/verify' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"domain": "string",
"verified": true
}https://gateway.aardvarkdocs.com/v1/sso/scim-tokenList the account’s active SCIM tokens (id, label, created, last used) — never the token value. Owner-only. PLAN-EXEMPT (anti-lockout teardown): a downgraded account can still discover a live provisioning credential in order to revoke it; only minting stays plan-gated. Owner only.
Responses
Body
tokens | array<object> | no | The account's active SCIM tokens. |
tokens[]. | string | no | Token id (used to revoke). |
tokens[]. | string | no | Human label supplied at mint, or null. |
tokens[]. | integer | no | Epoch-ms mint time. |
tokens[]. | integer | no | Epoch-ms of the token's last successful SCIM request, or null if never used. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/sso/scim-token' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"tokens": [
{
"id": "string",
"label": "string",
"created_at": 0,
"last_used_at": 0
}
]
}https://gateway.aardvarkdocs.com/v1/sso/scim-tokenMint a bearer token for the SCIM v2 provisioning surface (/scim/v2/*). The raw aardvark_scim_… value is returned ONCE; only its SHA-256 hash is stored. Owner-only, Business/Enterprise plan (403 plan_required otherwise) — minting a new provisioning credential is a plan capability. (Listing and revoking existing tokens, below, stay plan-exempt for anti-lockout.) Owner only.
Request body
label | string | no | Optional human label to identify the token later. |
Responses
Body
id | string | no | The new token's id (use it to revoke). |
label | string | no | The label supplied at mint, or null. |
token | string | no | The raw aardvark_scim_… bearer value — shown ONCE and never retrievable again. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sso/scim-token' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"id": "string",
"label": "string",
"token": "string"
}https://gateway.aardvarkdocs.com/v1/sso/scim-tokenRevoke a SCIM token by id (query parameter). Owner-only. PLAN-EXEMPT (anti-lockout teardown): a downgraded account can always revoke a live — possibly compromised — provisioning credential without upgrading. Owner only.
id | query | string | yes |
Responses
Body
revoked | boolean | no | True if a matching un-revoked token was revoked. |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/sso/scim-token?id={id}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"revoked": true
}Stripe webhooks.
https://gateway.aardvarkdocs.com/v1/stripe/webhookStripe-to-server webhook authenticated by the Stripe-Signature header (HMAC over the raw body). Handles payment_intent.succeeded (durable credit) and payment_intent.payment_failed (audit + auto-top-up streak), plus the subscription lifecycle (migration 0044): customer.subscription.created/customer.subscription.updated (snapshot sync, plan reconcile, lost-insert heal), customer.subscription.deleted (downgrade to Free), invoice.paid (billing history, past-due recovery, scheduled-downgrade apply at the boundary), and invoice.payment_failed (dunning + past_due grace clock). Acks 200 once a delivery is handled or irrelevant; deliberately returns 500 on transient read/write failures so Stripe redelivers instead of losing a money event.
Request body
Map of string keys to any values.
Try it now unavailable
This endpoint is server-to-server only, so browser calls from this docs page are blocked by CORS. Use a generated request sample from your backend instead.
Responses
Body
received | boolean | no | Always true; acks the verified delivery so Stripe stops its retry storm. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/stripe/webhook' \
-H 'Stripe-Signature: YOUR_API_KEY'Response examples
{
"received": true
}Docs quality checks.
https://gateway.aardvarkdocs.com/v1/github/capabilitiesThe static catalog of AI authoring capabilities (e.g. keyword and description generation, the style-guide pass) that can be enabled to run on a connected repo. Readable by any authenticated dashboard user.
Responses
Body
capabilities | string | no | The catalog of available authoring capabilities, each with its id, label, and runner command. |
style_rulesets | array<object> | no | The style rulesets selectable for the styleguide capability — {id, label} pairs in catalog order. |
style_rulesets[]. | string | yes | |
style_rulesets[]. | string | yes |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/github/capabilities' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"capabilities": "string",
"style_rulesets": [
{
"id": "string",
"label": "string"
}
]
}https://gateway.aardvarkdocs.com/v1/github/configureDeclarative per-repo automation config: for each capability set whether it’s enabled, its schedule (cron, floored to at most once per hour), run-on-push, base branch, and project dir. The styleguide capability additionally REQUIRES rulesets: a non-empty, duplicate-free array of style ruleset ids (see style_rulesets on GET /v1/github/connection) in precedence order — index 0 wins conflicts; rulesets is rejected on every other capability. A pure DB apply — no GitHub writes. Owner only. Owner only.
Request body
repo | string | yes | Target repo in owner/name format. |
automations | array<object> | yes | Array of per-capability automation configs to apply (last-write-wins per capability). Enabling styleguide requires rulesets (non-empty, known ids, no duplicates, precedence-ordered). |
automations[]. | string | yes | |
automations[]. | boolean | no | |
automations[]. | boolean | no | |
automations[]. | boolean | no | |
automations[]. | string | no | |
automations[]. | string | no | |
automations[]. | string | no | |
automations[]. | array<string> | no |
Responses
Body
repo | string | no | Echoes the configured repo owner/name. |
automations | array<object> | no | The repo's automation rows after the apply. |
automations[]. | string | no | Capability id this automation runs. |
automations[]. | string | no | Whether the automation is active after the apply. |
automations[]. | string | no | Whether a matching push fires the automation. |
automations[]. | boolean | no | When true, a run-on-push fire restyles only the pages that push changed. Requires run_on_push and a scope-capable capability; ignored for cron. |
automations[]. | string | no | Resolved 5-field cron schedule, or null when unscheduled. |
automations[]. | string | no | Branch the automation runs against, or null for the repo default. |
automations[]. | string | no | Subdirectory the vark project lives in, or null for the repo root. |
automations[]. | array<string> | no | Styleguide only: the applied style ruleset ids in precedence order; null for capabilities that take none. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/configure' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"repo": "acme/docs",
"automations": [
{
"capability": "keywords",
"enabled": true,
"run_on_push": true,
"cron": "0 9 * * 1",
"base_branch": "main"
},
{
"capability": "styleguide",
"enabled": true,
"cron": "0 6 * * 1",
"rulesets": [
"microsoft",
"google"
]
}
]
}'Response examples
{
"repo": "string",
"automations": [
{
"capability": "string",
"enabled": "string",
"run_on_push": "string",
"run_on_push_diff_only": true,
"cron": "string",
"base_branch": "string",
"project_dir": "string",
"rulesets": [
"string"
]
}
]
}https://gateway.aardvarkdocs.com/v1/github/connectMints a single-use install state and returns the GitHub App install URL carrying it. The browser follows that URL; GitHub echoes state back to the setup callback, which binds the installation to this account. Owner only. Owner only.
Responses
Body
install_url | string | no | GitHub App install URL with the single-use state embedded; redirect the browser here to start the install. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/connect' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"install_url": "string"
}https://gateway.aardvarkdocs.com/v1/github/connectionEverything the dashboard's Docs Quality Checks page needs: whether the integration is configured, the install-URL slug, the account's installations, and each connected repo with its per-capability automation config.
Responses
Body
configured | boolean | no | Whether the gateway is fully configured for the integration (app creds, slug, webhook secret, OAuth creds). |
app_slug | string | no | The GitHub App's URL slug used to build the install URL, or null when unset. |
capabilities | string | no | The static catalog of AI authoring capabilities that can be enabled per repo. |
style_rulesets | array<object> | no | The static catalog of style rulesets selectable for the styleguide capability — {id, label} pairs in catalog order. Render labels from here; the ids are the values accepted in rulesets. |
style_rulesets[]. | string | yes | |
style_rulesets[]. | string | yes | |
installations | array<object> | no | GitHub App installations bound to this account. |
installations[]. | string | no | GitHub's numeric installation id. |
installations[]. | string | no | The org/user login the app is installed on. |
installations[]. | string | no | Installation account type, e.g. Organization or User. |
installations[]. | boolean | no | true when GitHub has suspended the installation. |
installations[]. | boolean | no | true when GitHub no longer recognizes this installation id (the app was reinstalled) — reconnect to fix. |
repos | array<object> | no | Repos reachable through the installations, each with its automation config. |
repos[]. | string | no | Repo owner/name. |
repos[]. | string | no | Repo default branch (the automation base when none is set). |
repos[]. | string | no | Whether the repo is private. |
repos[]. | string | no | Installation that grants access to this repo. |
repos[]. | integer | no | GitHub’s numeric repo id (stable across renames); pass as repo_id to POST /v1/sites to bind a hosted site. |
repos[]. | integer | no | true when the repo has at least one automation set up. |
repos[]. | array<object> | no | Per-capability automation rows configured on the repo. |
repos[]. | string | no | Capability id this automation runs. |
repos[]. | string | no | Whether the automation is active. |
repos[]. | string | no | Whether a matching push fires the automation. |
repos[]. | boolean | no | When true, a run-on-push fire restyles only the pages that push changed (not the whole docset). Only meaningful for a scope-capable capability with run_on_push; it never affects a cron fire. |
repos[]. | string | no | Schedule (5-field cron, at most hourly), or null. |
repos[]. | string | no | Branch the automation runs against, or null for the repo default. |
repos[]. | string | no | Subdirectory the vark project lives in, or null for the repo root. |
repos[]. | array<string> | no | Styleguide only: selected style ruleset ids in precedence order (index 0 wins conflicts). null = no selection stored — a legacy styleguide row that won’t dispatch until re-saved with rulesets, or a capability that takes none. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/github/connection' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"configured": true,
"app_slug": "string",
"capabilities": "string",
"style_rulesets": [
{
"id": "string",
"label": "string"
}
],
"installations": [
{
"installation_id": "string",
"github_login": "string",
"account_type": "string",
"suspended": true,
"stale": true
}
],
"repos": [
{
"full_name": "string",
"default_branch": "string",
"private": "string",
"installation_id": "string",
"repo_id": 0,
"configured": 0,
"automations": [
{
"capability": "string",
"enabled": "string",
"run_on_push": "string",
"run_on_push_diff_only": true,
"cron": "string",
"base_branch": "string",
"project_dir": "string",
"rulesets": [
"string"
]
}
]
}
]
}https://gateway.aardvarkdocs.com/v1/github/disconnectStops all automations for a repo by dropping their config rows in one atomic delete. Leaves the app installed (uninstall happens in GitHub) and the repo listed so it can be reconfigured. Owner only. Owner only.
Request body
repo | string | yes | Target repo in owner/name format. |
Responses
Body
disconnected | boolean | no | Always true once the repo’s automations are removed. |
repo | string | no | Echoes the repo that was disconnected. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/disconnect' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"repo": "acme/docs"
}'Response examples
{
"disconnected": true,
"repo": "string"
}https://gateway.aardvarkdocs.com/v1/github/runDispatches a configured capability immediately on the central runner. The run is recorded as queued and advanced by the runner’s claim/complete callbacks. A balance or runner-config problem returns 402/503; an already-running capability returns 409; a styleguide automation with no stored ruleset selection (a legacy row from before rulesets existed) returns 409 rulesets_required until it’s re-saved with rulesets picked. Owner only. Owner only.
Request body
repo | string | yes | Target repo in owner/name format. |
capability | string | yes | Capability id to run; must be enabled for the repo. |
path | string | no | Optional page scope for this run only — a file or directory (relative to the project dir) to restyle instead of the whole docset. Only valid for a page-authoring capability (styleguide, keywords, description); does not persist. |
Responses
Body
dispatched | boolean | no | Always true when the run was queued on the central runner. |
run_id | string | no | Server-minted UUID of the queued run, for correlating later run-history rows. |
repo | string | no | Echoes the repo the run was dispatched for. |
capability | string | no | Echoes the capability the run executes. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/run' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"repo": "acme/docs",
"capability": "keywords"
}'Response examples
{
"dispatched": true,
"run_id": "string",
"repo": "string",
"capability": "string"
}https://gateway.aardvarkdocs.com/v1/github/run/cancelCancels the active queued or in-progress run for a repo/capability pair, revokes any already-minted ephemeral inference key, and best-effort cancels the backing GitHub Actions run. Idempotent: idle pairs return cancelled: false. Owner only.
Request body
repo | string | yes | Target repo in owner/name format. |
capability | string | yes | Capability id whose active run should be cancelled. |
Responses
Body
cancelled | boolean | yes | true when an active run was sealed as cancelled; false when no matching run was active. |
run_id | string | no | Server-minted UUID of the cancelled run. Present only when cancelled is true. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/run/cancel' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"repo": "acme/docs",
"capability": "keywords"
}'Response examples
{
"cancelled": true,
"run_id": "string"
}https://gateway.aardvarkdocs.com/v1/github/runner/claimCentral-runner callback: the runner claims a queued run and receives an ephemeral inference key plus a repo-scoped GitHub token after the claim CAS wins. An exact same-Actions-run deploy retry is idempotent: it keeps the already-bound one-time inference key, omits that secret from the response, and reissues a least-privilege repo token. Authed by the runner credential (a GitHub Actions OIDC JWT, verified against GitHub's JWKS), never a dashboard session.
Request body
run_id | string | yes | The gateway run UUID being claimed. |
github_run_id | integer | yes | The runner's GitHub Actions run id (positive integer), bound to the run for callback correlation. |
Try it now unavailable
This endpoint is server-to-server only, so browser calls from this docs page are blocked by CORS. Use a generated request sample from your backend instead.
Responses
Body
claim_recovered | boolean | no | False for an initial claim; true only when an exact same-Actions-run deploy retry recovers after an earlier successful claim. |
inference_key | string | no | Ephemeral, per-run secret inference key — returned only by the initial successful claim; omitted from an exact same-run deploy recovery response. |
repo_token | string | no | Short-lived GitHub token scoped to the customer repo: authoring claims get contents and pull-requests write, while deploy claims get contents read. |
command | string | no | The vark runner command to execute for this capability. |
full_name | string | no | Customer repo owner/name the run targets. |
installation_id | string | no | Installation id whose token grants access to the customer repo. |
base_branch | string | no | Branch to run against, or null for the repo default. |
project_dir | string | no | Subdirectory the vark project lives in, or null for the repo root. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/runner/claim' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"run_id": "1f0c…",
"github_run_id": 1234567890
}'Response examples
{
"claim_recovered": true,
"inference_key": "string",
"repo_token": "string",
"command": "string",
"full_name": "string",
"installation_id": "string",
"base_branch": "string",
"project_dir": "string"
}https://gateway.aardvarkdocs.com/v1/github/runner/completeCentral-runner callback: reports a finished run. Revokes the run's ephemeral key (stops spend), meters the compute, and records the conclusion plus the PR it opened. Idempotent; a late callback can top up a $0-sealed run. Authed by the runner credential.
Request body
github_run_id | integer | yes | The runner’s GitHub Actions run id; under OIDC it must match the token’s run_id claim. |
run_id | string | yes | The gateway run UUID being completed. |
conclusion | string | no | The GitHub Actions conclusion string (e.g. success, failure); unknown non-empty values normalize to failure. |
billable_ms | number | no | Authoritative billable wall-clock for the run, in milliseconds. |
pr_url | string | no | URL of the PR the run opened in the customer repo (must be an https github.com PR in that repo). |
Try it now unavailable
This endpoint is server-to-server only, so browser calls from this docs page are blocked by CORS. Use a generated request sample from your backend instead.
Responses
Body
ok | boolean | no | Always true once the run is finalized (or already was). |
already_finalized | boolean | no | Present and true when the run was already billed — an idempotent no-op. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/runner/complete' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"run_id": "1f0c…",
"github_run_id": 1234567890,
"conclusion": "success",
"billable_ms": 42000,
"pr_url": "https://github.com/acme/docs/pull/7"
}'Response examples
{
"ok": true,
"already_finalized": true
}https://gateway.aardvarkdocs.com/v1/github/runner/deploy-fileCentral-runner callback for managed-hosting deploys: streams ONE built site file per request (raw body) into the deploy’s immutable R2 prefix. Query params: run (the gateway run UUID), gh_run (the Actions run id, bound to the OIDC token), and path (urlencoded site-relative file path — traversal shapes are rejected). Enforces the per-file/per-deploy budgets (25MB/file, 10k files, 500MB total) and stamps the content type from the shared extension map. Authed by the runner credential, never a dashboard session.
gh_run | query | integer | yes | The positive GitHub Actions run id bound to the runner OIDC token. |
run | query | string | yes | The gateway run UUID for this deploy. |
path | query | string | yes | URL-encoded site-relative output path. |
Content-Length | header | integer | yes | Exact raw-body size in bytes; required for the per-file and per-deploy upload budgets. |
Request body
A single string value.
Try it now unavailable
This endpoint is server-to-server only, so browser calls from this docs page are blocked by CORS. Use a generated request sample from your backend instead.
Responses
Body
ok | boolean | no | Always true once the file is stored. |
path | string | no | Echoes the stored site-relative path. |
Request samples
curl -X PUT 'https://gateway.aardvarkdocs.com/v1/github/runner/deploy-file?gh_run={gh_run}&run={run}&path={path}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"ok": true,
"path": "string"
}https://gateway.aardvarkdocs.com/v1/github/runner/deploy-finalizeCentral-runner callback for managed-hosting deploys: every file is uploaded, so flip the deploy LIVE — supersede the previous live deploy for the (site, branch) and write the routes/<hostname> pointer object(s) the sites-worker serves from. Query param run carries the gateway run UUID. Idempotent (a retry re-writes the pointers). Compute metering still happens on the normal complete callback. Authed by the runner credential.
run | query | string | yes |
Request body
github_run_id | integer | yes | The runner’s GitHub Actions run id; under OIDC it must match the token’s run_id claim and the run’s own claimed id. |
Try it now unavailable
This endpoint is server-to-server only, so browser calls from this docs page are blocked by CORS. Use a generated request sample from your backend instead.
Responses
Body
ok | boolean | no | Always true once the deploy is live. |
live | boolean | no | Always true on success. |
already_live | boolean | no | true when this finalize was a retry of an already-live deploy. |
deploy_id | string | no | The deploy row's UUID. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/runner/deploy-finalize?run={run}' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"github_run_id": 1234567890
}'Response examples
{
"ok": true,
"live": true,
"already_live": true,
"deploy_id": "string"
}https://gateway.aardvarkdocs.com/v1/github/runsRun history for a connected repo, newest first, optionally filtered by capability. Each row carries status, conclusion, the PR the run opened, and the metered compute cost.
repo | query | string | yes | Repo owner/name to list runs for (required). |
capability | query | string | no | Restrict to one capability's runs. |
limit | query | integer | no | Max rows to return (default 50, capped at 200). |
Responses
Body
repo | string | no | Echoes the queried repo owner/name. |
runs | array<object> | no | Run-history rows, newest first. |
runs[]. | string | no | Stable run UUID (the React table key; run_number is null until the run starts). |
runs[]. | string | no | Capability the run executed. |
runs[]. | string | no | What started the run: manual, push, or schedule. |
runs[]. | string | no | Lifecycle state: queued, in_progress, completed, or skipped. |
runs[]. | string | no | GitHub Actions conclusion (e.g. success, failure), or null until finished. |
runs[]. | string | no | Why a skipped run never started (e.g. insufficient_balance), or null. |
runs[]. | string | no | GitHub Actions run number on our runner repo, or null until claimed. |
runs[]. | string | no | URL of the PR the run opened in the customer repo, or null. |
runs[]. | integer | no | Metered compute cost in micro-USD, or null until finalized. |
runs[]. | integer | no | Epoch-ms time the run was created. |
runs[]. | integer | no | Epoch-ms time the run row was last updated. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/github/runs?repo={repo}&capability={capability}&limit={limit}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"repo": "string",
"runs": [
{
"id": "string",
"capability": "string",
"trigger": "string",
"status": "string",
"conclusion": "string",
"skip_reason": "string",
"run_number": "string",
"pr_url": "string",
"compute_billed_micro": 0,
"created_at": 0,
"updated_at": 0
}
]
}https://gateway.aardvarkdocs.com/v1/github/runs/{run_id}Deletes one terminal GitHub automation run from the account’s dashboard history. Queued and in-progress runs must be cancelled first because they still gate dispatch and key cleanup. Owner only.
run_id | path | string | yes | Stable run UUID from GET /v1/github/runs. |
Responses
Body
deleted | boolean | yes | Always true once the history entry is removed. |
run_id | string | yes | Echoes the cleared run UUID. |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/github/runs/{run_id}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"deleted": true,
"run_id": "string"
}https://gateway.aardvarkdocs.com/v1/github/runs/{run_id}/logsReturns the latest GitHub Actions job log text for one Docs Quality Check run. The dashboard polls this endpoint while a row is expanded so queued and in-progress runs can surface logs as soon as GitHub publishes them.
run_id | path | string | yes | Stable run UUID from GET /v1/github/runs. |
Responses
Body
run_id | string | yes | Echoes the requested run UUID. |
status | string | yes | Current dashboard run status. |
available | boolean | yes | false until the runner has claimed the run and GitHub has a job log to download. |
logs | string | yes | Normalized text log payload, or an empty string while unavailable. |
truncated | boolean | yes | true when only the tail of an oversized log is returned. |
job | object | no | GitHub Actions job metadata for the selected runner job, or null while unavailable. |
job. | number | no | |
job. | string | no | |
job. | string | no | |
job. | string | no | |
updated_at | integer | yes | Epoch-ms time this log response was generated (refreshed on every request), not a run-row change stamp. |
message | string | no | Human-readable unavailable-state message. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/github/runs/{run_id}/logs' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"run_id": "string",
"status": "string",
"available": true,
"logs": "string",
"truncated": true,
"job": {
"id": 0,
"name": "string",
"status": "string",
"conclusion": "string"
},
"updated_at": 0,
"message": "string"
}https://gateway.aardvarkdocs.com/v1/github/setupGitHub redirects the browser here after the app is installed or updated. The single-use state (minted at connect) recovers which account initiated, an identity check proves the user administers the installation, then it binds the install, syncs repos, and 302-redirects back to the dashboard. Authed by state, not a session.
state | query | string | no | Single-use install state minted at connect; the credential that recovers and binds the initiating account. |
installation_id | query | integer | no | GitHub's numeric id for the new/updated installation. |
code | query | string | no | OAuth code GitHub appends so the gateway can prove the user administers this installation. |
Try it now unavailable
This endpoint is a browser redirect callback, not a cross-origin API call. Start the GitHub connection flow from the dashboard instead.
Responses
Headers
Location | string | Dashboard URL to follow, carrying ?connected=1 on success or ?error=<code> otherwise. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/github/setup?state={state}&installation_id={installation_id}&code={code}&state=YOUR_API_KEY'Response examples
{
"error": {
"code": "github_misconfigured",
"message": "The gateway origin is misconfigured; contact the operator."
}
}https://gateway.aardvarkdocs.com/v1/github/webhookGitHub-to-server webhook authenticated by the X-Hub-Signature-256 HMAC over the raw body. Handles installation lifecycle, repo-selection changes, pushes (run-on-push automations), workflow runs (a backstop for the runner’s complete callback), and PRs (PR-url capture). Acks 200 once verified; unrecognized event types are acked and ignored.
Request body
Map of string keys to any values.
Try it now unavailable
This endpoint is server-to-server only, so browser calls from this docs page are blocked by CORS. Use a generated request sample from your backend instead.
Responses
Body
received | boolean | no | Always true; acks the verified delivery so GitHub stops retrying. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/github/webhook' \
-H 'X-Hub-Signature-256: YOUR_API_KEY'Response examples
{
"received": true
}Managed docs hosting.
https://gateway.aardvarkdocs.com/v1/reader-auth/loginThe browser leg of reader authentication — not called with an API key. A reader visiting a gated docs site is 302’d here by the serving worker; with a valid dashboard session whose user is an active member of the site’s owning team, the gateway 302s back to the site’s /__reader_auth/callback with a short-lived signed handoff token (the worker then sets the reader-session cookie and resumes at next). Without a session the reader is sent to the dashboard sign-in instead.
site | query | string | yes | The gated site's UUID (supplied by the serving worker's redirect). |
next | query | string | no | Path-only return target on the docs site (defaults to /); absolute URLs are refused. |
host | query | string | no | Which of the site's own hostnames to return to (production, preview, or custom domain — validated against the site; defaults to the production host). |
Try it now unavailable
This operation uses a browser-managed cookie. Try it now cannot set that cookie from this docs page, so use the generated request sample or the dashboard instead.
Responses
Headers
Location | string | Dashboard URL to follow, carrying ?connected=1 on success or ?error=<code> otherwise. |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/reader-auth/login?site={site}&next={next}&host={host}' \
-H 'Cookie: __Host-av_session=YOUR_API_KEY'Response examples
{
"error": {
"code": "bad_request",
"message": "`site` must be a valid site id."
}
}https://gateway.aardvarkdocs.com/v1/sitesThe account’s managed-hosting site (v1: at most one) with its recent deploys and the URLs it serves — the production URL, the branch-preview pattern, and any custom hostname. NOT plan-gated: reads (and the DELETE takedown paths) stay available even after a plan lapse so a downgraded owner can still see and take down their site — the payload’s hosting_plan_allowed flag reports whether NEW deploys/attaches are allowed (only POST create/deploy/attach return 403 plan_required). 503 when hosting isn’t configured on this gateway. Owner/admin only.
Responses
Body
configured | boolean | no | Always true when this endpoint answers (an unconfigured gateway 503s instead). |
base_domain | string | no | The apex hosted sites serve under. In the default (PSL) mode a site’s production lives at https://<slug>.<base_domain>; in custom-domains-only mode (see custom_domains_only) production serves ONLY on an attached custom domain. Branch previews serve under the base in BOTH modes, but the preview hostname includes a short disambiguating hash (<branch-label>-<hash>--<slug>.<base_domain>) — do NOT reconstruct it as <branch>--<slug>.<base_domain> (that 404s); use each deploy’s url, or the site’s preview_url_pattern, for the exact host. |
custom_domains_only | boolean | no | true when the gateway runs in custom-domains-only mode (no PSL entry): production serves ONLY on attached custom domains, never on <slug>.<base> (previews still use the base). A created site is URL-less until BOTH a custom domain is attached AND a production deploy is live (attach writes the route pointer only when a live deploy exists). |
custom_domains_available | boolean | no | true when the operator configured Cloudflare for SaaS (custom-domain endpoints usable). |
hosting_plan_allowed | boolean | no | |
site | object | no | The site object with its recent deploys, or null when no site exists yet. |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | integer | no | |
site. | string | no | |
site. | string | no | The repo-relative build directory for a monorepo, or null (repo root). |
site. | string | no | |
site. | boolean | no | |
site. | string | no | The production URL — https://<slug>.<base> in PSL mode, or the attached custom domain in custom-domains-only mode; null in custom-domains-only mode until BOTH a custom domain is attached AND a production deploy is live. Derived from D1 (attachment + a live production deploy), NOT a per-request routing probe: in the rare case an attach’s route-pointer write failed after persisting the hostname (retryable — the attach returned 500 asking you to retry), this can be non-null before the pointer exists, so the host 404s until the attach is retried or the next production deploy finalizes. |
site. | boolean | no | True when the gateway runs in custom-domains-only mode (no Public Suffix List entry): production serves ONLY on the attached custom domain, so url is null until a domain is attached AND a production deploy is live; previews stay public on the base. |
site. | string | no | |
site. | string | no | |
site. | integer | no | |
site. | array<object> | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | The URL this deploy would serve at, or null. Reachability requires BOTH status: live AND a non-null url: a non-live deploy that still carries a url (a preview host, or a PSL-mode production host) does NOT necessarily serve THIS deploy’s content — that host is served by whichever deploy is currently live there, so after a failed redeploy the PREVIOUS live deploy keeps serving, a superseded row’s host now serves a newer deploy, and it 404s only when no deploy is live there. In custom-domains-only mode a production deploy (branch === production_branch) is url: null UNLESS it is the live deploy AND a custom domain is attached — so every non-live CDO production deploy is url: null even after a domain is attached, and the live one stays null until its domain is attached. Only preview rows and PSL-mode production rows carry a url while non-live. |
site. | integer | no | |
site. | integer | no | |
site. | integer | no | |
site. | integer | no |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/sites' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"configured": true,
"base_domain": "string",
"custom_domains_only": true,
"custom_domains_available": true,
"hosting_plan_allowed": true,
"site": {
"id": "string",
"slug": "string",
"source": "string",
"repo": "string",
"repo_id": 0,
"production_branch": "string",
"project_dir": "string",
"status": "string",
"takedown_pending": true,
"url": "string",
"custom_domains_only": true,
"preview_url_pattern": "string",
"custom_hostname": "string",
"created_at": 0,
"deploys": [
{
"id": "string",
"branch": "string",
"commit_sha": "string",
"status": "string",
"error": "string",
"url": "string",
"file_count": 0,
"bytes_total": 0,
"created_at": 0,
"finished_at": 0
}
]
}
}https://gateway.aardvarkdocs.com/v1/sitesCreates the account’s hosted site: a dns-safe slug served at https://<slug>.<base domain> (in custom-domains-only mode the slug backs preview URLs and production goes live on a custom domain attached afterward — the site is URL-less until then), bound to a repo from the account’s GitHub connection. Every push to the repo then builds and deploys automatically (in PSL mode the production branch goes live at <slug>.<base>; in custom-domains-only mode production goes live on the attached custom domain; other branches get preview hostnames in both modes). One site per account in v1 (409 site_exists); a taken slug returns 409 slug_taken. Plan-gated to Pro and above. Owner/admin only. Provide EXACTLY ONE of repo_id (a repo-built site — everything above) or source:“cli” (a CLI-owned site with NO repo binding, deployed by vark deploy uploading a locally-built output via POST /v1/sites/{site_id}/cli-deploys; slug may be omitted to have one generated, and the create returns 201 with the CLI-facing {site:{site_id, slug, source, repo, urls}} shape).
Request body
source | string | no | Pass the string cli to create a CLI-owned site (no repo binding; deployed via the cli-deploys upload API). Mutually exclusive with repo_id. |
repo_id | integer | no | GitHub’s numeric repo id, from the connected-repo list on GET /v1/github/connection. |
slug | string | no | The subdomain label: 3-40 chars of a-z, 0-9, and single hyphens; reserved names refused. |
production_branch | string | no | The branch that deploys to the production hostname (default: the repo's default branch). |
project_dir | string | no | For a monorepo: the repo-relative directory holding the Aardvark project (e.g. docs); the build runs there. Blank/omitted = repo root. Relative, shell-safe (no leading /, no ..). |
Responses
Body
site | object | no | The created site object (no deploys yet). |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | object | no | |
site. | string | no | |
site. | string | no | |
site. | integer | no | |
site. | string | no | |
site. | string | no | The repo-relative build directory for a monorepo, or null (repo root). |
site. | string | no | |
site. | boolean | no | |
site. | string | no | The production URL — https://<slug>.<base> in PSL mode, or the attached custom domain in custom-domains-only mode; null in custom-domains-only mode until BOTH a custom domain is attached AND a production deploy is live. Derived from D1 (attachment + a live production deploy), NOT a per-request routing probe: in the rare case an attach’s route-pointer write failed after persisting the hostname (retryable — the attach returned 500 asking you to retry), this can be non-null before the pointer exists, so the host 404s until the attach is retried or the next production deploy finalizes. |
site. | boolean | no | True when the gateway runs in custom-domains-only mode (no Public Suffix List entry): production serves ONLY on the attached custom domain, so url is null until a domain is attached AND a production deploy is live; previews stay public on the base. |
site. | string | no | |
site. | string | no | |
site. | integer | no | |
site. | array<object> | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | |
site. | string | no | The URL this deploy would serve at, or null. Reachability requires BOTH status: live AND a non-null url: a non-live deploy that still carries a url (a preview host, or a PSL-mode production host) does NOT necessarily serve THIS deploy’s content — that host is served by whichever deploy is currently live there, so after a failed redeploy the PREVIOUS live deploy keeps serving, a superseded row’s host now serves a newer deploy, and it 404s only when no deploy is live there. In custom-domains-only mode a production deploy (branch === production_branch) is url: null UNLESS it is the live deploy AND a custom domain is attached — so every non-live CDO production deploy is url: null even after a domain is attached, and the live one stays null until its domain is attached. Only preview rows and PSL-mode production rows carry a url while non-live. |
site. | integer | no | |
site. | integer | no | |
site. | integer | no | |
site. | integer | no | |
created | boolean | no | Always true once the site row exists. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sites' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"slug": "acme-docs",
"repo_id": 987654321,
"production_branch": "main"
}'Response examples
{
"site": {
"site_id": "string",
"slug": "string",
"source": "string",
"repo": "string",
"urls": {
"site": "string"
},
"id": "string",
"repo_id": 0,
"production_branch": "string",
"project_dir": "string",
"status": "string",
"takedown_pending": true,
"url": "string",
"custom_domains_only": true,
"preview_url_pattern": "string",
"custom_hostname": "string",
"created_at": 0,
"deploys": [
{
"id": "string",
"branch": "string",
"commit_sha": "string",
"status": "string",
"error": "string",
"url": "string",
"file_count": 0,
"bytes_total": 0,
"created_at": 0,
"finished_at": 0
}
]
},
"created": true
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}Disables the site and stops serving it: the hostname route pointers are removed and any custom hostname is detached best-effort. Deployed content objects are kept in R2 (cheap, and no destructive bulk-delete path). Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites. |
Responses
Body
deleted | boolean | no | true when the site was active and is now disabled. |
site_id | string | no |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"deleted": true,
"site_id": "string"
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploysOpens an upload session for a CLI-owned site (source: cli): vark deploy builds locally, then streams each output file to PUT .../files/{path} and flips the deploy live with POST .../finalize. One deploy in flight per site — a second begin returns 409 deploy_in_progress carrying the blocker’s deploy_id inside the error object (abort it or wait). The declared totals are a courtesy preflight against the fixed caps; the per-file budget reservation on the deploy row stays authoritative. Only sites created with source: cli accept this API (409 site_not_cli otherwise); repo-built sites deploy from pushes / Deploy now instead. Plan-gated to Pro and above. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites (or the CLI create response). |
Request body
file_count | number | yes | How many files the CLI is about to upload (positive; at most 10000). |
total_bytes | number | yes | Total bytes the CLI is about to upload (at most 524288000). |
Responses
Body
error | object | no | |
error. | string | no | |
error. | string | no | |
error. | string | no | |
deploy_id | string | no | The opened deploy's UUID — the id every files/finalize/abort call names. |
limits | object | no | The fixed upload budgets: max_file_bytes (25MB per file), max_files (10000), max_total_bytes (500MB per deploy). |
limits. | string | no | |
limits. | string | no | |
limits. | string | no |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploys' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"file_count": 128,
"total_bytes": 4816321
}'Response examples
{
"error": {
"code": "string",
"message": "string",
"deploy_id": "string"
},
"deploy_id": "string",
"limits": {
"max_file_bytes": "string",
"max_files": "string",
"max_total_bytes": "string"
}
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploys/{deploy_id}Aborts an in-flight CLI deploy: the deploy row is sealed failed (freeing the one-in-flight slot) and the already-uploaded objects are left under the deploy’s immutable prefix for out-of-band cleanup. Idempotent — re-aborting an aborted deploy succeeds; a deploy that already went live returns 409 deploy_not_open. Available even while new work is paused (a lapsed plan, a held account, or a withdrawn hosting affirmation), so an upload can always be stopped. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites (or the CLI create response). |
deploy_id | path | string | yes | The deploy UUID to abort. |
Responses
Body
aborted | boolean | no | Always true once the deploy is sealed failed (idempotent). |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploys/{deploy_id}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"aborted": true
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploys/{deploy_id}/files/{path}Streams ONE built file into the open deploy; the raw request body is stored under the deploy’s immutable prefix with a Content-Type derived from the file extension. {path} is the site-relative file path (URL-encode each segment; no .., no leading /). Idempotent per path with REPLACE semantics: re-PUTting a path overwrites the object and reconciles the byte budget, so a partial-failure retry is a plain re-run. Exceeding the per-file cap returns 413 file_too_large; exceeding the per-deploy file/byte budget returns 409 budget_exceeded. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites (or the CLI create response). |
deploy_id | path | string | yes | The open deploy's UUID from the begin call. |
path | path | string | yes | Site-relative file path inside the built output (e.g. guide/index.html). |
Content-Length | header | integer | yes | Exact raw-body size in bytes; required for the per-file and per-deploy upload budgets. |
Request body
A single string value.
Responses
Body
path | string | no | The stored site-relative path (decoded). |
bytes | string | no | The stored object's size in bytes. |
Request samples
curl -X PUT 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploys/{deploy_id}/files/{path}' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"path": "string",
"bytes": "string"
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploys/{deploy_id}/finalizeFlips the uploaded deploy LIVE through the same publish pipeline as repo-built deploys: the build’s _headers/_redirects are compiled, the hostname route pointer is written, and the deploy row is promoted atomically. file_count must equal the number of files the deploy actually counted (409 count_mismatch — a lost upload must not publish a truncated site). A _headers/_redirects the gateway could not read never blocks the publish, but is surfaced in the response’s warning and on the deploy’s error field until a retry reads it cleanly. Idempotent: finalizing an already-live deploy re-writes the pointer and reports it live again. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites (or the CLI create response). |
deploy_id | path | string | yes | The open deploy's UUID from the begin call. |
Request body
file_count | number | no | The number of files the CLI uploaded; must match the server's count exactly. |
Responses
Body
deploy | object | no | The published deploy: deploy_id, status (live), url (where it serves; null in custom-domains-only mode until a domain is attached), and — only when a hosting-config artifact could not be applied — warning. |
deploy. | string | no | |
deploy. | string | no | |
deploy. | string | no |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/cli-deploys/{deploy_id}/finalize' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"file_count": 128
}'Response examples
{
"deploy": {
"deploy_id": "string",
"status": "string",
"url": "string"
}
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/deployManually enqueues a build-and-deploy run for a branch (default: the production branch). The deploy executes on the central runner and bills compute like any automation run; an unpayable balance returns 402, an in-flight deploy for the same branch returns 409 deploy_in_flight. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites. |
Request body
branch | string | no | Branch to build and deploy (default: the site's production branch). |
Responses
Body
queued | boolean | no | Always true when the deploy was dispatched. |
deploy_id | string | no | The new deploy row's UUID (its status advances as the runner builds). |
run_id | string | no | The backing run's UUID (compute metering + run history). |
branch | string | no | Echoes the branch being deployed. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/deploy' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"branch": "main"
}'Response examples
{
"queued": true,
"deploy_id": "string",
"run_id": "string",
"branch": "string"
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domainPolls the attached custom hostname’s validation + certificate status from Cloudflare for SaaS. 404 no_domain when the site has no custom domain. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites. |
Responses
Body
hostname | string | no | The attached hostname. |
status | string | no | Cloudflare custom-hostname status (e.g. pending, active). |
ssl_status | string | no | Certificate status (e.g. pending_validation, active), or null. |
verification | array<object> | no | DNS records still pending publication, if any (an array; empty once validated). |
verification[]. | string | no | |
verification[]. | string | no | |
verification[]. | string | no | |
dns_target | string | no | Where the customer points their CNAME (the site's production hostname). |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domain' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"hostname": "string",
"status": "string",
"ssl_status": "string",
"verification": [
{
"type": "string",
"name": "string",
"value": "string"
}
],
"dns_target": "string"
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domainAttaches a customer-owned hostname to the site via Cloudflare for SaaS. REQUIRES a confirmed DNS ownership proof for that exact hostname first — call POST /v1/sites/{site_id}/domain/verify, publish the TXT record it returns, and call it again until it reports verified: true; until then this returns 403 domain_verification_required (a proof also expires, after which it must be re-confirmed). Returns the validation records the customer must publish plus the CNAME target; poll GET /v1/sites/{site_id}/domain for status. 503 custom_domains_unavailable unless the operator configured CF_API_TOKEN + CF_ZONE_ID — in PSL / shared-subdomain mode production on <slug>.<base> keeps working regardless, but in custom-domains-only mode an attached custom domain is the ONLY production path, so attach being unavailable means the site has no production URL until CF for SaaS is configured. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites. |
Request body
hostname | string | yes | The customer-owned dns name to serve the site on (outside the hosting base domain). At most 236 characters — shorter than the 253-character DNS maximum, because the ownership challenge is published at _aardvark-verify.<hostname> and that derived name must itself be a legal DNS name. |
Responses
Body
hostname | string | no | The attached hostname (normalized). |
status | string | no | Cloudflare custom-hostname status (e.g. pending, active). |
ssl_status | string | no | Certificate status (e.g. pending_validation, active), or null. |
verification | array<object> | no | DNS records the customer must publish for ownership + certificate validation (an array; empty once validated). |
verification[]. | string | no | |
verification[]. | string | no | |
verification[]. | string | no | |
dns_target | string | no | Where the customer points their CNAME (the site's production hostname). |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domain' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"hostname": "docs.acme.com"
}'Response examples
{
"hostname": "string",
"status": "string",
"ssl_status": "string",
"verification": [
{
"type": "string",
"name": "string",
"value": "string"
}
],
"dns_target": "string"
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domainDetaches the custom hostname: removes its route pointer (serving stops immediately) and clears it from the site. When Cloudflare is still configured it also releases the CF-for-SaaS hostname (a real CF failure returns a retryable 5xx); if the operator removed/rotated CF creds after the domain was attached, detach still succeeds and the CF object is left as a warn-logged orphan for manual reaping rather than stranding the customer. NOT gated on Cloudflare being configured (unlike attach/status). In PSL mode the <slug>.<base> subdomain URL keeps serving; in custom-domains-only mode this was the site’s only production URL, so production goes offline until another custom domain is attached. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites. |
Responses
Body
deleted | boolean | no | Always true once the domain is detached. |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domain' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"deleted": true
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domain/verifyMints (or re-reads) the DNS TXT challenge that POST /v1/sites/{site_id}/domain requires, and confirms it against live DNS in the same call. Call it once to learn the record, publish that record in the hostname’s zone, then call it again — it returns verified: true once the record resolves, and the attach is permitted from that point. A not-yet-published record is NOT an error: the call returns 200 with verified: false so a client can poll while DNS propagates. The token is stable per (account, hostname), so re-calling never invalidates a record you already published. The challenge is bound to the EXACT hostname being attached (_aardvark-verify.docs.acme.com for docs.acme.com), never to a parent domain. Proofs expire and must be re-confirmed. Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites. |
Request body
hostname | string | yes | The customer-owned dns name you intend to attach (outside the hosting base domain). At most 236 characters — shorter than the 253-character DNS maximum, because the challenge is published at _aardvark-verify.<hostname> and that derived name must itself be a legal DNS name. |
Responses
Body
hostname | string | no | The hostname the challenge is bound to (normalized). |
verified | boolean | no | Whether the TXT record currently resolves with the expected token AND the proof is unexpired. Only a true here permits the attach. |
record_name | string | no | The DNS record name to create, e.g. _aardvark-verify.docs.acme.com. |
record_type | string | no | The DNS record type to create (TXT). |
record_value | string | no | The exact TXT value to publish (carries the verification token). |
detail | string | no | Present only when verified is false: what to do next. |
Request samples
curl -X POST 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/domain/verify' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"hostname": "docs.acme.com"
}'Response examples
{
"hostname": "string",
"verified": true,
"record_name": "string",
"record_type": "string",
"record_value": "string",
"detail": "string"
}https://gateway.aardvarkdocs.com/v1/sites/{site_id}/reader-authTurns reader authentication on or off for the hosted site (v1 team mode: only dashboard-team members of the owning account may view it). Enabling mints the site’s signing secret on first use (encrypted at rest; the gateway returns 503 encryption_unavailable rather than store it unprotected) and rewrites the LIVE deploy’s route pointers in place, so the gate takes effect without a redeploy; disabling rewrites them back to public serving. The flip is not instantaneous: the serving workers cache a resolved route pointer at the edge, and that cache cannot be purged remotely, so an edge that already resolved the pre-change pointer keeps serving the old state until its copy expires. The response returns propagation_seconds — the site is private for new edge lookups as soon as this returns, and everywhere within that many seconds. Treat a site as fully private only after the window elapses. Enable is plan-gated to Business/Enterprise; disable is deliberately not (a lapsed plan can always make its own site public again). Note the v1 revocation window: reader sessions are 12-hour cookies verified offline by the serving worker, so removing a teammate does not cut a session they already hold — in v1 revocation waits for that cookie to expire. Toggling the site off and back on does NOT revoke: a re-enable reuses the site’s existing signing secret and key id, so cookies issued before it become valid again as soon as the gate is back on. (Reader auth also applies to preview and custom-domain hostnames, and a gated site’s hosted /mcp endpoint returns 404 while the gate is on.) Owner/admin only.
site_id | path | string | yes | The site UUID from GET /v1/sites. |
Request body
enabled | boolean | yes | true to require reader sign-in on every request to the site; false to serve publicly again. |
Responses
Body
enabled | boolean | no | The new state. |
mode | string | no | Always team in v1: dashboard-team members of the owning account may view. |
propagation_seconds | string | no | Upper bound, in seconds, on how long an edge that already resolved the previous route pointer may keep serving the previous state (public before an enable, gated before a disable). 0 when nothing was serving the old state. |
Request samples
curl -X PUT 'https://gateway.aardvarkdocs.com/v1/sites/{site_id}/reader-auth' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"enabled": true
}'Response examples
{
"enabled": true,
"mode": "string",
"propagation_seconds": "string"
}Health check.
https://gateway.aardvarkdocs.com/Unauthenticated root health check; returns a fixed text/plain body.
Responses
Body
A single string value.
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/'Response examples
"string"Other
https://gateway.aardvarkdocs.com/v1/account/byokOwner only.
Responses
Body
provider | string | no | |
last4 | string | no | |
updated_at | number | no |
Request samples
curl -X GET 'https://gateway.aardvarkdocs.com/v1/account/byok' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"provider": "string",
"last4": "string",
"updated_at": 0
}https://gateway.aardvarkdocs.com/v1/account/byokOwner only.
Request body
provider | string | no | |
key | string | yes |
Responses
Body
provider | string | no | |
last4 | string | no | |
updated_at | number | no |
Request samples
curl -X PUT 'https://gateway.aardvarkdocs.com/v1/account/byok' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"provider": "string",
"last4": "string",
"updated_at": 0
}https://gateway.aardvarkdocs.com/v1/account/byokOwner only.
Responses
Body
deleted | boolean | no |
Request samples
curl -X DELETE 'https://gateway.aardvarkdocs.com/v1/account/byok' \
-H 'Authorization: Bearer YOUR_API_KEY'Response examples
{
"deleted": true
}