> ## 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.

# Connect a provider account

> Save a provider credential securely, test the connection, and refresh the models it can use.

Connect a provider in four parts:

1. choose a provider;
2. enter the credential in a secure browser step;
3. test the connection; and
4. refresh the models it can use.

The provider credential never belongs in a Millwork API request.

## Before you begin

```bash theme={null}
export MILLWORK_API_URL="https://api.getmillwork.dev/v1"
export MILLWORK_API_KEY="<organization API key>"
```

List providers first:

```bash theme={null}
curl --fail-with-body \
  --header "Authorization: Bearer $MILLWORK_API_KEY" \
  "$MILLWORK_API_URL/model-source-profiles" | tee providers.json
```

Only a returned `source_id` and `auth_scheme` can be used.

## 1. Start secure setup

This example uses OpenAI. Replace both values with a pair returned by the
provider-profile endpoint.

```bash theme={null}
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer $MILLWORK_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "source_id": "openai_direct",
    "auth_scheme": "api_key"
  }' \
  "$MILLWORK_API_URL/source-credential-handoffs" | tee handoff.json

SETUP_ID="$(jq -r '.handoff_intent_id' handoff.json)"
jq -r '.continue_url' handoff.json
```

Open the one-time `continue_url` in a browser and complete the provider step.
Do not paste that URL into a support message. The poll response does not return
the continuation URL again.

## 2. Finish the browser step

```bash theme={null}
curl --fail-with-body \
  --header "Authorization: Bearer $MILLWORK_API_KEY" \
  "$MILLWORK_API_URL/source-credential-handoffs/$SETUP_ID" \
  | tee handoff-status.json
```

Continue only when `state` is `completed`. This secure setup is short-lived,
bound to one organization and provider, and can be used once.

If it expires or fails, start a new setup. Do not reuse its URL.

## 3. Create and test the connection

```bash theme={null}
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer $MILLWORK_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{
    \"display_name\": \"OpenAI account\",
    \"source_id\": \"openai_direct\",
    \"auth_scheme\": \"api_key\",
    \"handoff_intent_id\": \"$SETUP_ID\",
    \"source_scope\": {
      \"kind\": \"account\",
      \"account_ref\": \"primary\"
    }
  }" \
  "$MILLWORK_API_URL/source-connections" | tee connection.json

CONNECTION_ID="$(jq -r '.connection_id' connection.json)"

curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer $MILLWORK_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{}' \
  "$MILLWORK_API_URL/source-connections/$CONNECTION_ID/test" \
  | tee connection-test.json
```

The scope must describe the provider account, project, or region you intend to
use. Follow the API reference for the chosen provider.

This request body is for OpenAI. If you choose another provider, use the
account, project, or region fields shown for that provider in the API reference.

**Expected result:** the test reports that the connection is ready. If it does
not, use the test error table below before refreshing models.

## 4. Refresh models and read the catalog

```bash theme={null}
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer $MILLWORK_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{}' \
  "$MILLWORK_API_URL/source-connections/$CONNECTION_ID/deployments/sync"

curl --fail-with-body \
  --header "Authorization: Bearer $MILLWORK_API_KEY" \
  "$MILLWORK_API_URL/model-catalog"
```

The catalog includes only models that both Millwork and the tested connection
can use.

**Expected result:** supported models from this connection appear in the model
catalog. An empty result means the tested account has no currently supported
model route.

## Provider setup fields

| Source ID              | Authentication                                          | Scope                                            |
| ---------------------- | ------------------------------------------------------- | ------------------------------------------------ |
| `openai_direct`        | API key                                                 | Account                                          |
| `anthropic_direct`     | API key                                                 | Account field containing the workspace reference |
| `gemini_developer_api` | API key                                                 | Account                                          |
| `deepseek_direct`      | API key                                                 | Account                                          |
| `moonshot_direct`      | API key                                                 | Account                                          |
| `fireworks`            | API key                                                 | Account                                          |
| `xai_direct`           | API key                                                 | Account                                          |
| `openrouter`           | API key                                                 | Account                                          |
| `aws_bedrock`          | Short-term Bedrock API key or temporary AWS credentials | Region and inference profile                     |

For Bedrock, the region must match the inference-profile ARN. The AWS principal
must be allowed to read and invoke through that profile.

## If the connection test fails

| Test error        | What to do                                                                   |
| ----------------- | ---------------------------------------------------------------------------- |
| `authentication`  | Complete a new secure setup and rotate the connection.                       |
| `permission`      | Allow the provider account to read and invoke the selected model or profile. |
| `model_not_found` | Check the account, project, region, and model availability.                  |
| `rate_limited`    | Wait, then test again.                                                       |
| `capacity`        | Retry later or choose another catalog model.                                 |
| `source_5xx`      | The provider failed. Retry later.                                            |

## Rotate or revoke

Rotation tests the replacement credential before changing the connection. A
failed replacement leaves the working credential in place.

Revoking a Millwork connection immediately stops later work from using it. It
does not revoke the credential in the provider account. Remove or rotate that
credential in the provider’s own controls when needed.

<CardGroup cols={2}>
  <Card title="Run a model" icon="play" href="/get-started/builder">
    Use a model returned by the refreshed catalog.
  </Card>

  <Card title="Get help" icon="life-buoy" href="/help/provider-connections">
    Send safe context without sending the credential.
  </Card>
</CardGroup>
