# Authentication

Every request carries an API key. What a key can do depends on its scope and on the member who created it.

Source: https://docs.pantechdynamics.com/api/authentication

## Send your key

Create a key in the console under **Organization → API keys** ([how](https://docs.pantechdynamics.com/getting-started/api-keys)). Send it on every request as a bearer token:

```http
Authorization: Bearer PAN_…
```

```console
$ curl https://api.pantechdynamics.com/public/v1/me \
    -H "Authorization: Bearer $PANTECH_API_KEY"
```

The key alone decides who you are. There is no organization id in the path: a key belongs to one organization, and every request acts in it.

Keys work only on the public API, at `/public/v1` on api.pantechdynamics.com. They are not accepted anywhere else, and a console sign-in session does not work on the public API.

:::warning[Treat a key like a password]
Keep it in your CI's secret store or an environment variable, never in code or a repository. If one leaks, revoke it in the console at once; it stops working within about 30 seconds.
:::

## Scopes

A key has one of two scopes, chosen when you create it:

| Scope | Can call |
| --- | --- |
| `read` | Every `GET`, and the price estimate |
| `write` | Everything a read key can, plus every create, change and delete |

### Keys for AI apps

A key the console makes when you [connect an AI app](https://docs.pantechdynamics.com/ai/connect-your-ai) has `kind` `ai_app`. It is listed under **Organization › AI apps**, not **API keys**. It can carry a third scope, `delete`, which only AI app keys use and only together with `write`:

| AI app access | Scopes |
| --- | --- |
| Read only | `read` |
| Manage | `write` |
| Manage and delete | `write`, `delete` |

For an AI app key, `write` does not cover deleting or wiping data. These calls also need `delete`: every `DELETE` except `DELETE /me`, rebuilding or restoring an instance, and lowering a snapshot schedule's `retention_count`. Each one's entry in the reference says so. Without `delete` the call returns `403 INSUFFICIENT_SCOPE` and nothing changes. Restoring a snapshot to a new volume overwrites nothing, so it needs only `write`. A standard key's `write` still covers all of these.

Each endpoint in this reference says which scope it needs. Calling one your key's scope does not cover returns `403` with code `INSUFFICIENT_SCOPE`, and no change is made.

Use a read key wherever you only need to look: dashboards, monitoring, cost reports.

## A key acts as its creator

A key never has more access than the member who created it. If that member's role does not allow something, the key cannot do it either, and the call returns `403 FORBIDDEN`. If the member leaves the organization, their keys stop working.

## Check a key

`GET /me` returns the key's organization, its scopes, when it expires, its `kind` (`standard` or `ai_app`) and, for an AI app, the app's `client_name`. It is the cheapest way to confirm a key works before a long job:

```json
{
  "organization_id": "org_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "project_id": "acc_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "api_key": {
    "id": "key_06gk3x9tq7m2v8r4y1c5d0zp8w",
    "name": "github-actions",
    "scopes": ["read", "write"],
    "expires_at": "2026-12-31T09:30:00Z",
    "kind": "standard",
    "client_name": null
  }
}
```

## Revoke the key you are using

`DELETE /me` revokes the key that sends it, and returns `204`. Use it when a job is done, or to sign out. It needs only `read`, and no `Idempotency-Key`. Calling it again returns `401`, because the key is gone.

```console
$ curl -X DELETE https://api.pantechdynamics.com/public/v1/me \
    -H "Authorization: Bearer $PANTECH_API_KEY"
```

## The Pantech-Client header

Pantech's own tools say who they are with a `Pantech-Client` header. The MCP server sends `Pantech-Client: mcp/<version>`. When an organization has [turned AI apps off](https://docs.pantechdynamics.com/ai/ai-apps-security#turn-ai-apps-off-for-the-organization), the API refuses any request carrying it, whatever key it uses. You do not need to send this header yourself.

## When authentication fails

| Status | `code` | Meaning |
| --- | --- | --- |
| `401` | `UNAUTHENTICATED` | No key, or one that is mistyped, revoked or expired. Check the URL starts with `/public/v1` |
| `403` | `INSUFFICIENT_SCOPE` | The key's scope does not cover this endpoint |
| `403` | `AI_APPS_DISABLED` | AI app access is turned off for this organization. An owner can turn it on under **Organization › AI apps** |
| `403` | `FORBIDDEN` | The key's creator is not allowed to do this |
| `429` | `RATE_LIMITED` | Too many failed attempts from your address, or the key's budget is used up |

Repeated requests with a wrong key from one address are slowed down. Fix the key before retrying.
