---
title: "API Tokens"
description: "Personal and organization API tokens in Shiplight Cloud — scopes, creation, revocation, and using a token for the Cloud API and the Shiplight LLM proxy."
---

# API Tokens

<div class="view-markdown-wrapper">
<ViewMarkdown />
</div>

API tokens authenticate everything outside the browser: uploading test results, reading them back from the `/shiplight cloud` skill, and calling LLMs through the Shiplight [LLM proxy](#llm-proxy). Manage them at [app.shiplight.ai/api-tokens](https://app.shiplight.ai/api-tokens).

A token carries **scopes**, so one token can be limited to exactly the job it does.

## Two kinds of token

|                              | Personal                     | Organization                                           |
| ---------------------------- | ---------------------------- | ------------------------------------------------------ |
| Prefix                       | `shp_pat_`                   | `shp_org_`                                             |
| Acts as                      | You, within one organization | The organization, with no user attached                |
| Who can create               | Any member                   | **Owners only**                                        |
| Visible to                   | Only you                     | All members; only owners can create, revoke, or reveal |
| Survives you leaving the org | No                           | Yes                                                    |
| Limit                        | 20 active per organization   | 20 active (configurable per org)                       |

Use a **personal** token for local development and anything that should stop working when you leave. Use an **organization** token for CI and shared automation, so it does not break when someone changes teams.

## Scopes

Scopes are a **ceiling, not a grant**. What a token can actually do is your live organization role _intersected with_ its scopes — so a member's token can never do owner-only things just by checking more boxes, and a token loses access immediately if your role changes or you're removed.

| Scope                                                          | Grants                                                             |
| -------------------------------------------------------------- | ------------------------------------------------------------------ |
| `llm:invoke`                                                   | Calling the [LLM proxy](#llm-proxy)                                |
| `analytics:read`                                               | The whole `/v1/analytics/*` API                                    |
| `action-cache:read` / `action-cache:write`                     | Reading and updating the self-healing locator cache                |
| `recordings:write`                                             | Uploading recorder sessions (personal tokens only)                 |
| `proxy:egress`                                                 | Authenticating the browser egress proxy (organization tokens only) |
| `secrets:*`, `organizations:*`, `instances:*`, `accounts:read` | Platform management APIs (personal tokens only)                    |

::: warning An empty scope list means full access
If you tick **every** box in the create form, the token is stored with no scope restriction at all — which is _broader_ than the boxes you ticked, because it also grants scopes the form doesn't show. The token list displays this as **Full access**. To get a genuinely limited token, leave at least one box unticked.
:::

::: warning Some scopes can't be selected in the UI
The create form doesn't render `analytics:read` or `recordings:write` for personal tokens. Unticking any box therefore silently drops them. If you need one of those as part of a _restricted_ personal token, create the token through the API rather than the UI, or use a full-access token.

`proxy:egress` is also special: it is off by default, and a full-access token cannot perform egress — the scope must be granted explicitly.
:::

## Managing tokens

Create tokens on the **Personal** or **Organization** tab at [app.shiplight.ai/api-tokens](https://app.shiplight.ai/api-tokens), giving a name, an expiration (90 days by default), and the scopes above. Unlike most platforms, Shiplight can show you a token again later — **Reveal & copy** works for as long as the token is active, and only owners can reveal organization tokens. There is no rotate action: to rotate, create a replacement, deploy it, then revoke the old one. Revocation takes effect everywhere within about a minute.

For local development, the CLI can create or restore a personal token for you:

```bash
npx shiplight setup-api-token
```

The command opens Shiplight in your browser, asks you to choose an organization, and writes the resulting `SHIPLIGHT_API_TOKEN` to the current project's `.env` file. The browser device-auth session is used only during setup and is not persisted. The personal API token remains valid until it expires or is revoked.

To stop using the token in one project, remove `SHIPLIGHT_API_TOKEN` from that project's `.env` file. To invalidate it everywhere, revoke it on the [API Tokens page](https://app.shiplight.ai/api-tokens). The CLI has no logout command because there is no persistent CLI login session.

This configures access to the Shiplight platform; it does **not** configure login for the application you are testing. For that, use the `/shiplight setup-test-auth` skill command.

Do not use the CLI-created personal token as a shared CI credential. Create an organization token in the web app for CI and other shared automation.

## Reading results with a token

The result endpoints — test runs, test results, failing and flaky tests, and artifact downloads — require only a valid, active token. **No particular scope is needed**, so even a tightly scoped token can read results. This is what the `/shiplight cloud` skill uses:

```bash
export SHIPLIGHT_API_TOKEN=shp_pat_…
```

The analytics endpoints are the exception: `/v1/analytics/*` requires `analytics:read`, or a full-access token.

The organization is always taken from the token itself, never from the request, so a token can only ever see its own org's data.

## LLM proxy

The Shiplight LLM proxy is a metered pass-through in front of Anthropic, OpenAI, and Google Gemini. You send provider-native requests and get provider-native responses — it is not a separate API, so existing SDKs work unchanged. It lets you run AI-powered test steps without holding your own provider keys, and bills the usage to your organization alongside compute and storage.

Prompts and responses are **never stored**. Only token counts, model, provider, and request metadata are recorded, which is what powers per-token cost attribution in [Usage](/cloud_v2/billing#usage).

### Pointing a tool at the proxy

Base URL is `https://api.shiplight.ai/llm`, and your Shiplight token replaces the provider key:

```bash
# Anthropic
ANTHROPIC_BASE_URL=https://api.shiplight.ai/llm
ANTHROPIC_AUTH_TOKEN=shp_pat_…

# OpenAI
OPENAI_BASE_URL=https://api.shiplight.ai/llm/v1
OPENAI_API_KEY=shp_pat_…

# Gemini
GOOGLE_GEMINI_BASE_URL=https://api.shiplight.ai/llm
GEMINI_API_KEY=shp_pat_…
```

For the Shiplight CLI you don't set these at all — setting `SHIPLIGHT_API_TOKEN` is what puts it in proxy mode. See [LLM Providers](/local/local-testing/llm-providers).

### Requirements

The token needs **`llm:invoke`** (or full access). Without it you get a 403 naming the missing scope. This doesn't apply on Shiplight-managed compute, where credentials are injected automatically.

### Models

The proxy only forwards models in the Shiplight catalog. Requesting anything else is rejected before the request reaches the provider, with a 400 naming the unsupported model — so a typo or an unlisted model fails immediately rather than running up cost.

| Model                                                               | Provider  | Tier     |
| ------------------------------------------------------------------- | --------- | -------- |
| `claude-opus-4-8`, `claude-opus-4-7`                                | Anthropic | Pro      |
| `claude-sonnet-5`, `claude-sonnet-4-6`                              | Anthropic | Standard |
| `claude-haiku-4-5`                                                  | Anthropic | Lite     |
| `gemini-3.1-pro-preview`, `gemini-3.5-flash`                        | Google    | Standard |
| `gemini-3-flash-preview`                                            | Google    | Lite     |
| `gpt-5.6-sol`                                                       | OpenAI    | Pro      |
| `gpt-5.6-terra`, `text-embedding-3-large`, `text-embedding-3-small` | OpenAI    | Standard |
| `gpt-5.6-luna`                                                      | OpenAI    | Lite     |

Shiplight can also retire a model from the catalog, after which new requests for it are rejected the same way.

### What you're billed for

Usage is metered in millions of tokens (MTok) at your plan's rate per tier. The billed total is **every** token the provider reports — input, output, thinking, cache reads, and cache writes.

Shiplight checks your balance **before** forwarding the request, so an exhausted allowance fails fast without spending anything upstream. A request already in flight is always allowed to finish.

Retries are safe: send an `Idempotency-Key` header and a replayed request returns the cached response without billing twice.

## Related

- [LLM Providers](/local/local-testing/llm-providers) — the proxy versus your own provider keys
- [Billing](/cloud_v2/billing) — how token usage is priced
- [Test Results](/cloud_v2/test-results) — uploading and reading results
- [CI Runners](/cloud_v2/ci-runners) — automatic credentials on hosted runners
