# Custom providers

Any platform with a custom-provider or bring-your-own-model form can point at DirectInference. What to enter in each field, what to leave blank, and how to confirm it's live.

## Pick the dialect the form speaks

A provider form is really asking one question: what request shape will the tool send? Most forms labeled "custom provider" or "OpenAI-compatible" speak the OpenAI shape — pick that unless the tool explicitly offers the Anthropic or Gemini shape. Whichever dialect arrives, DirectInference serves it; you are choosing a wire format, not a model.

| The form speaks | Base URL | Credential |
| --- | --- | --- |
| OpenAI-compatible<br />"custom provider", "OpenAI-compatible", "bring your own model" | `https://api.directinference.com/di/v1` | `Authorization: Bearer llm_live_…` |
| Anthropic Messages<br />"Anthropic provider", "Messages API" | `https://api.directinference.com/di`<br />the client appends `/v1/messages` | `x-api-key: llm_live_…`<br />`anthropic-version: 2023-06-01` |
| Gemini<br />"Gemini provider", "Google AI" | `https://api.directinference.com/di`<br />the client appends `/v1beta/models/…` itself; if the form's base URL must already include `/v1beta`, enter `…/di/v1beta` | `x-goog-api-key: llm_live_…`<br />`?key=llm_live_…`<br />`Authorization: Bearer llm_live_…` |

