# Convertlyft read API — https://convertlyft.com # version 2026-11-15.2548, sent as Convertlyft-API-Version on every /api response — including the # 401 you get before you have a credential — and on these three documents. # Every report is read-only. A personal access token can be given write scopes; the writes are # listed in the manifest (POST /api/memory memory:write, POST /api/crawl crawl:run — each crawled # page counts toward the plan —, POST /api/tools/ seo:write, and on the MCP door cvl_change_apply / _undo # changes:write; cvl_change_preview needs only changes:read). A connected app (sign-in from an AI # app) gets reads, plus crawl:run, seo:write, pages:write, board:write and memory:write only if the # person ticks them — never changes:write. AUTH Authorization: Bearer cvl_pat_<12 hex>_<64 hex> Header only. A cvl_pat_ token in a query string is refused with code token_in_query. Headless: POST /api/tokens/device/code -> show user_code to a human -> poll POST /api/tokens/device/token (RFC 8628). no demo credential is published in this document; there is no anonymous read, and you need a human once, to mint one FIRST CALL — proves auth and scopes in one request. NO from: all time, on purpose curl -s "https://convertlyft.com/api/reports/kpi" -H "Authorization: Bearer $TOKEN" | jq .kpis.sessions.value A liveness probe wants "did this credential reach a workspace with data", not a trend — so it omits from deliberately, which is the sanctioned exception the next section names. Any other call should send one. WHAT WILL MAKE YOUR CALL FAIL from/to are ISO 8601 with a zone, or a date alone: "2026-08-01" means that whole UTC day. "2026-08-01T00:00:00" with no zone is a 400. Omitting from means ALL TIME — not today. A scheduled check that omits it reports lifetime numbers and stays green. Two quota buckets: 120/minute and 20,000/day per credential. A 429 body names which: {"error":..,"bucket":"minute"|"day","limit":N}. Do NOT sleep on the day bucket — Retry-After can be most of a day. Back off on minute; stop and reschedule on day. Every refusal carries a machine code (token_expired, missing_scope, workspace_mismatch, ...). Branch on code, never on prose. WHAT AN ABSENT NUMBER MEANS A figure carries a state. state != "ok" means the number does not exist for this workspace — it does not mean zero. conversion.state "unmapped" = nothing is mapped to a Purchase stage. revenue.state "no_amount" = purchases carried no currency amount. Never render a non-ok figure as 0. Check state before you read the value. window.data_complete_through is the boundary we can honestly claim complete data through; window.handle pins that exact window — present it as ?window_handle= on later calls to the 8 /api/reports/* endpoints. WORTH POLLING /api/reports/kpi The headline numbers — sessions, conversion, revenue, LCP. /api/issues The issue queue. /api/changes Changes shipped on the site, with their markers. MORE https://convertlyft.com/llms-full.txt worked request/response per endpoint https://convertlyft.com/.well-known/convertlyft-capabilities.json endpoints, scopes, MCP revision, changelog