Authentication
Every request carries your token as a Bearer header:
Authorization: Bearer glt_YOUR_TOKEN
Tokens are created in Settings → AI Agents & API. Copy the glt_… value once — only its hash is stored, so it can’t be shown again. Revoking a token cuts off access instantly, and each token tracks when it was last used.
Scopes
| Scope | Reads | Writes |
|---|---|---|
| Project token | the granted project set | the granted project set |
| Account token | any project you’re a member of (or own) — pass projectId explicitly | any project where you are an editor |
An Account token acts as you: it can never do more than your own role allows. If you’re a view-only guest on a project, a ReadWrite token still can’t write there — writes are attributed to your membership, and API-created tasks are assigned to the token’s own integration identity on the project roster.
Permissions
Each token is ReadOnly or ReadWrite. ReadOnly tokens can call every GET; any write returns 403 forbidden — uniformly, whether the target exists or not.
How denials behave (by design)
- Wrong or revoked token →
401with aBearerchallenge. An expired token, a revoked token, and a token whose account was deactivated are indistinguishable. - A resource you can’t reach, addressed by its own id (
GET/PATCH/DELETEon/tasks/{id},/resources/{id},/projects/{id}and their sub-paths) →404, never403. A foreign id looks exactly like a nonexistent one — the API never confirms existence of things you can’t access. Archived (soft-deleted) projects behave as nonexistent too, including their tasks, members, and resources. - A project you name in the URL to write into (
POST /projects/{id}/tasks,.../tasks/reorder,.../resources) that you cannot write to →403 forbidden. Because you supplied the project id, a403here reveals nothing you didn’t already assert; a foreign and a nonexistent project both answer the same403(no existence oracle). - A project you CAN reach but that is read-only (subscription lapsed, admin lock, pending deletion) →
403with codeproject_read_onlyand the reason in the message. - A ReadOnly token attempting any write →
403 forbidden.
User-Agent
Every request must include a non-empty User-Agent header identifying your client. A request without one is rejected before your token is even checked, with 403 and:
{ "code": "user_agent_required" }
Note that curl, browsers, and standard HTTP libraries (in most languages) send a
User-Agentautomatically — you’ll only hit this if you’re building a raw request by hand. In that case, set one explicitly:
User-Agent: my-app/1.0
HTTPS only
Plain-HTTP requests never reach the API. Keep tokens out of URLs and logs; send them only in the Authorization header.