The v1 API
Ten endpoints: what each takes, what it returns, and what it refuses.
Everything lives under https://noots.ai/api/v1. JSON in, JSON out.
Shared rules
- Authentication
Authorization: Bearer noots_…on every request. Missing or unrecognised gives 401{"error":"Invalid or missing API token"}.- Rate limit
- 600 requests per minute per IP, shared across all API routes. Over it you get 429 with a
retry-after: 60header. Preflight requests count. - CORS
- Any origin, for
GET,POST,PATCH,DELETEandOPTIONS, withAuthorizationandContent-Typeallowed. A preflight answers 204. - Cookies
- Never accepted. Credentials are not allowed on cross-origin requests — the token in the header is the only way in, which is exactly why any origin is safe.
The endpoints
| Method & path | Body / query | Returns |
|---|---|---|
GET /me | — | { user: { id, email, name }, org: { id, name } }. org is null if the token has none. |
GET /me/tasks | ?status= optional | { tasks: [...] } — the tasks assigned to the token's owner, with key, title, status, priority, due date, project, estimate and logged time. |
GET /noots | — | { noots: [{ id, name, icon, created_at }] }, newest first. |
POST /noots | { name } — trimmed, first 60 characters | 201 { id, name }. |
GET /progress | ?nootId= optional | { noots: [{ id, name, total, done, in_progress, in_review, todo, percent }] }. |
GET /notifications | — | { items: [{ text, kind, when }], count }. kind is prompt or activity; count is the pending prompts only. |
POST /context/search | { query } — first 120 characters | { hits: [{ type, id, title, subtitle }] }, where type is noot, task or meeting. |
POST /context/factcheck | { claim } | { verdict, explanation, sources }. verdict is supported, contradicted or unverifiable. |
POST /meetings/capture | { url, nootId? } | 201 { ok, meetingId, botId, notice } when a bot was dispatched; 200 with a notice when one was already on that meeting. |
POST /meetings/ingest | { transcript, title?, nootId?, durationMin? } | 201 { ok, meetingId, summary, decisions, actionItems, summarized }. |
/noots, /progress, /context/search and /context/factcheck return only the projects that person can actually open. If your integration used to see private projects its owner wasn't on, it no longer does — that was a leak, and closing it is a change you may notice. A nootId you send that doesn't belong to the token's organization is ignored rather than honoured.
Errors
| Status | When |
|---|---|
| 400 | A required field is missing (name, claim, transcript, url), the URL isn't a meeting link, or the token has no organization on a route that needs one. |
| 401 | No Authorization header, a malformed one, or a token that has been revoked or whose owner is no longer an active member. |
| 404 | GET /me only, when the account behind the token no longer exists. |
| 429 | Over 600 requests in the last minute from your IP. |
| 502 | POST /meetings/capture only, when the recording provider refused. |
/me/tasks, /noots, /progress, /notifications and /context/search all return 200 with an empty list rather than failing. The routes that have to write something — creating a project, capturing or ingesting a meeting, fact-checking — return 400 instead, because there is nowhere to put the result.
With no AI configured, or when the model call fails, /context/factcheck answers 200 with unverifiable and whatever sources it found. It never returns a 5xx, so your caller doesn't have to distinguish "couldn't tell" from "broke" — the verdict already says which.
POST /meetings/ingest is the route to reach for if you already have a transcript. It runs the whole normal pipeline — summary, decisions, action items, and tasks onto the project you name.
