execution), and
read its result and receipt. You can also register, test, and connect an
output check (a verifier in the API). 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.millwork command-line
tool, so this page and the CLI setup use the same version. The tool reads
SOLVERAPI_API_KEY and optional SOLVERAPI_BASE_URL;
Set up with the CLI covers it.
For the shared setup and private key-entry rules, follow
Connect an output check. Use the
generated REST lifecycle reference
for exact API fields and the verifier-dock contract
for the endpoint request and response. The installed CLI reports its supported
commands and flags offline with millwork verifier capabilities --json.
Make a test run
First configure your organization key in this terminal. The SDK accepts the key and base URL as arguments; it does not choose an organization for you. Save this JavaScript example asexample.mjs next to the package.json where
you installed the SDK. It runs with Node directly and uses the same client
and methods as TypeScript. It submits a free test run and reads its receipt.
completed echo. For another outcome, keep the run ID and
follow Errors and retries. To get a model answer,
continue with Run a model.
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.
Register and test an output check
Start with a running endpoint that implements the output-check contract. SetVERIFIER_URL to its HTTPS address. Save this as output-check.mjs next to
the installed package and run node output-check.mjs from the terminal with
your organization key configured:
verifier_id. The test reports endpoint health; it does not
authorize a paid run. If the endpoint needs a key, continue with the private
handoff below. Do not put that key in verifiers.create.
Use an output check on a run
First save a model and keep itsarm_id. Connect and
test the check above, then keep its verifier_id. A live run has a platform fee
when accepted and may incur model usage. Review the exact task, model, limits,
check, and charge before authorizing this run; the
shared run procedure
owns approval and recovery.
Set ARM_ID, VERIFIER_ID, MAX_COST_USD, MAX_RUNTIME_S, and a unique
RUN_REQUEST_KEY in your terminal. Record that key with the exact request
before submitting; reuse it only for an uncertain retry of the same request.
Choose positive limits for the task you reviewed; the model budget is separate
from the platform fee. Save this as checked-run.mjs
next to the installed package. Run node checked-run.mjs only for the run you
have authorized:
execution_id and an initial status. Keep the request
key unchanged if you need to recover an uncertain submission. Read the
result and receipt
by that ID; a completed run can still have a rejected or unavailable check.
Connect, replace, or restore a protected output check
@millwork/solver@0.1.21 includes verifierConnection. Register the endpoint
as above, then start the private handoff from your server. This example uses
Response.redirect to send the intended person’s browser to Millwork’s
private page. Keep verifierOperationKey in that person’s server-side session
between the two requests. Do not log or retain the private URL. The person
enters the endpoint key on that page; the key is never an SDK argument.
beginProtected(verifierId, session) and returns
its redirect response. After private entry, the person returns to your app
manually and uses Continue, which calls finishProtected(verifierId, session). The
intent_id saved by the first action is the operation key used by the second.
The 90-day stop choice is an example; choose a supported stop policy for your
application. For a replacement or restoration,
create a new intent for the same verifier_id and repeat the handoff. Read
solver.verifiers.connection(verifierId) or
solver.verifierConnection.inspect(verifierId, { operationKey }) to see the
current state. The SDK also exposes testAndPromote and revoke as lower-level
operations; use continue and disconnect for read-backed lifecycle results.
To disconnect, obtain explicit confirmation from the person who owns the
connection, then save a new operation key for this disconnect:
disconnectKey unchanged if the result asks you to resume. Set the last
argument to true only after that explicit confirmation.
Millwork stopping use of its key does not revoke that key at your endpoint.
The shared connection guide owns the
deployment, private entry, governed-run approval, and receipt sequence.
Connecting or testing a check never authorizes a paid run.
What the client does
You construct oneSolver 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.
These methods return newest first: receipts.list(), arms.list(),
verifiers.list(), and proposals.list(). For arms, verifiers, and proposals,
use nextCursor and .next() to fetch older items. The receipts list has no
next page.
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.
Connect your provider account
CallmodelSourceProfiles.list() before requesting a provider credential.
Follow Connect a provider account for the returned
method and the handoff, test and model-refresh sequence. A browser step
finishing does not mean the connection passed its test or a paid run started.
For replacement or removal, sourceConnections.rotate() and
sourceConnections.revoke() operate on the existing connection ID. The
replacement guide explains when to remove
old provider access and how to recover a response you did not receive.
Errors
Every non-2xx response throwsSolverApiError. 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 lists each error code and the
next step. If a run was accepted and the provider later failed, inspect its
status, events and receipt. That is a run failure, not necessarily an SDK
transport failure; repeat browser setup only when access needs replacement.
API basics
The base URL, bearer authentication, request keys, polling, and the error format.
Make your first API call
Send a free test run with curl and read its receipt.