Connect from your terminal
With the CLI installed and your Millwork API key configured, list the providers and connections:available_providers and existing_connections. A provider can be absent from new setup while an existing
connection remains visible.
This is an authenticated read of your organization; it starts no model run.
If the key is rejected, follow API key help.
An empty provider list needs model access help,
not another credential.
Choose your provider from the setup table, prepare
its account access, and run its command below. Each command starts one setup;
run only the row for the provider you chose.
Choose a model if setup offers more than one. If the provider you want is not
listed, stop and ask support about access; choosing OpenRouter would use its
gateway route, not the provider’s direct connection. OpenRouter asks you to approve
access in the browser; key-entry providers ask for their key on Millwork’s
private setup page. For AWS Bedrock, enter a
short-term Bedrock API key on that page; Millwork
lists your available system profiles and matches the Bedrock model you selected. Or use
its explicitly selected advanced STS method. Return to
the same terminal to finish. Setup may reuse
an existing connection, so this command does not always connect a new account.
The command follows the same journey as
millwork tenant start --template byok-open-model --source-id "<source ID>".
For a specific model or a script, follow
Choose a provider and model in a script.
Keep the application ID and connection ID. If you stop, continue the saved
application.
Setup asks separately before a paid run and shows its model, payer and costs.
Connecting provider access alone does not approve spending.
Follow the CLI setup guide through its paid-run step
in the same setup. Review the selected model and provider, your provider account
as the model-usage payer, the Millwork platform fee, model budget and runtime
limit before approving. A model call already running can exceed its budget;
the budget stops further calls once recorded spend reaches it.
Expected result: First live result ready., an answer and a receipt for
the same run. Check the provider and selected model against your setup.
A receipt records the outcome, route and model usage; it does not contain
the answer or prompt. Provider-reported model details may be absent. Use
Results and receipts to distinguish the
requested model from the identity the provider reported. A connection check
or free test run alone does not prove that a model answered.
If setup stops, use Provider connection help.
For Millwork fee credit, add credit and continue the same application.
For provider_insufficient_funds, fund the chosen provider account through
its own billing controls; Millwork credit does not pay that bill. Funding
either account does not approve another paid run.
Connect through the REST API
Use these steps when your application manages connection setup. They use a private browser step and return a connection ID for later requests. The OpenAI example usesopenai_direct with api_key;
Provider setup fields lists the other methods.
Before you begin
- Your organization is approved for the private preview.
- Your Millwork API key is configured for the organization you want to connect.
- You have
curlandjq.
umask 077 keeps newly created response files private to you. Keep
handoff.json out of source control and support messages; it contains the
private setup link.
List the providers your organization can connect:
source_id
and authentication methods. For OpenRouter, use
OpenRouter browser setup. The api_key method
in OpenRouter’s profile describes the resulting credential; you still
connect by approving access in the browser.
Use only a provider and method returned here. For the OpenAI example below,
confirm openai_direct offers api_key, then get a key allowed to list and
call models in the intended OpenAI account. Enter it only in the browser step.
If the provider you need is absent, contact support.
For a provider with browser key-entry setup enabled, this diagram shows the
requests your app sends and the step you complete in the browser.
1
Start secure setup
Continue here after choosing Expected result:
openai_direct with api_key from the list above.
For OpenRouter, follow CLI setup; its browser
approval is different from entering a key.201 with state pending, a handoff_intent_id, a
one-time continue_url, and expires_at.If the start response is lost, repeat the same request with the saved
SETUP_REQUEST_KEY; do not generate another key for that retry.Save handoff_intent_id. The last command stores it in SETUP_ID; steps 2
and 3 send it.Open continue_url in your browser, sign in to the intended Millwork
organization and enter the provider key there before expires_at.
The link belongs to this setup; keep it private.2
Wait for the browser step to finish
completed. While the browser step is still open, the
value is pending; check again. This response does not include continue_url.
The completed response includes source_scope. Keep that object unchanged;
the next step sends it back to connect the account you just set up.A secure setup belongs to one organization and one provider, expires at
expires_at, and can be used once. If state is expired or failed, start
a new secure setup from step 1. The old link cannot be reused.If it is consumed, the setup has already been used to create or update a
connection. List connections with GET /v1/source-connections and check the
existing connection before starting again.3
Create and test the connection
201 with a connection_id, status disabled, and
test_state untested. Continue only after the connection is created.
Millwork does not run anything through it until its test passes.Save the connection ID and test it:connection_id. The assignment stores it in CONNECTION_ID; the
test, the model refresh, and every later rotate or revoke send it.Expected result: the test returns status active, test_state passed,
and test_error null. If test_state is failed, test_error names the
reason and the connection stays disabled. Fix it with the table under
If the connection test fails before you
refresh models.The connection check verifies provider access, such as reading account or
model information. It makes no model call. A live run is the step that asks
the chosen model to answer.4
Refresh models and read your catalog
deployments, one entry per model
this connection can use, and the first jq prints their count. The catalog
returns models; the last command prints the names of the ones that come from
this connection. Keep CONNECTION_ID in this terminal and follow
Run a model. That guide filters to this connection, saves
your chosen model and pins the first run to it.If no models appear after a successful refresh, check the account and any
provider permissions needed for the model. Ask support about
supported models with the connection_id and requested model, never the key.
An empty catalog does not by itself mean the credential is invalid.Provider setup fields
These are reference fields for provider-specific integrations. They do not list which connections are enabled for your organization; useGET /v1/model-source-profiles for that. OpenRouter uses the CLI browser flow
described above.
Millwork offers setup for all nine providers below. Check
millwork provider list for your organization before obtaining a key; it
also shows any existing connections you can manage.
Availability is organization-specific. Always use
millwork provider list as
the current answer before starting setup.
Initial setup for a key-entry provider asks for one active provider API
key on Millwork’s private browser page. It does not ask you to paste a
provider project, workspace or account ID into the CLI. Choose the key from
the provider scope you intend to use and bill:
Choose the account, project or workspace you want billed, and make sure it
allows API use of your selected model. A subscription to a provider’s chat
application does not by itself establish API access or API credit. Keep the
key out of CLI arguments, chat and source control. The browser asks for the
provider key, not your Millwork API key.
If your chosen provider is absent from
millwork provider list,
contact support before setup; do not substitute a gateway route.
For AWS, follow AWS Bedrock setup for the
prerequisites, private form fields and access renewal. Use the source and
auth scheme returned by GET /v1/model-source-profiles. Choose STS explicitly
when you need it; renewal keeps the connection’s existing method. Gemini means the Gemini Developer API,
not Vertex AI.
For provider account and key-management links, see
Manage access at your provider.
If the connection test fails
Rotate or revoke a connection
To replace access, usemillwork provider rotate "<connection ID>" and follow
Replace a provider key. It tests the new
access before switching and keeps the existing connection.
To disconnect, use the exact ID from millwork provider list:
state is disconnected: routing
through that connection is disabled and removal of its saved credential is
scheduled. It does not revoke the provider’s key or select a fallback model.
Already-dispatched model calls may finish. Choose another model explicitly
before your next task if you disconnected the selected connection.
In a script, first add --json to preview the change. After the human approves,
use the returned command with --yes. An optional --idempotency-key can be
reused after an uncertain response. An already-revoked connection is inspected
without sending another delete.
Manage the connection through the API
Replace access on the same connection withPOST /v1/source-connections/{connectionId}/rotate. OpenRouter
asks for approval again; a key-entry provider asks for a replacement key.
For AWS Bedrock, renew access
with the same method, region and profile. Millwork tests the replacement before
switching. A failed replacement keeps the previous binding, but cannot make an
expired or revoked credential work. Follow
Replace a provider key for each request
and its expected result.
To disconnect, read GET /v1/source-connections and keep the connection ID.
Check its catalog models with GET /v1/model-catalog and any saved models
with GET /v1/arms before disconnecting. Then use that connection ID:
status disabled, and a
revoked_at timestamp. Millwork disables only the models tied to this connection
and schedules removal of its saved credential. A model call already sent may
finish; disconnecting does not cancel it or return its platform fee.
If you lose the response, read GET /v1/source-connections/{connectionId}
before repeating the request. A connection with revoked_at has already
been disconnected.
Disconnecting in Millwork does not revoke the credential at the provider.
Use the provider’s own controls
when you also need to remove that access.
Run a model
Save a model from the refreshed catalog and submit a live task.
Get help
Send the connection id and the error reason, never the key.