Skip to main content
Goal: Connect your provider account so Millwork can run its models and your provider bills you for model usage. You are done when: the CLI returns a live model answer and its matching receipt through the provider account you chose. For connection-only API setup, finish when the connection test passes and its models appear in your catalog. A provider connection is the saved link between your Millwork organization and a provider account. Your application uses its connection ID instead of sending a provider credential with each request. The provider bills your organization for model usage. Millwork charges a platform fee when it accepts a live run. Read Model access and billing.

Connect from your terminal

With the CLI installed and your Millwork API key configured, list the providers and connections:
Expected result: “Available providers for new setup” lists source IDs and setup methods. “Existing connections and saved models” lists the connections you already saved, their test state and their models. In JSON output these are 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 uses openai_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 curl and jq.
These examples reuse the key from Configure your API key. 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:
Expected result: one line per available provider with its 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 openai_direct with api_key from the list above. For OpenRouter, follow CLI setup; its browser approval is different from entering a key.
Expected result: 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

Expected result: 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

Expected result: 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:
Save 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

Expected result: the refresh returns 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; use GET /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, use millwork 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:
The command shows the affected saved models before asking you to confirm. Declining changes nothing. On success, 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 with POST /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:
Expected result: the 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.