Provider

Choosing which AI service answers, why the API key lives in the environment file instead of a form, and what the connection test actually proves.

6 min readUpdated 6 August 2026admin, provider, api-key, env

/admin/ai/support/provider. Nothing else in the console has any effect until this screen is green: with no provider connected the assistant cannot answer, and the model pickers on Agents and Settings have nothing to list.

The three options

Option You provide Billed by
Managed connection Nothing — included with your licence Us, against your plan
Your own key An API key from the AI vendor The vendor, directly to you
Any compatible endpoint A base URL and a key Whoever runs it

The third speaks the widely-supported chat-completions shape, so a self-hosted model or a third-party router works with no code change.

The comparison block above the provider list compares what you get, not price per answer. That is deliberate: a per-answer figure for the managed connection and for a raw key are computed from the same rate card and read as an argument against the product on the screen where you choose. The differences that decide the question are the ones stated there in prose — whose documentation you are answering from and whether it stays current, where the tuning lives, and where the ceiling is enforced. The gateway's commercial terms on that block — the multiplier, the per-answer floor, the trial credit and the default caps — are served by the endpoint rather than typed into the screen, so they cannot go stale against the rate card beside them.

Choosing the active provider is Super-Admin only, one of twelve keys that are — see Permissions.

The Model tab lists models for the managed connection and for your own key. For a compatible endpoint it lists nothing and the field is inert: the endpoint could be serving anything, so there is no catalogue to enumerate and a select box full of models it may not have is worse than saying where the value comes from.

The value comes from AI_SUPPORT_OPENAI_MODEL in .env. aiSupportModel is ignored on that provider.

Why this screen has no key field

GET /api/settings is unauthenticated. It has to be — the storefront reads branding, currency and feature flags from it before anyone signs in — and it returns every settings row minus a short denylist.

A credential written there would be readable by anyone who loads your public site. So this screen accepts no credential and displays none. It reports only whether a key is present, its first few characters, and what is missing.

The accepted consequence, stated here rather than discovered later: connecting a provider needs shell access and a backend restart. There is no way to do it from the browser, and that is the design rather than an omission.

# The AI vendor's own API
ANTHROPIC_API_KEY=sk-ant-...

# Any compatible endpoint
AI_SUPPORT_OPENAI_BASE_URL=https://your-endpoint.example/v1
AI_SUPPORT_OPENAI_API_KEY=sk-...
AI_SUPPORT_OPENAI_MODEL=the-model-your-endpoint-serves
AI_SUPPORT_OPENAI_INPUT_USD_PER_MTOK=0.60
AI_SUPPORT_OPENAI_OUTPUT_USD_PER_MTOK=2.40

# The managed connection
AI_SUPPORT_GATEWAY_TOKEN=...
AI_SUPPORT_GATEWAY_SECRET=...

The screen lists the keys each provider expects, and marks the ones it cannot find. A local endpoint needs no key, so AI_SUPPORT_OPENAI_API_KEY is only reported as missing when the base URL is not a loopback address.

The two rate-card variables are the ones nobody expects, and they are not optional if you run a spend cap. This adapter reports no cost — it cannot know whether your endpoint is a free local model, a metered API or a flat subscription — and a cap set over calls that record nothing is refused rather than assumed safe. Set both, in USD per million tokens, or set the caps to 0. Half a rate card is treated as none. See Error codes.

The connection test

Test connection makes one real call to the service. It is not a string check and not a ping: it runs the whole path a customer's question takes, and the result is only green if the model actually answered.

Run it after every .env change and after every backend restart. It reports a tick or a cross per step, each with a sentence of detail, and the steps differ by provider:

Provider Steps
Managed connection Gateway credentials → Account → Answering
Your own key API key → Answering
Any compatible endpoint Endpoint → Answering

Only the managed connection has a middle step, and it is the useful one: it reads your plan, balance and remaining spend cap, so an empty gateway wallet is named rather than surfacing later as a generation that will not run. On the other two, a wrong credential and an unreachable host both come back as a failed Answering step, and the detail line carries the upstream message that tells them apart.

Credentials are never echoed. A passing credential step shows the first few characters of the loaded key, or the endpoint URL — enough to confirm which key is loaded, not enough to use it.

The backend reads .env at boot. Editing the file and pressing Test without restarting reports the old state, which reads exactly like a bad key.

It performs a real generation, so it bills — a fraction of a cent on the managed connection, which prices the probe on its cheapest tier. That cost is filed against the same daily and monthly ceilings a customer's answer counts against, whether the probe passed or failed.

The button is refused with a 429 when a ceiling is already reached. There is no point learning the provider works if the budget will not let it answer anybody.

When the service is briefly unavailable

Every provider goes away sometimes: a deploy, a restart, a proxy reloading, a rate limit. The assistant is built to ride out a short one rather than turn it into a failed conversation.

A request is retried, not queued. There is no durable queue that holds a customer's question until the service returns — a queue would be worse, because an answer arriving forty minutes later, after one of your agents has already replied, is not help. Instead the call is retried in place with a short, increasing wait, and the whole attempt is bounded so nobody watches a typing indicator indefinitely.

Only failures a wait can fix are retried. A refused connection, a 502 from a proxy whose upstream is reloading, a maintenance page, a rate limit — those are tried again. An exhausted balance, a rejected credential and a malformed request are not: repeating them spends your customer's patience to arrive at the same answer, and repeating a rejected credential can walk an account into a lockout. If the service asks for a specific wait, that is honoured.

An answer already being generated is not thrown away. Once the request has been accepted, the work is under way and has been priced. If the service becomes unreachable while it runs, the assistant keeps trying to collect the result for considerably longer than it would spend getting the request accepted in the first place — because giving up there discards something you have paid for.

If it stays down, the conversation goes to a person. Past the retry budget the turn is recorded as failed and the ticket is escalated with the reason provider_error — filed as an infrastructure failure, not as a hard question, so it does not distort what you learn about the questions your assistant cannot handle. This is the fallback, and it is a better outcome than silence.

The gateway runs on the same platform as your MashDiv account, so it restarts when that platform is updated. A restart of a few seconds is invisible to your customers; a longer outage shows up as tickets on your desk rather than as unanswered conversations.

Switching provider later

Changing provider does not migrate anything and does not invalidate your knowledge index — the index is built from your own articles and the documentation packs, not from the model. Conversations already answered keep the answers they were given.

What does change is cost per answer and, potentially, tone. If you have tuned the persona against one model, read a handful of drafts after switching before you leave it unsupervised.

What leaves your install

The assistant sends the customer's question and the retrieved passages to the service you connect. Before that happens, every field that could carry a password, an API key, a wallet address or a KYC document is stripped.

Whether the question itself may be shared beyond the answer is a separate switch on Settings — it ships off.