Outline Setup & Authentication
Establish access to an Outline workspace and learn the conventions every other call depends on. Do this once per session before any other Outline operation. Authentication is a single static key — there is no login/token-exchange step.
Environment variables
The user sets these in their shell or repo .env. Read them — never hardcode or print the key.
| Variable |
Required |
Meaning |
OUTLINE_API_URL |
yes |
API base including /api. Cloud: https://app.getoutline.com/api. Self-hosted: https://wiki.mycompany.com/api. |
OUTLINE_API_KEY |
yes |
Personal API key. Always begins with ol_api_ followed by a random string. Sent as Authorization: Bearer ${OUTLINE_API_KEY}. |
If OUTLINE_API_URL is missing, ask the user for it. Normalize the trailing slash with ${OUTLINE_API_URL%/} and build every endpoint as ${OUTLINE_API_URL%/}/<method>. The URL already ends in /api — do not append /api yourself, and do not pass a URL that ends in a method name.
A user mints a key under Settings → API Keys → New API Key. Keys grant full access to the user's data (or are scoped — see Scopes below), so treat them like passwords and never commit them.
Step 1 — Verify access
curl -s -X POST "${OUTLINE_API_URL%/}/auth.info" \
-H "Authorization: Bearer ${OUTLINE_API_KEY}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" | jq '.data | {user: .user.name, email: .user.email, team: .team.name}'
A 200 with ok: true and your user + workspace (team) confirms the key works. A 401 means the key is missing, wrong, or revoked — fix the key before continuing.
Global conventions (apply to every call)
These rules hold across the entire API. Internalize them now so individual operations stay short.
- RPC, not REST-by-noun. Every endpoint is a
POST to ${OUTLINE_API_URL%/}/<method> where the method is dotted, e.g. documents.info, collections.list. There are no path parameters and no GET requests — all inputs go in the JSON body. An empty body is -d '{}'.
- Headers. Always send
Authorization: Bearer ${OUTLINE_API_KEY}, Content-Type: application/json, and Accept: application/json. (Attachment uploads to cloud storage are the one exception — see api-reference → attachments-fileops.md.)
- Response envelope. Successful responses are
{ "ok": true, "status": 200, "data": …, "pagination"?: {…}, "policies"?: [...] }. The payload you want is under .data — always jq '.data'. List endpoints put the array in .data; a few wrap it (e.g. .data.users + .data.memberships) — check the reference file.
- Errors. Failures return
{ "ok": false, "error": "…", "message": "…", "status": <code> } with the matching HTTP status. 400 validation, 401 unauthenticated, 403 unauthorized (policy), 404 not found, 429 rate limited.
- Pagination. List methods take
{"limit": 25, "offset": 0} in the body (default limit 25). The response pagination echoes them and adds nextPath (e.g. /api/documents.list?limit=25&offset=25) as a shortcut to the next page. Walk results by incrementing offset until a short/empty page returns.
- Sorting. List methods accept
{"sort": "updatedAt", "direction": "DESC"} (direction is ASC or DESC). Document search uses sort values relevance|createdAt|updatedAt|title.
- IDs. Objects are addressed by UUID. Documents, collections, and templates also accept a short
urlId (e.g. hDYep1TPAM), and documents.info additionally accepts a shareId. Humans speak in titles — resolve a title to an id first with documents.search / documents.search_titles / collections.list before acting.
- Rate limits. Mutating endpoints are stricter than reads. Exceeding a limit returns
429 with a Retry-After header (seconds to wait). Inspect with curl -s -D - … and back off.
- Policies. Most responses include a
policies array describing the current key's authorized actions on each object. For most uses you can ignore it; when a write returns 403, the policy is telling you the key lacks that permission — respect it.
Scopes (optional, for scoped keys)
API keys can be global (read, write) or narrowed — by namespace (documents:read, collections:write), by endpoint (documents.info), or by wildcard (documents.*). If a previously-working call starts returning 403, the key may be scoped too narrowly for that method.
Next steps
- For everyday workflows (create a doc, search, share, manage people, report) → use the
common-operations skill.
- For the full endpoint catalog of every resource → load the
api-reference skill and open the relevant references/*.md file (or the bundled references/outline-openapi.yml spec).
- When a call fails → use the
troubleshoot skill.
1---2name: setup-123description: This skill should be used when the user wants to "connect to Outline", "authenticate with Outline", "set up Outline access", "use my Outline API key", or before running any Outline REST API call. Establishes the API key + base URL from the environment and the global request conventions (RPC POST style, Bearer header, response envelope, limit/offset pagination, sorting, rate limits, policies).4---56# Outline Setup & Authentication78Establish access to an Outline workspace and learn the conventions every other call depends on. Do this once per session before any other Outline operation. Authentication is a single static key — there is no login/token-exchange step.910## Environment variables1112The user sets these in their shell or repo `.env`. Read them — never hardcode or print the key.1314| Variable | Required | Meaning |15|----------|----------|---------|16| `OUTLINE_API_URL` | yes | API base **including `/api`**. Cloud: `https://app.getoutline.com/api`. Self-hosted: `https://wiki.mycompany.com/api`. |17| `OUTLINE_API_KEY` | yes | Personal API key. Always begins with `ol_api_` followed by a random string. Sent as `Authorization: Bearer ${OUTLINE_API_KEY}`. |1819If `OUTLINE_API_URL` is missing, ask the user for it. Normalize the trailing slash with `${OUTLINE_API_URL%/}` and build every endpoint as `${OUTLINE_API_URL%/}/<method>`. The URL already ends in `/api` — do **not** append `/api` yourself, and do not pass a URL that ends in a method name.2021A user mints a key under **Settings → API Keys → New API Key**. Keys grant full access to the user's data (or are scoped — see Scopes below), so treat them like passwords and never commit them.2223## Step 1 — Verify access2425```bash26curl -s -X POST "${OUTLINE_API_URL%/}/auth.info" \27 -H "Authorization: Bearer ${OUTLINE_API_KEY}" \28 -H "Content-Type: application/json" \29 -H "Accept: application/json" | jq '.data | {user: .user.name, email: .user.email, team: .team.name}'30```3132A `200` with `ok: true` and your user + workspace (`team`) confirms the key works. A `401` means the key is missing, wrong, or revoked — fix the key before continuing.3334## Global conventions (apply to every call)3536These rules hold across the entire API. Internalize them now so individual operations stay short.3738- **RPC, not REST-by-noun.** Every endpoint is a **`POST`** to `${OUTLINE_API_URL%/}/<method>` where the method is dotted, e.g. `documents.info`, `collections.list`. There are **no path parameters and no GET requests** — all inputs go in the JSON body. An empty body is `-d '{}'`.39- **Headers.** Always send `Authorization: Bearer ${OUTLINE_API_KEY}`, `Content-Type: application/json`, and `Accept: application/json`. (Attachment uploads to cloud storage are the one exception — see `api-reference` → `attachments-fileops.md`.)40- **Response envelope.** Successful responses are `{ "ok": true, "status": 200, "data": …, "pagination"?: {…}, "policies"?: [...] }`. **The payload you want is under `.data`** — always `jq '.data'`. List endpoints put the array in `.data`; a few wrap it (e.g. `.data.users` + `.data.memberships`) — check the reference file.41- **Errors.** Failures return `{ "ok": false, "error": "…", "message": "…", "status": <code> }` with the matching HTTP status. `400` validation, `401` unauthenticated, `403` unauthorized (policy), `404` not found, `429` rate limited.42- **Pagination.** List methods take `{"limit": 25, "offset": 0}` in the body (**default limit 25**). The response `pagination` echoes them and adds `nextPath` (e.g. `/api/documents.list?limit=25&offset=25`) as a shortcut to the next page. Walk results by incrementing `offset` until a short/empty page returns.43- **Sorting.** List methods accept `{"sort": "updatedAt", "direction": "DESC"}` (`direction` is `ASC` or `DESC`). Document search uses `sort` values `relevance|createdAt|updatedAt|title`.44- **IDs.** Objects are addressed by UUID. Documents, collections, and templates also accept a short `urlId` (e.g. `hDYep1TPAM`), and `documents.info` additionally accepts a `shareId`. Humans speak in titles — resolve a title to an id first with `documents.search` / `documents.search_titles` / `collections.list` before acting.45- **Rate limits.** Mutating endpoints are stricter than reads. Exceeding a limit returns `429` with a `Retry-After` header (seconds to wait). Inspect with `curl -s -D - …` and back off.46- **Policies.** Most responses include a `policies` array describing the current key's authorized actions on each object. For most uses you can ignore it; when a write returns `403`, the policy is telling you the key lacks that permission — respect it.4748## Scopes (optional, for scoped keys)4950API keys can be global (`read`, `write`) or narrowed — by namespace (`documents:read`, `collections:write`), by endpoint (`documents.info`), or by wildcard (`documents.*`). If a previously-working call starts returning `403`, the key may be scoped too narrowly for that method.5152## Next steps5354- For everyday workflows (create a doc, search, share, manage people, report) → use the `common-operations` skill.55- For the full endpoint catalog of every resource → load the `api-reference` skill and open the relevant `references/*.md` file (or the bundled `references/outline-openapi.yml` spec).56- When a call fails → use the `troubleshoot` skill.