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

# TypeScript SDK

> Submit runs and read results with typed requests and responses in TypeScript and JavaScript.

Use the TypeScript SDK to connect a provider account, save a model, submit a
**run** (one task you send to Millwork; the API calls it an `execution`), and
read its result and receipt. It provides typed requests and responses
for TypeScript and JavaScript on Node.js.

## Install

Requires Node.js 20 or later (Millwork tests 20 and 22) and an organization
API key.

```bash theme={null}
npm install @millwork/solver@0.1.3
```

The package is [@millwork/solver on npm](https://www.npmjs.com/package/@millwork/solver).
Version 0.1.3 also includes the `millwork` command-line tool, which 0.1.0 and
0.1.1 do not carry. The tool reads `SOLVERAPI_API_KEY` and `SOLVERAPI_BASE_URL`
rather than the two variables this example names;
[Set up with the CLI](/get-started/tenant-start) covers it.

## Make a test run

The example reads two variables you set yourself; the client takes the key and
base URL as arguments. Use your organization API key and
`https://api.getmillwork.dev/v1`. Save it as `example.mts` and run it with
`npx tsx example.mts`. The package is ESM only, so a JavaScript copy needs
`"type": "module"` in your `package.json`.
[API basics](/api-reference/overview) explains authentication. This example
submits a test run and reads its receipt without calling a model.

```ts theme={null}
import { Solver } from "@millwork/solver";

const solver = new Solver({
  apiKey: process.env.MILLWORK_API_KEY!,
  baseUrl: process.env.MILLWORK_API_URL!, // https://api.getmillwork.dev/v1
});

const run = await solver.executions.create(
  {
    mode: "echo",
    task: { objective: "Check the Millwork API lifecycle." },
    policy: { data_classes: ["public"], budget: { max_cost_usd: 1, max_runtime_s: 30 } },
  },
  { idempotencyKey: `echo-${Date.now()}` },
);

let status = run.status;
while (!["completed", "failed", "cancelled", "expired"].includes(status)) {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  status = (await solver.executions.get(run.execution_id)).status;
}

const receipt = await solver.receipts.get(run.execution_id);
console.log(status, receipt.mode);
```

A **test run** (the API calls it Echo, `mode: "echo"`) has no platform fee or
model cost. It takes no **output check**, a check applied to a run's output, so
the example omits `verifier_id`.

## What the client does

You construct one `Solver` with `apiKey` and `baseUrl`. The client never
changes the base URL you give it. Each resource below calls one API endpoint
and returns the response typed. A saved model is an `arm` in the API, an output
check is a `verifier`, and an organization is a `tenant`.

| Client method or resource                                                    | REST endpoint                                                                           | What it does                                                                                                                                                                                                                            |
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `executions.create(request, { idempotencyKey })`                             | `POST /v1/executions`                                                                   | Submits a run.                                                                                                                                                                                                                          |
| `executions.get(id)`                                                         | `GET /v1/executions/{id}`                                                               | Reads a run's status.                                                                                                                                                                                                                   |
| `executions.events(id)`                                                      | `GET /v1/executions/{id}/events`                                                        | Polls the run's events and stops after the final status event.                                                                                                                                                                          |
| `executions.result(id)`                                                      | `GET /v1/executions/{id}/result`                                                        | Reads the model output of a completed live run.                                                                                                                                                                                         |
| `executions.cancel(id)`                                                      | `POST /v1/executions/{id}/cancel`                                                       | Cancels a run.                                                                                                                                                                                                                          |
| `receipts.get(id)`, `receipts.list(filter)`                                  | `GET /v1/receipts/{id}`, `GET /v1/receipts`                                             | Reads one receipt, or lists receipts by time, status, or saved model.                                                                                                                                                                   |
| `arms` create, list, get, update, disable                                    | `/v1/arms`                                                                              | Manages your saved models.                                                                                                                                                                                                              |
| `verifiers` create, list, get, update, test, retire                          | `/v1/verifiers`                                                                         | Manages your output checks.                                                                                                                                                                                                             |
| `modelSourceProfiles.list()`                                                 | `GET /v1/model-source-profiles`                                                         | Lists the providers you can connect with your provider key.                                                                                                                                                                             |
| `sourceCredentialHandoffs` start, poll                                       | `/v1/source-credential-handoffs`                                                        | Starts the browser step where you enter your provider key; `poll` reads the step's state once, so call it until the step is `completed`. The key never passes through the client.                                                       |
| `sourceConnections` create, list, get, test, rotate, revoke, syncDeployments | `/v1/source-connections`                                                                | Manages a provider connection and loads its models.                                                                                                                                                                                     |
| `modelDeployments` list, get                                                 | `/v1/model-deployments`                                                                 | Reads the models loaded from your connections.                                                                                                                                                                                          |
| `modelCatalog.get()`, `modelCatalog.definitions()`                           | `GET /v1/model-catalog`, `GET /v1/model-definitions`                                    | Reads the models you can save now, and model identity records.                                                                                                                                                                          |
| `apiKeys` create, list, update, revoke                                       | `/v1/api-keys`                                                                          | Manages organization API keys.                                                                                                                                                                                                          |
| `proposals` list, get, approve, reject                                       | `/v1/proposals`                                                                         | Reads and decides proposed follow-up actions.                                                                                                                                                                                           |
| `usage.get(period)`                                                          | `GET /v1/usage`                                                                         | Reads usage for a period.                                                                                                                                                                                                               |
| `account.get()`                                                              | `GET /v1/account`                                                                       | Reads your account, quota, and balance.                                                                                                                                                                                                 |
| `evalSummary.get(window)`                                                    | `GET /v1/eval-summary`                                                                  | Reads the evaluation summary for a time window.                                                                                                                                                                                         |
| `complianceExports.get(period)`                                              | `GET /v1/compliance-export`                                                             | Reads a period's compliance export.                                                                                                                                                                                                     |
| `tenantTemplates` list, plan, apply, get, recover, resume                    | `/v1/tenant-templates`, `/v1/tenant-template-plans`, `/v1/tenant-template-applications` | The setup path the CLI uses. Present from 0.1.2 on.                                                                                                                                                                                     |
| `bootstrapTenant({ baseUrl, displayName })`                                  | `POST /v1/tenants`                                                                      | Creates an organization and its first API key. A standalone function, because it runs before you have a key. It takes no request key and does not replay: a same-name retry is refused, a different name creates a second organization. |

Run submission takes a **request key**, sent as the `Idempotency-Key` header.
You own the key; the client forwards it unchanged, so a retry with the same
key returns the same run instead of starting a second one. Most other writes accept
a request key as an option. The client offers no request-key option for
cancel, proposal decisions, and template plans, so each of those gets one
attempt. Template apply and template resume require a request key.

The client retries on its own only when a replay cannot apply work twice: a
read, or a write that carries your request key. It retries those after a
network failure or a `5xx` response, up to two more attempts by default
(`maxRetries`), with exponential backoff from 500 ms (`retryBackoffMs`), and
replays the same bytes each time. It never retries a `4xx` response, and a
write without a request key gets exactly one attempt.

## Errors

Every non-2xx response throws `SolverApiError`. It carries the API's error
object as fields, so you never parse the message: `type` (the error code),
`status`, `detail`, `instance`, `errors` (per-field messages, when present),
and `retryAfterS` (the seconds to wait, when the API sends one). A network
failure, or an error response whose body is not valid JSON, throws
`SolverApiNetworkError` with the underlying `cause`.
[Errors and retries](/guides/errors-and-retries) lists each error code and the
next step.

<CardGroup cols={2}>
  <Card title="API basics" icon="book" href="/api-reference/overview">
    The base URL, bearer authentication, request keys, polling, and the error format.
  </Card>

  <Card title="Make your first API call" icon="terminal" href="/get-started/first-api-call">
    Send a free test run with curl and read its receipt.
  </Card>
</CardGroup>
