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

# Discovery and admission endpoints

> Look up an engine, or admit a request with auto-provision and auto-wake.

Two endpoints. Both require `X-Platform-Key`.

`/admit` is the primary entry point for products — it's the one you
call on every user request.

## GET /engines/{user_id}

Look up the engine for a user. Read-only. Doesn't trigger
provisioning.

### Request

```http theme={null}
GET /engines/demo-user-001
X-Platform-Key: pk-sept-...
```

### Response (200)

```json theme={null}
{
  "engine_id": "5c2f...",
  "user_id": "demo-user-001",
  "status": "running",
  "url": "http://engine-...:8000",
  "api_key": "sk-sept-...",
  "engine_version": "september-engine:2.3.0",
  "created_at": "2026-04-27T12:34:56.000Z",
  "last_health_at": "2026-04-27T12:35:11.000Z"
}
```

If the engine is `stopped` or `sleeping`, the URL may still be set
(the container is just paused). Check `status`.

### Errors

* `404 ENGINE_NOT_FOUND` — no engine for this user\_id.

## POST /engines/{user_id}/admit

The product's main call. Goes through:

1. **Rate limit check** (`policy.check_admit`).
2. **Lookup** in the registry.
3. **Auto-provision** if no engine and `auto_provision=true`.
4. **Auto-wake** if engine is `sleeping` and `auto_wake=true`.
5. **Return** the engine's URL + key, or denial.

### Request

```http theme={null}
POST /engines/demo-user-001/admit
X-Platform-Key: pk-sept-...
Content-Type: application/json

{
  "auto_provision": true,
  "auto_wake": true
}
```

| Field            | Type | Required | Default | Purpose                                                |
| ---------------- | ---- | -------- | ------- | ------------------------------------------------------ |
| `auto_provision` | bool | no       | `false` | If no engine exists, provision one (subject to quota). |
| `auto_wake`      | bool | no       | `false` | If engine is sleeping, wake it.                        |

### Response (200)

Admitted:

```json theme={null}
{
  "admitted": true,
  "engine": {
    "engine_id": "5c2f...",
    "user_id": "demo-user-001",
    "status": "running",
    "url": "http://engine-...:8000",
    "api_key": "sk-sept-...",
    "engine_version": "september-engine:2.3.0",
    "created_at": "2026-04-27T12:34:56.000Z",
    "last_health_at": "2026-04-27T12:35:11.000Z"
  }
}
```

Not admitted:

```json theme={null}
{
  "admitted": false,
  "engine": null,
  "reason": "engine_unhealthy" | "engine_not_found" | "engine_sleeping"
}
```

### When admitted is false

| Reason             | Cause                                       | What to do                     |
| ------------------ | ------------------------------------------- | ------------------------------ |
| `engine_not_found` | No engine and `auto_provision=false`.       | Call `/provision` explicitly.  |
| `engine_sleeping`  | Engine is sleeping and `auto_wake=false`.   | Call `/start` explicitly.      |
| `engine_unhealthy` | Engine is `failed` and not auto-restarting. | Investigate via the audit log. |

### Errors

* `429 RATE_LIMITED` — product over `rate_limit_rpm`.
* `429 QUOTA_EXCEEDED` — product at `max_engines` (only when
  `auto_provision=true` and a provision was attempted).
* `503 PORT_EXHAUSTION` — port allocator empty.
* `504 BOOT_TIMEOUT` — auto-provisioned engine didn't become healthy.

## When to use which

| You want to                                        | Use                                                      |
| -------------------------------------------------- | -------------------------------------------------------- |
| Get engine info for a known-existing user          | `GET /engines/{user_id}`                                 |
| Process a user request, possibly auto-provisioning | `POST /admit` with `auto_provision=true, auto_wake=true` |
| Provision deliberately at signup time              | `POST /engines/provision` directly                       |

`/admit` is idempotent and safe to call on every user request. It
handles the rate-limit and quota concerns for you.

## See also

* [Lifecycle](../../lifecycle) — the state machine.
* [Policy](../../policy) — quota and rate-limit details.
* [Lifecycle endpoints](./lifecycle) — the explicit operations.
