# API quickstart

> Create an API key, authenticate with a Bearer token, check it with whoami, choose scopes, find every endpoint, and revoke a key you no longer use.

API keys let your own scripts and CI act for your organization. Each key carries only the scopes you give it.

## Create a key

1. Turn on two-factor authentication in **Settings**. Creating a key requires it.
2. In the console, open **Keys** and choose **Create key**.
3. Name the key after what uses it, for example `ci-runner`.
4. Pick its scopes and its lifetime: 30, 90, 180 or 365 days.
5. Optionally, set its spending limits (see below).
6. Copy the key. It is shown once.

Owners and admins of the organization manage keys. Each new key is announced by email to the person who created it.

## Authenticate

Send the key as a Bearer token:

```bash
export NODELODGE_API_KEY="nl_live_..."
curl https://nodelodge.com/v1/whoami \
  -H "Authorization: Bearer $NODELODGE_API_KEY"
```

The answer names the organization and the scopes the key carries:

```json
{
  "orgId": "6f1c...",
  "via": "api_key",
  "apiKeyId": "2b9e...",
  "scopes": ["workloads:read"]
}
```

Use `whoami` in a pipeline to fail fast on a revoked, expired or mistyped key.

## Reference

Every endpoint, with its parameters and a curl example, is in the [API reference](https://nodelodge.com/docs/api-reference). The same description is published as an OpenAPI 3.1 document at `https://nodelodge.com/v1/openapi.json`: import it in your HTTP client, or generate a typed client from it.

```bash
curl https://nodelodge.com/v1/openapi.json -o nodelodge-openapi.json
```

## Scopes

| Scope | Grants |
|---|---|
| `workloads:read` | Read the catalogs, your sessions and rentals, your saved SSH keys and the environments. |
| `workloads:write` | Launch and stop sessions and raise their budget, charged to your organization, and read the connection details of the sessions the key launched. |
| `volumes` | Manage storage volumes. |
| `secrets` | Manage stored secrets. |
| `billing:read` | Read the credit available and your account limits. |

Give each key the fewest scopes its job needs. A key that only reports status needs `workloads:read`.

## What a key can call

| Request | Scope |
|---|---|
| `GET /v1/catalog/partner-offers`, `GET /v1/catalog/partner-offers/{id}` | `workloads:read` |
| `GET /v1/catalog/offers`, `GET /v1/catalog/offers/{id}` | `workloads:read` |
| `GET /v1/sessions`, `GET /v1/sessions/{id}`, `GET /v1/sessions/{id}/receipt` | `workloads:read` |
| `GET /v1/environments`, `GET /v1/client-address`, `GET /v1/ssh-keys` | `workloads:read` |
| `POST /v1/sessions`, `POST /v1/sessions/{id}/stop`, `POST /v1/sessions/{id}/budget` | `workloads:write` |
| `GET /v1/sessions/{id}/access` | `workloads:write` |
| `GET /v1/reservations`, `GET /v1/reservations/{id}` | `workloads:read` |
| `POST /v1/reservations`, `POST /v1/reservations/{id}/start`, `/complete`, `/cancel` | `workloads:write` |
| `GET /v1/account/funds`, `GET /v1/limits` | `billing:read` |
| `GET /v1/whoami` | any |

A key raises the budget and reads the connection details of the sessions it launched only. Any key of the organization with `workloads:write` can stop a session.

## Launch a session

```bash
curl -X POST https://nodelodge.com/v1/sessions \
  -H "Authorization: Bearer $NODELODGE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"partnerOfferId":"3f0c8f5e-8c3a-4f39-9a8e-2d9b4c1e7a10","environmentId":"jupyterlab","pricing":"on_demand","budgetCents":2000,"allowedCidr":"203.0.113.7","sshPublicKey":"ssh-ed25519 AAAA... you@laptop"}'
```

- `budgetCents` is the most the session may cost. It is reserved on your credit at launch. Billing follows the real time the machine runs, from the moment it is ready, and Budget Guard stops the session before the budget is spent.
- `allowedCidr` is the public IPv4 address, or a range up to /24, allowed to connect over SSH.
- `sshPublicKey` opens this session only: it is not saved on your account. To use a key saved in the console, send its id in `sshKeyIds` instead. Saving or removing a key on your account is done in the console.
- `environmentId`: data-center machines run `jupyterlab`. `GET /v1/environments?offerId=...` lists what a Community machine can run.
- Add `maxDurationHours` to stop the session after that many hours, even with budget left.
- The `Idempotency-Key` header makes a retried request start one session.

Read the session with `GET /v1/sessions/{id}`: once its status is `ready`, `directSsh` gives the host, user and port. Raise its budget with `POST /v1/sessions/{id}/budget`, and stop it with `POST /v1/sessions/{id}/stop`: billing ends and the rest of the budget is released.

When `POST /v1/sessions` answers `409 RESERVATION_REQUIRED`, book the machine with `POST /v1/reservations` (`partnerOfferId` and `durationHours`, or `mode: "on_demand"`), then start it with `POST /v1/reservations/{id}/start`. A fixed duration holds its full price, and `maxCostCents` refuses the booking when that amount would exceed it. On demand, the amount held covers the next 60 minutes and is renewed while the machine runs. In both cases you are billed per started minute of real use, with no one-hour minimum.

To drive sessions from an AI agent, use the [MCP server](https://nodelodge.com/docs/mcp).

## Spending limits

Each key can carry limits, enforced by Node Lodge when a session is launched, when its budget is raised, and each time an on-demand reservation is extended:

| Limit | Bounds |
|---|---|
| Per session | The most one session launched with the key can cost: its budget, raises included. |
| Total | Everything the key has ever committed: the whole budget of a running session, what it was billed once it ended. |
| Calendar month | The same, for sessions launched this calendar month (UTC). |
| Sessions at a time | Running sessions and open reservations of the key, together. |

A launch or a raise that would go past a limit answers `409 API_KEY_LIMIT` and reserves nothing. Requests made at the same time with one key are checked one after the other, so they cannot pass a limit together. A key without limits is still bounded by your available credit and your [account limits](https://nodelodge.com/docs/account-limits). Owners and admins change the limits of a live key with **Edit limits** in **Keys**, after a fresh two-factor code. Sessions launched from the console are not limited by any key.

Account settings, keys, saved SSH keys, cards and two-factor stay in the console: a request with an API key to those answers `403 API_KEY_NOT_ALLOWED`. Every action made with a key is listed in **Activity**, with the key that made it.

## Errors

| Status | Meaning |
|---|---|
| `401` | The key is missing, mistyped, revoked or expired. |
| `402` | Your available credit does not cover the session. |
| `403` | The key lacks the scope, or the action needs a console session. |
| `409` | A limit of the key, or the `maxCostCents` of the request, would be exceeded. `SESSION_REQUIRED` and `RESERVATION_REQUIRED` name the request to send instead. |
| `429` | Too many requests. Wait, then retry with backoff. |

Error bodies have the same shape everywhere:

```json
{ "error": { "code": "API_KEY_NOT_ALLOWED", "message": "...", "reference": "7F3K-92QD" } }
```

`reference` identifies the request. Log it with the error, and include it when you write to support.

## Keep keys safe

- Store keys in your secret manager or CI secrets, never in code.
- One key per tool, so you can revoke one without touching the others.
- Revoke a key in **Keys** the moment it leaks. Requests using it stop at once.
- Every key creation and revocation is listed in **Activity**.
