Getting Started
The Madless API is programmatic access to your space — the concepts you kept, the connections between them, the files behind them, and Ask. Let material in through the one door, POST /api/v1/keep. Read and write the graph. Subscribe to changes over webhooks.
Get an API key
A space admin mints a key in Settings → Developer. Every key — live, or a test key against the sandbox — needs the Pro plan, which carries the api-keys entitlement. Whoever mints it holds admin.write — a fact about the minter, never a scope the key needs: the key carries only the scopes you pick for it. See Authentication for the full requirements.
Base URL
Endpoints live under your space host — replace {space} with your space slug. The apex madless.com and api.madless.com work too — the same API and the same spec: an API key resolves its own space, so the slug is optional. What a key cannot do is call another space’s host — that answers 421 misdirected_request, and the body’s base_url names where the key belongs.
https://{space}.madless.com/api/v1/
Quick Start
Create an API key
In Settings → Developer → API Keys, generate a key with the scopes your integration needs. The first request below asks a question, which takes ask.run and concepts.read.
Get your credentials
Copy the key — it starts with mad_sk_. Nothing else is needed: the key carries its own space.
Make your first request
Ask your mind one question. It answers only from what you kept, checks every claim against the passage it cites before showing you anything, and refuses to guess. Swap in your own space slug and key.
curl -N 'https://acme.madless.com/api/v1/ask' \ -H 'Authorization: Bearer mad_sk_abc123...' \ -H 'Content-Type: application/json' \ -d '{ "query": "What did I keep about fermentation?" }'
The answer streams as text/event-stream: progress first, then one answer frame — its data is the checked answer, shortened here — then done. [1] in the text is the citation whose n is 1, and its excerpt is the exact line the claim was checked against.
{ "id": "ask_7h2k9mRt7Wq2Zx9Kp4Vn", "text": "You kept that a warmer kitchen speeds the starter [1], and that rye wakes it faster than wheat [2].", "abstained": false, "citations": [ { "n": 1, "id": "con_abc123Td92kLm0PqRt7W", "title": "The Art of Fermentation", "url": "/?concept=con_abc123Td92kLm0PqRt7W", "evidence_class": "user_note", "excerpt": "Keep the starter somewhere warm — it doubles in half the time." }, { "n": 2, "id": "con_4d6e8f0aAHTd92kLm0Rt", "title": "Rye starter notes", "url": "/?concept=con_4d6e8f0aAHTd92kLm0Rt", "evidence_class": "user_note", "excerpt": "Rye flour wakes a sleepy starter faster than wheat." } ], "verification": { "claims_examined": 2, "outcomes": { "supported": 2, "supported_after_repoint": 0, "removed": 0, "inconclusive": 0 } }, "checked": true }
When nothing you kept answers the question, abstained is true, citations is empty, and text says so in a sentence. Cited, or silent.
List what you kept
The answer stands on these. Read them back, newest first.
curl 'https://acme.madless.com/api/v1/concepts' \ -H 'Authorization: Bearer mad_sk_abc123...'
Response Format
Every response with a body wraps the result in a data envelope; a single-resource delete returns 204 with none. Every list carries next_cursor — a string, or null on the last page — and the same pointer rides a Link header with rel="next". The cursor is opaque: pass it back unchanged.
{ "data": [ { "id": "con_abc123Td92kLm0PqRt7W", "title": "The Art of Fermentation", "labels": [{ "id": "lbl_7Hk2mQ9pRt4vXw1yZa3b", "name": "Cooking", "color": "#4A9EFF" }], "embedding_status": "ready", "created_at": "2026-03-15T10:00:00.000Z" } ], "next_cursor": "WzE3ODA0NDA0OTcxNTYsImNvbl9qeSJd.dHM4WlNyOFhxV0J4QUhUZDkya0xtMHBRclN0Vg" }