:::note[Configuring code or a CLI instead?]
This page is for settings screens. Swapping an SDK in application code is covered in [Migrate to DirectInference](https://docs.directinference.com/migrate/); pointing CLIs and coding agents at DI through environment variables is covered in [AI coding agents](https://docs.directinference.com/agents/). The per-surface credential details live in [Authentication](https://docs.directinference.com/authentication/).
:::

## Enter the base URL and key

The whole configuration is two values: a base URL and a key you issue on the [API Keys](https://app.directinference.com/api-keys) page. The only quirk is how much of the path the form builds itself — the base URL plus whatever the form appends must come out to `https://api.directinference.com/di/v1/chat/completions`. Pick the row that matches your form:

| The form appends | Enter |
| --- | --- |
| `/chat/completions`<br />the most common convention | `https://api.directinference.com/di/v1` |
| `/v1/chat/completions` | `https://api.directinference.com/di` |
| Nothing — it wants the full endpoint URL | `https://api.directinference.com/di/v1/chat/completions` |

The field's placeholder or help text usually says which it is. If you can't tell, start with `…/di/v1` and move one path segment over if the first call returns a not-found error — at that point the key is never the problem. You can prove the pair from a terminal before fighting the form:

```bash
# Prove the base URL and key work before pasting them into a form
curl https://api.directinference.com/di/v1/chat/completions \
  -H "Authorization: Bearer llm_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "model": "di-fusion", "messages": [{ "role": "user", "content": "ping" }] }'
```

:::caution[A vendor-branded key error means the base URL, not the key]
Built-in key tests usually validate against the tool's default vendor API until the custom base URL is set *and saved*. If the test fails with another vendor's "incorrect API key" message, the base URL hasn't been applied yet — save the form first, then run the test again. The curl above is ground truth that the key itself is fine.
:::

## Answer the rest of the form

Everything else a provider form asks has a default answer. Fields that belong to other vendors' account schemes stay empty:

| Field | What to enter |
| --- | --- |
| Organization ID | Leave blank — it belongs to another vendor's account scheme. |
| Project ID | Leave blank. |
| Deployment name | Leave blank. |
| API version | Leave blank — the version is already in the path. If an Anthropic-dialect form insists on a value, enter `2023-06-01`. |
| Auth type / auth source / token prefix | Keep the default. Standard Bearer (or the dialect's native header) is exactly what DirectInference expects. |

Capability checkboxes tell the tool which features to expose, not what the endpoint must do — answer generously:

| The form asks about | Answer | Notes |
| --- | --- | --- |
| Streaming | On | Server-sent events on every dialect; the OpenAI dialect terminates with a `data: [DONE]` sentinel. |
| Tool / function calling | On | Supported on all three dialects. |
| Vision / image input | On | An image in the request makes it a `vision` request, served accordingly. |
| PDF / document input | On | Via Anthropic-dialect document blocks; served as the `document` request type. |
| JSON mode / structured output | On | OpenAI `response_format` with `json_schema`; Anthropic `output_config.format` with type `json_schema`. |
| Prompt caching | On | Supported — see [Prompt caching](https://docs.directinference.com/caching/) for the per-dialect details. |

:::caution[Turn the tool / function-calling and thinking toggles on by hand]
Many agent tools decide whether a model supports tools, function calling, or a thinking channel by matching its _name_ against a built-in list — and `di-fusion` is not on anyone's list. If those capability switches default off, the tool silently falls back to brittle text-parsing instead of real tool calls. Whenever a bring-your-own-model form exposes "function calling / tools" or "show thinking / reasoning" toggles, enable them: DirectInference serves all of them on every dialect. Capability is a property of the request shape here, never of the model id.
:::

If the form has a custom-headers field, two optional headers are worth setting: `X-Title` with a name for the tool gives it its own line in per-application usage ([Usage & analytics](https://docs.directinference.com/usage/)), and `X-DI-Effort` (`fast`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` — default `auto`) biases cost against quality for everything the tool sends ([Effort](https://docs.directinference.com/effort/)).

:::note[Unknown parameters are stripped, not rejected]
If the tool injects vendor-specific request parameters of its own, DirectInference silently drops what it doesn't recognize and serves the request — an extra field never turns into a `400`. A few recognized-but-unsupported vendor features (such as Gemini-dialect server-side tools) return a clear error instead.
:::

## Register a model

Forms come in two kinds. Tools that auto-discover models list three entries — `di-fusion` (select it), plus `di-saver` and `di-max`, the same model with effort pinned for tools with fast/smart model slots. Tools that want a typed-in model name accept any string: use `di-fusion`, or keep the ids your team already has wired into saved prompts and pipelines. Every id resolves, nothing ever returns a not-found error, and the id you send is echoed back unchanged in the response.

```bash
curl https://api.directinference.com/di/v1/models \
  -H "Authorization: Bearer llm_live_..."

# { "object": "list",
#   "data": [ { "id": "di-fusion", "root": "di-fusion", ... },
#             { "id": "di-saver",  "root": "di-fusion", ... },
#             { "id": "di-max",    "root": "di-fusion", ... } ] }
```

:::tip[Model ids are labels, not switches]
The id is read as intent, never as a model selection — there is no model to choose, and request handling is automatic. Treat the field as the label the tool will show in its own charts and dropdowns, and pick whatever keeps your existing configs unchanged.
:::

## Worked example: Open WebUI & LibreChat

Two common self-hosted chat UIs, end to end. Both speak the OpenAI dialect, so the base URL is `https://api.directinference.com/di/v1` and the credential is a plain `llm_live_…` key — they auto-discover `di-fusion`, `di-saver`, and `di-max`.

In **Admin Settings → Connections → OpenAI → Manage**, click **➕ Add New Connection**:

- **URL** — `https://api.directinference.com/di/v1`
- **API Key** — `llm_live_...`

Save, then pick `di-fusion` from the model selector. Models are listed automatically from `/models`; no manual entry needed. Installing Open WebUI from scratch (Docker or pip) is covered step by step in the dedicated [Open WebUI](https://docs.directinference.com/open-webui/) guide.

Add a custom endpoint in `librechat.yaml`:

```yaml
endpoints:
  custom:
    - name: "DirectInference"
      apiKey: "${DIRECTINFERENCE_API_KEY}"
      baseURL: "https://api.directinference.com/di/v1"
      models:
        default: ["di-fusion", "di-saver", "di-max"]
        fetch: true
      titleConvo: true
      titleModel: "di-fusion"
```

Set `DIRECTINFERENCE_API_KEY` in the environment and restart. `fetch: true` populates the model list from `/models`. For the full walkthrough — the Docker mount, title generation, multi-tenant user-provided keys, and troubleshooting — see [LibreChat](https://docs.directinference.com/librechat/).

## Confirm it's live

Three checks, strongest first:

1. **The model echo.** The response's `model` field is exactly the id you configured — nothing rewrites it (the Gemini dialect echoes it as `modelVersion`).
2. **The header.** The response carries `X-DI-Request-Type` (`pro`, `code`, `vision`, `document`, `long`, `json`, `reason`, or `flash`). It is the only customer-readable response header, and its presence proves the request was served by DirectInference — see [Response headers](https://docs.directinference.com/headers/) and [Request types](https://docs.directinference.com/request-types/).
3. **The dashboard.** The request shows up under [Traces](https://app.directinference.com/traces) and [Usage](https://docs.directinference.com/usage/); with `X-Title` set, the tool becomes its own line in [Applications](https://app.directinference.com/applications).

```bash
# -D - dumps the response headers; the body is discarded
curl -s -o /dev/null -D - https://api.directinference.com/di/v1/chat/completions \
  -H "Authorization: Bearer llm_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "model": "di-fusion", "messages": [{ "role": "user", "content": "ping" }] }' \
  | grep -i x-di-request-type

# x-di-request-type: pro
```

## If something looks wrong

| Symptom | What's happening — and the fix |
| --- | --- |
| The key test fails with another vendor's error | The base URL hasn't been applied — the test ran against the tool's default vendor. Save the base URL, then re-test; confirm the key with the curl above. |
| The first request returns a 404 | The form and the base URL are one path segment apart. Move between `…/di`, `…/di/v1`, and the full endpoint URL per the table above. |
| The model dropdown shows three entries — `di-fusion`, `di-saver`, `di-max` | Expected — that is the endpoint's whole catalog: one model, with `di-saver`/`di-max` pinning effort. Select `di-fusion` unless you want the pin. |
| The tool's per-model cost estimates look wrong | The tool prices by the model label it sees, which DirectInference only echoes. Actual spend lives in [Usage & analytics](https://docs.directinference.com/usage/) and [Spend & limits](https://docs.directinference.com/spend/). |
| Responses arrive but nothing shows in Traces | The tool is still calling its previous provider — settings unsaved, or overridden per-model. Check a response from inside the tool for `X-DI-Request-Type`; if it is absent, re-save the provider settings. |

Error envelope shapes and rate limits live in [Errors & limits](https://docs.directinference.com/errors/).