# Add an AI provider

> Add an AI provider to a workspace, with its API key. provider is a frontier lab (anthropic, openai, gemini, xai, mistral, deepseek), a model platform (azure_openai, openrouter, groq, together, fireworks, cerebras) or a self-hosted endpoint (anthropic_endpoint for one that speaks Anthropic's Messages API, openai_endpoint for one that speaks OpenAI's Chat Completions API). config: base_url is the address of an endpoint or an Azure OpenAI resource, over https; auth_header (x-api-key or authorization) is how an endpoint takes the key; model names the model the team uses, or the Azure deployment. secret is the key, checked as it is saved, sealed and never returned. g1t hosts no model and bills nothing for it.

<div class="g1t-endpoint"><span class="g1t-method" data-method="post">POST</span><code>/workspaces/{workspace}/ai/providers</code></div>

Owners only.

The key is checked as it is saved: one the provider refuses is refused with `422`, saying why. It is sealed and never returned; only its last four characters come back, as `secret_hint`.

- **Authentication:** Required. Send an [access token](/reference/api/#authentication) as `Authorization: Bearer`.
- **MCP tool:** [`ai`](/reference/mcp/#ai) with `action` `add_provider`, and the same inputs
- **Scope:** An access token needs [`workspace:admin`](/guides/authentication/#scopes).

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `workspace` | string | Yes | The workspace's slug, e.g. "flagon-io". |

## Body parameters

Send a JSON object. Names are `snake_case`, as in responses; the `camelCase` spelling is accepted too.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `provider` | string | Yes | Frontier labs: anthropic, openai, gemini, xai, mistral, deepseek. Model platforms: azure_openai, openrouter, groq, together, fireworks, cerebras. Self-hosted endpoints: anthropic_endpoint, openai_endpoint. One of `anthropic`, `openai`, `gemini`, `xai`, `mistral`, `deepseek`, `azure_openai`, `openrouter`, `groq`, `together`, `fireworks`, `cerebras`, `anthropic_endpoint`, `openai_endpoint`. |
| `name` | string | No | What to call it. The provider's name if left out. |
| `config` | object | No | Settings, where the provider needs them. |
| `config.base_url` | string | No | The address of a self-hosted endpoint or an Azure OpenAI resource, over https. An Anthropic-compatible one without /v1; an OpenAI-compatible one up to and including the version. |
| `config.auth_header` | string | No | For an endpoint: send the key as x-api-key, or as authorization: Bearer. One of `x-api-key`, `authorization`. |
| `config.model` | string | No | The model the team uses on it; for Azure OpenAI, the deployment. |
| `config.console_workspace` | string | No | For anthropic: the Console workspace the key belongs to (wrkspc_â€¦), or any Console address in it, so links to the sessions it starts open there. Without it, the account's Default workspace. |
| `secret` | string | No | Its API key. Checked as it is saved; write-only: sealed, never returned. Optional for an endpoint that needs none. |

## Example request

```sh
curl -X POST https://api.g1t.sh/workspaces/flagon-io/ai/providers \
  -H "Authorization: Bearer $G1T_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "openai_endpoint",
    "name": "vLLM",
    "config": {
      "base_url": "https://llm.example.com/v1",
      "auth_header": "authorization",
      "model": "qwen3-coder"
    },
    "secret": "sk-…"
  }'
```

## Example response

A successful request answers `200` with:

```json
{
  "id": "ai_01kpx4n8r3g9s0v5w7x1z2a3bf",
  "workspace": "flagon-io",
  "provider": "openai_endpoint",
  "group": "self_hosted",
  "name": "vLLM",
  "config": {
    "base_url": "https://llm.example.com/v1",
    "auth_header": "authorization",
    "model": "qwen3-coder"
  },
  "secret_hint": "…k9Lm",
  "created_by": "syntaqx",
  "created_at": "2026-10-14T10:03:51.902Z",
  "last_used_at": null,
  "last_error": null,
  "models": [
    "qwen3-coder"
  ]
}
```

## Errors

A failed request answers with one of these statuses and a body like `{"error": {"code": "not_found", "message": "Repository not found."}}`. See [errors](/reference/api/#errors).

| Status | Code | When |
| --- | --- | --- |
| 401 | `unauthenticated` | A token is required, or the one sent is not valid. |
| 403 | `forbidden` | The token is valid but not allowed to do this, such as a member-only change, or a token without the scope it needs. |
| 404 | `not_found` | It does not exist, or you cannot see it. |
| 409 | `conflict` | The request conflicts with the current state. |
| 422 | `invalid` | The input is not valid. `message` says which field and why. |
