> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kallima.bio/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> API tokens, authorization header, credits, rate limits, and error handling.

## API tokens

All `/v1/` endpoints authenticate via an API token. Tokens:

* Start with the prefix `ab_`
* Are 51 characters long
* Are scoped to a single organization
* Never expire (but can be revoked instantly)

**Create a token:** Dashboard → **Settings → API tokens → New token**.

API token access requires the **Team plan**. The token value is shown only once at creation — store it in a secrets manager or environment variable immediately.

## Authorization header

Pass your token in the `Authorization` header on every request:

```bash theme={null}
curl https://api.kallima.bio/v1/me \
  -H "Authorization: Bearer ab_your_token_here"
```

```python theme={null}
from kallima import KallimaClient
client = KallimaClient("ab_your_token_here")
```

Requests without a valid token return `401 unauthorized`.

## Check your balance

Before submitting compute jobs, verify your credit balance with:

```bash theme={null}
curl https://api.kallima.bio/v1/me \
  -H "Authorization: Bearer ab_your_token_here"
```

```json theme={null}
{
  "org_id": "aabbccdd-...",
  "plan": "team",
  "subscription_balance": 11840,
  "purchased_balance": 500,
  "total_credits": 12340,
  "monthly_grant": 12000
}
```

See [Credits](/credits) for the full cost table and how to buy additional credits.

## Rate limits

Every `/v1/` response carries rate-limit headers:

| Header                  | Meaning                                          |
| ----------------------- | ------------------------------------------------ |
| `X-RateLimit-Limit`     | Requests allowed per minute                      |
| `X-RateLimit-Remaining` | Requests left in the current window              |
| `X-RateLimit-Reset`     | RFC 7231 timestamp when the window resets        |
| `X-Quota-Limit`         | Write requests allowed this calendar month       |
| `X-Quota-Remaining`     | Write requests left this month                   |
| `X-Quota-Reset`         | RFC 7231 timestamp when the monthly quota resets |

**Reads** (GET) consume the rate bucket but do **not** count against your monthly write quota — polling for job status is free.

**Writes** (POST/PATCH/DELETE) consume both the rate bucket and the quota. Pipeline submits additionally spend credits.

| Plan       | Rate       | Monthly writes |
| ---------- | ---------- | -------------- |
| Team       | 60 req/min | 25,000         |
| Enterprise | custom     | custom         |

When you hit a limit the API returns `429` with a `Retry-After` header giving the seconds until the window resets.

## Errors

All error responses use [RFC 9457 problem+json](https://www.rfc-editor.org/rfc/rfc9457) with `Content-Type: application/problem+json`.

```json theme={null}
{
  "type": "https://docs.kallima.bio/errors/insufficient_credits",
  "title": "Insufficient credits",
  "status": 402,
  "detail": "Humanization costs 1 credit; balance is 0.",
  "instance": "/v1/humanizations",
  "code": "insufficient_credits",
  "request_id": "req_01JB..."
}
```

Switch on the `code` field — it is stable across API versions.

| `code`                 | HTTP | Meaning                                           |
| ---------------------- | ---- | ------------------------------------------------- |
| `unauthorized`         | 401  | Missing or invalid token                          |
| `not_found`            | 404  | Resource doesn't exist in your org                |
| `insufficient_credits` | 402  | Not enough credits — top up or upgrade            |
| `plan_required`        | 402  | Endpoint requires a higher plan                   |
| `rate_limit_exceeded`  | 429  | Slow down — check `Retry-After`                   |
| `quota_exceeded`       | 429  | Monthly write quota exhausted                     |
| `invalid_request`      | 400  | Malformed body                                    |
| `validation_failed`    | 422  | Field-level validation error — see `errors` array |
| `idempotency_mismatch` | 422  | Same `Idempotency-Key` with different body        |
| `conflict`             | 409  | e.g. canceling an already-running job             |
| `internal_error`       | 500  | Something went wrong on our side                  |

### Python SDK error handling

```python theme={null}
from kallima import (
    KallimaClient,
    KallimaError,
    InsufficientCreditsError,
    RateLimitError,
    NotFoundError,
)
import time

client = KallimaClient(api_key)

try:
    job = client.humanizations.submit(variant_id=variant_id)
except InsufficientCreditsError as e:
    print(f"Out of credits: {e}")
except RateLimitError as e:
    time.sleep(e.retry_after or 60)
    job = client.humanizations.submit(variant_id=variant_id)
except NotFoundError:
    print("Variant not found or doesn't belong to your org")
except KallimaError as e:
    print(f"API error {e.status_code} [{e.code}]: {e}")
```

## Idempotency

All write endpoints accept an `Idempotency-Key` header. Send a unique UUID per logical operation — replayed requests with the same key return the cached response without creating a duplicate job or spending credits twice.

```bash theme={null}
curl -X POST https://api.kallima.bio/v1/humanizations \
  -H "Authorization: Bearer ab_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"variant_id": "11112222-3333-4444-5555-666677778888"}'
```

Keys expire after 24 hours. Sending the same key with a different request body returns `422 idempotency_mismatch`.
