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

ScopeReadsWrites
Project tokenthe granted project setthe granted project set
Account tokenany project you’re a member of (or own) — pass projectId explicitlyany 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 token401 with a Bearer challenge. 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/DELETE on /tasks/{id}, /resources/{id}, /projects/{id} and their sub-paths) → 404, never 403. 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, a 403 here reveals nothing you didn’t already assert; a foreign and a nonexistent project both answer the same 403 (no existence oracle).
  • A project you CAN reach but that is read-only (subscription lapsed, admin lock, pending deletion) → 403 with code project_read_only and the reason in the message.
  • A ReadOnly token attempting any write403 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-Agent automatically — 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.