# Store a browser storage state as a reusable session

POST /v1/sessions: Store a browser storage state as a reusable session

```http
POST /v1/sessions
```

|  |  |
|---|---|
| Operation id | `createSession` |
| Key scope | `run`: keys that run jobs (and `admin` keys) |
| Section | [Sessions](https://docs.kaab.ist/reference/api#sessions) |

## Request body

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | pattern `^[a-z0-9][a-z0-9-]{1,62}$` |
| `storage_state` | object | yes |  |
| `storage_state.cookies` | object[] | yes |  |
| `storage_state.cookies[].name` | string | yes |  |
| `storage_state.cookies[].value` | string | yes |  |
| `storage_state.cookies[].domain` | string | yes |  |
| `storage_state.cookies[].path` | string | yes |  |
| `storage_state.cookies[].expires` | number | yes |  |
| `storage_state.cookies[].httpOnly` | boolean | yes |  |
| `storage_state.cookies[].secure` | boolean | yes |  |
| `storage_state.cookies[].sameSite` | `"Strict"`, `"Lax"`, `"None"` | yes |  |
| `storage_state.origins` | object[] | yes |  |
| `storage_state.origins[].origin` | string | yes |  |
| `storage_state.origins[].localStorage` | object[] | yes |  |
| `storage_state.origins[].localStorage[].name` | string | yes |  |
| `storage_state.origins[].localStorage[].value` | string | yes |  |
| `origins` | string[] |  |  |
| `concurrency` | `"exclusive"`, `"shared"` |  | default `"exclusive"` |
| `refresh` | object |  |  |
| `refresh.program` | string | yes | min length 1 |
| `refresh.inputs` | map of string or number or boolean |  |  |

## Example request

```bash
curl -X POST "https://api.kaab.ist/v1/sessions" \
  -H "Authorization: Bearer $KAAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"acme","storage_state":{"cookies":[{"name":"sid","value":"abc","domain":"portal.acme.test","path":"/","expires":1790000000,"httpOnly":true,"secure":true,"sameSite":"Lax"}],"origins":[{"origin":"https://portal.acme.test","localStorage":[{"name":"theme","value":"dark"}]}]},"origins":["https://portal.acme.test"],"concurrency":"exclusive","refresh":{"program":"acme-login","inputs":{"email":"ops@acme.test"}}}'
```

## Responses

### 201

Session

[Session](https://docs.kaab.ist/reference/api/schemas/session)

```json
{
  "id": "ses_01j9zqk3q7m4n5p6r7s8t9v0wx",
  "object": "session",
  "name": "acme",
  "origins": [
    "https://portal.acme.test"
  ],
  "status": "valid",
  "concurrency": "exclusive",
  "refresh": {
    "program": "acme-login",
    "has_inputs": true
  },
  "last_verified_at": "2026-09-18T10:00:00Z",
  "last_used_at": "2026-09-18T10:00:00Z",
  "locked_by": null,
  "created_at": "2026-09-18T10:00:00Z",
  "updated_at": "2026-09-18T10:00:00Z"
}
```

## Errors

Every error answers with the [error envelope](https://docs.kaab.ist/reference/api/schemas/error-response); its `code` is one of the [error codes](https://docs.kaab.ist/reference/codes#errors).

| Status | When |
|---|---|
| 400 | `request_invalid`: request validation failed |
| 401 | Missing or invalid API key |
| 402 | `insufficient_credits`: top up to continue |
| 403 | The key's scope does not cover this operation |
| 409 | Conflicting state (see `error.code`) |
| 422 | Semantically invalid request (see `error.code`) |
| 429 | Rate limited; see `Retry-After` |
| 500 | `internal`: unexpected server error |
