# Personal API tokens

Source: https://iskue.com/docs/api-tokens/

> Create, use and revoke personal access tokens (isk_…) for scripts, CI and AI assistants: the same Authorization header as a session JWT, with per-token expiry and revocation.

A **personal access token** lets a script, a CI job or an AI assistant call the API as you, without an interactive login and without embedding your password anywhere. It carries exactly your permissions — global role, project memberships, restricted-ticket visibility — and is re-checked against your live account on every request, so deactivating the account or revoking the token cuts access immediately. Treat a token like a password.

## Create a token

Open **Account → API tokens** (`/account`), give the token a name that says what it is for ("Release bot", "Claude Desktop"), pick an expiry — never, 30 days, 90 days or a year — and press **Create token**. The raw value is shown **once**, with a copy button; after you dismiss the panel only its first 12 characters (`isk_` plus eight more) remain visible as an identifier. The same flow exists over the API:

*Omit expiresInDays for a token that never expires; zero or negative values are rejected*

```bash
curl -s -X POST http://localhost:8088/api/v1/account/tokens \
  -H "Authorization: Bearer $JWT" -H 'Content-Type: application/json' \
  -d '{"name":"Release bot","expiresInDays":90}'
# → {"token":{"id":"…","name":"Release bot","prefix":"isk_3kQ9xYz1","createdAt":"…","expiresAt":"…","lastUsedAt":null,"revokedAt":null},
#    "rawToken":"isk_3kQ9xYz1…"}   ← shown once; store it in your secret manager now
```

| Endpoint | Purpose |
| --- | --- |
| `GET /api/v1/account/tokens` | Your tokens, newest first — name, visible prefix, created/expires/last-used/revoked timestamps. Never the secret. Revoked tokens stay listed. |
| `POST /api/v1/account/tokens` | Create (201): `name` (required, ≤ 100 characters), optional `expiresInDays` and optional `scope` (`READ`, `WRITE` — the default — or `FULL`). Returns the token row plus `rawToken`. |
| `DELETE /api/v1/account/tokens/{id}` | Revoke (204). Only your own tokens; revoking twice is harmless. |

## Use it

Send the token on the very same header a session JWT uses. The backend tells the two apart by prefix — every personal token starts with `isk_` — so nothing else changes: the same endpoints, the same permission checks, the same `401`/`403` semantics.

*A token works everywhere a JWT works — including /api/v1/account/tokens itself*

```bash
export ISKUE_TOKEN='isk_…'

# Search tickets with TQL
curl -s "http://localhost:8088/api/v1/search/tql?query=assignee%20%3D%20me%20AND%20status%20!%3D%20Done" \
  -H "Authorization: Bearer $ISKUE_TOKEN"

# Add a comment from a CI job
curl -s -X POST http://localhost:8088/api/v1/tickets/CORE-42/comments \
  -H "Authorization: Bearer $ISKUE_TOKEN" -H 'Content-Type: application/json' \
  -d '{"body":"Build 1234 passed on main"}'
```

- **Format** — `isk_` followed by 43 URL-safe base64 characters (32 random bytes): 47 characters in total. Only a SHA-256 hash is stored; the raw value cannot be recovered, so a lost token is replaced, not retrieved.
- **Lifetime** — a token works until it expires (`expiresAt`) or is revoked; each successful use stamps `lastUsedAt`, which the Account page shows so stale tokens are easy to spot.
- **Access level** — pick **Read only**, **Read & write** (the default) or **Full access** (administration, the Jira importer, tokens, 2FA, connected accounts) when you create a token; a request beyond the token's level gets a `403` that says so. Within that level a token is you — never more than your own permissions.
- **Who may create them** — any active user, in every edition. No limit on the number of tokens per account.
- **Where they are not useful** — on the paths that are open without a login anyway (customer portal, inbound webhooks), and on the SSE stream and attachment thumbnails, where the browser cannot set headers and the app uses a short-lived `access_token` query parameter instead.

## Revoke and rotate

Press **Revoke** next to a token (the UI confirms: *Anything using it will stop working immediately*) or call `DELETE /api/v1/account/tokens/{id}`. Revocation is a soft delete — the row stays in the list marked **Revoked** so you keep a record of what existed. To rotate, create the replacement first, update the consumer, then revoke the old one.

> **Warning:** Rate limits apply per authenticated **user**, not per token (`app.ratelimit.api-per-min`, default 240 requests per minute per backend node). A chatty automation sharing your account competes with your own browser session; give heavy integrations their own account.

> **Note:** Token creation and revocation are self-service and are **not** written to the audit log in this release; administrators cannot list other users' tokens. Deactivating a user (Administration → Users) is the administrative kill switch: it invalidates every token the user holds on the next request.
