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