# Keys for coding agents

> Get a temporary SentiSense API key with one keyless call, use it right away, and keep the same key on a free account with the keep link.

Base URL: `https://app.sentisense.ai/api/v1/keys`
Tier: Free (no API key needed to call)

All API access requires an API key via the `X-SentiSense-API-Key` header. Keys look like `ss_live_...`.
## Overview

A coding agent working in a project that has no SentiSense key can get one itself with a single call that needs no key. The response carries a working API key and a keep link. The agent uses the key right away and gives the keep link to the person it works for. That person opens the link, signs in or creates a free account, and the same key stays on their account, so nothing in the project has to change.

From a terminal the same call is one command: `npx sentisense init` (see [From the command line](#from-the-command-line)). A person who prefers to sign up first gets a free key at [app.sentisense.ai/get-api-key](https://app.sentisense.ai/get-api-key).

**Until the key is kept:**

- It works for 72 hours from the moment it was made.
- It allows 10 requests a minute, 500 requests per UTC day and 1,000 requests in all.
- Every data endpoint answers it the way it answers a Free key. Account endpoints (`/api/v1/apikeys`, `/api/v1/billing`, `/api/v1/account`, `/api/v1/user` and the like) answer `403 key_not_kept`.

Keeping the key moves it onto the Free tier, with its 30 requests/minute and its monthly allowance.

---

## POST /api/v1/keys/provision

Makes a temporary API key and returns it with its keep link and limits. No request body.

**Authentication:** no API key needed. This is the one endpoint that takes no key; every call made with the key it returns sends it in the `X-SentiSense-API-Key` header as usual.

**Headers:**

| Header | Required | Description |
|--------|----------|-------------|
| `X-SentiSense-Client-Id` | No | A random UUID generated once per install and sent on every call to this endpoint. Limits per machine are counted on it; limits per network apply either way |

**Example Request:**

```bash
curl -X POST https://app.sentisense.ai/api/v1/keys/provision \
  -H "X-SentiSense-Client-Id: 3f6c2a5e-8d1b-4c7a-9e2f-1b5d6a7c8e90"
```

**Example Response (201 Created):**

```json
{
  "apiKey": "ss_live_YOUR_KEY",
  "expiresAt": 1800259200,
  "keepUntil": 1801209600,
  "keepUrl": "https://app.sentisense.ai/keep-key#token=YOUR_KEEP_TOKEN",
  "limits": {
    "requestsPerMinute": 10,
    "requestsPerDay": 500,
    "requestsTotal": 1000
  },
  "docs": {
    "llms": "https://sentisense.ai/llms.txt",
    "skill": "https://sentisense.ai/skill.md"
  }
}
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `apiKey` | string | The temporary key (`ss_live_...`). Store it in the project's own secret store, such as an environment variable or a secret manager, and never in committed code |
| `expiresAt` | int | Epoch seconds when the key stops working unless it has been kept |
| `keepUntil` | int | Epoch seconds until which the keep link works. Later than `expiresAt`: a key that has stopped can still be kept |
| `keepUrl` | string | The keep link. Give it only to the person you work for: whoever keeps the key first has it on their account. Use it exactly as returned |
| `limits.requestsPerMinute` | int | Per-minute limit until the key is kept |
| `limits.requestsPerDay` | int | Requests per UTC day until the key is kept |
| `limits.requestsTotal` | int | Requests in all until the key is kept |
| `docs.llms` | string | Agent-readable index of the API docs |
| `docs.skill` | string | The single-file agent reference |

The response carries `Cache-Control: no-store`.

**Errors:**

Every refusal is `{"error": "...", "message": "..."}`, and the message says what to do next. A free key from [app.sentisense.ai/get-api-key](https://app.sentisense.ai/get-api-key) works in every case below.

| Status | `error` | When |
|--------|---------|------|
| 403 | `account_blocked` | An account policy blocks this network or device. The message carries a reference code (`AP-...`) to quote to support |
| 403 | `browser_not_supported` | The request carries an `Origin` header from another website. Call it from a terminal or a server |
| 403 | `client_ip_unknown` | The caller's network address could not be determined |
| 429 | `provision_limit_reached` | This network has used today's temporary keys. `Retry-After` gives the seconds until 00:00 UTC |
| 429 | `keep_existing_key` | This network or install already has temporary keys that were never kept. Keep one of them with its keep link, or create a free account |
| 503 | `provision_paused` | New temporary keys are paused for the day. `Retry-After` gives the seconds until 00:00 UTC. Keys already issued keep working |
| 503 | `provision_unavailable` | Temporary keys are unavailable for a moment. Try again in a few minutes |

---

## Calls made with a temporary key

Every response to a call made with a key that has not been kept carries three extra headers. They stop appearing once the key is kept.

| Header | Value |
|--------|-------|
| `X-SentiSense-Key-Status` | `temporary` |
| `X-SentiSense-Key-Expires-At` | Epoch seconds when the key stops working |
| `X-SentiSense-Keep-Url` | The keep link for this key |

At a limit, or once the key has stopped, the refusal names the keep link in its `message`:

| Status | `error` | When |
|--------|---------|------|
| 401 | `key_expired` | The 72 hours are over. Until `keepUntil` the message carries the keep link, and keeping the key makes the same key work again |
| 403 | `key_not_kept` | An account endpoint was called with a key that has not been kept |
| 429 | `rate_limit_exceeded` | Over the per-minute limit. Keeping the key raises it |
| 429 | `key_limit_reached` | The day's 500 requests or the 1,000 in all are used, or temporary keys are busy right now. `Retry-After` is set when waiting helps |

---

## Keeping the key

1. The person opens the keep link in a browser.
2. They sign in, or create a free account.
3. They confirm on the page. The same key string moves onto their account, so the project keeps working with nothing to change, now on the Free tier's limits.

The keep link works for 14 days from the moment the key was made, including after the key has stopped working at 72 hours. If the account already has an API key, the page asks whether to use the new key and retire the current one, or to keep the current one. After `keepUntil` the key can no longer be kept: make a new one.

---

## From the command line

```bash
npx sentisense init
```

Makes a temporary key and prints `SENTISENSE_API_KEY=<key>` in full, when it expires, the keep link and how long it works, the limits, and where the agent docs are. It writes no project files: put the key in the project's own secret store. The CLI sends its own `X-SentiSense-Client-Id`.

If a key is already configured (the `SENTISENSE_API_KEY` environment variable, or a key saved with `sentisense auth`), `init` says where it comes from and makes no new one. `npx sentisense init --new` asks for a fresh temporary key anyway. `--json` prints the exact API response.
