Provider Connections and Roles
On this page
Managed services. Connections and roles are how the managed-services build authenticates every call to an AI or speech provider. The open-source build keeps reading provider keys from the agent’s secrets; see Manage secrets.
Every provider key an agent or an organization uses lives in a named connection, and every task that calls a provider uses the connection bound to one of its roles. Whoever configures an agent picks a connection by name and never sees its key. A role with no usable connection is refused and reported; it is never served by another key, so withdrawing a credential stops the agents that used it instead of moving their spend onto a contract nobody chose.
Connections
A connection holds one provider credential under a name of your choosing, encrypted at rest. It has one of three owners:
- The organization. An Owner or Admin creates it on Settings → Organization → Connections (
/organizations/{org}/settings/organization/providers) and lends it to workspaces. Only agents in a workspace it is lent to can bind it. - One workspace. A workspace’s own connection is created on the workspace’s Settings → Available connections page and only that workspace’s agents can bind it. No other workspace can use it, and the organization cannot lend it elsewhere.
- One agent. A private connection is created from the agent’s Providers section and only that agent can bind it. It replaces the provider keys an agent used to keep as secrets.
An organization set to Organization credentials only refuses workspace and private connections, when they are created and at every call (see below).
The organization’s Connections page lists its connections with what each provider can do and the workspaces each is lent to. Add connection opens the provider catalog, speech services included. Each connection opens in a sheet that shows which fields are set (never their values), the lending switch for each workspace, rename, rotate and delete. The same page holds the managed-only switch. The old …/settings/organization/provider-credentials address redirects there.
A workspace’s Available connections page (/organizations/{org}/workspaces/{ws}/settings/connections, under workspace.assignment:manage) lists the connections its agents can choose: the workspace’s own and those the organization lends it. New workspace connection creates one of the workspace’s own, which is renamed, rotated and deleted from the same page. From the organization… lends one of the organization’s connections to the workspace (Make available), and Remove from this workspace withdraws it; an organization connection is otherwise read-only here. A workspace connection is refused with 400 for a provider the organization is not admitted to; a provider the organization holds and the workspace does not yet is turned on in the workspace when its first connection is created. Names are unique per workspace.
Each provider accepts its own fields, and the API refuses a credential that could not authenticate before storing it:
| Provider | Fields |
|---|---|
| OpenAI, Anthropic, Nebius, TensorX, Scaleway, Regolo.ai, ElevenLabs, Deepgram, Typesafe | api_key |
| Bedrock | region, plus either api_key (a Bedrock API key) or access_key_id and secret_access_key. A region alone is accepted only in an organization granted the deployment’s AWS identity. |
Three gestures act on a connection, and they are not interchangeable:
- Rotate replaces the whole credential under the same name. It is the answer to a leaked key: every role bound to it keeps working.
- Withdraw the lending from a workspace, on the organization’s Connections page or with Remove from this workspace on the workspace’s Available connections page. Agents there that bound it stop at their next call with
connection_unavailable, and lending it again restores them. - Delete is refused with
409while any role, of an agent or of the organization, is still bound to the connection. Bind those roles elsewhere first.
Rotate and delete apply to every owner: the organization’s on its Connections page, a workspace’s on its Available connections page, an agent’s in its Providers section.
The organization’s connections are read and written with GET, POST, PATCH and DELETE on /api/organizations/{orgSlug}/provider-connections, with org.secret:read and org.secret:write. Lending is PUT /api/organizations/{orgSlug}/workspaces/{workspaceSlug}/provider-connections with { "connectionId": "<id>", "assigned": true } (or false to withdraw), under workspace.assignment:manage; the workspace’s Available connections page offers the same switch. A workspace’s own connections are created, renamed or rotated, and deleted with POST, PATCH and DELETE on /api/organizations/{orgSlug}/workspaces/{workspaceSlug}/provider-connections[/{id}], with the same body as the organization’s and under the same permission; creation answers 403 in a managed-only organization and 409 for a name the workspace already uses.
What each provider can do
The provider catalog declares the capabilities of each provider, and a role accepts only a connection whose provider has the capability it needs. A picker therefore never offers an Anthropic connection for an embedder, and the API refuses that binding.
| Provider | Capabilities | Needs admission |
|---|---|---|
| OpenAI | chat, embeddings, speech to text, rewriting, decisions | yes |
| Anthropic | chat, rewriting | yes |
| Bedrock | chat, embeddings, speech to text (Amazon Transcribe) | yes |
| Nebius, Scaleway | chat | yes |
| TensorX, Regolo.ai | chat, embeddings | yes |
| ElevenLabs | speech to text, text to speech | no |
| Deepgram | speech to text | no |
| Typesafe | decisions (Jev) | no |
The providers that need admission are the chat and embedding providers that a platform admin admits to the organization and an organization admin assigns to the workspace; see AI Gateway. The speech services are outside that catalog, so no admission applies to them; lending and the managed-only rule still do.
Roles
A role is one use of a provider credential. Each owner binds each role it uses to exactly one connection.
| Role | Owner | What it authenticates | Provider |
|---|---|---|---|
chat | agent | The conversation: the agent’s turns and the model calls made on its behalf | The provider chosen in the agent’s Model section |
embedding | agent | The agent’s memories, its own documents and its search queries. In use only with memory or knowledge on | The agent’s embedder |
stt | agent | Voice notes received on messaging channels. In use unless transcription is disabled | OpenAI, Bedrock (Amazon Transcribe) or Deepgram, by the agent’s transcription setting |
voice_tts | agent | The voice the caller hears on a phone call | ElevenLabs |
voice_stt | agent | The transcription of the caller | ElevenLabs, or Deepgram when the channel runs on Deepgram Flux alone |
voice_turn_detection | agent | Deciding when the caller has finished, beside ElevenLabs transcription. In use with the default recognition option | Deepgram |
voice_text_model | agent | The voice layer’s own sentences: wait lines and replies joined to an interruption | The provider of the voice text model the channel selects: OpenAI, Anthropic or Bedrock (a connection in eu-central-1 or eu-west-1) |
voice_decisions | agent | The classifier behind the call’s judges. Optional: without it the judges are skipped | Typesafe or OpenAI, by the judges’ classifier setting |
library_embedding | organization | The organization’s and its workspaces’ shared knowledge libraries | The library embedder’s provider |
A role bound to a connection for another provider than the one the agent chose is refused with connection_mismatch. That is what happens right after a provider change in the Model section: the old binding stays, the Model section warns before the save, and the role stops until a connection for the new provider is bound. A plugin can register further roles at boot; the panel shows such a role by its id.
Binding an agent’s roles
Two sections of the agent’s Configuration group share the work. The Providers section lists every connection the agent can reach, with its provider, what it can do, who provides it (this agent, the workspace or the organization) and the tasks that use it. Add connection creates a private one where the organization allows it, and a private connection opens in a sheet with rename, rotate and delete; the workspace’s and the organization’s are shown read-only. In a managed-only organization the private connections made before the switch are still listed, marked as not usable, with delete as the only action.
The Model section binds the roles: one row per task the agent calls a provider for (the conversation, the embedder, voice-note transcription, and the voice tasks the agent uses), with the provider, the model, the connection and whether it can run, by the same resolution the real call makes. A row opens the task in a side panel where all of it is chosen and saved together. Each connection picker offers the workspace’s own connections, those lent to the workspace and the agent’s private connections, narrowed to those that can serve the role and, where the agent chose a provider for it, to that provider, so nothing it offers is refused on save.
An agent created after the upgrade, from the panel, the API or an import, has no bindings. Its turns are refused with connection_required until chat is bound, and so are its other roles in use.
The same through the API:
# Roles, readiness and the connections each may use
curl -s https://<engine>/api/instances/my-agent/provider-roles \
-H "X-Polyant-Key: $POLYANT_KEY" | jq '.roles[] | {role, inUse, connectionId, readiness}'
# Bind the conversation to a connection
curl -s -X PUT https://<engine>/api/instances/my-agent/provider-roles/chat \
-H "X-Polyant-Key: $POLYANT_KEY" -H "Content-Type: application/json" \
-d '{ "connectionId": "<connection id>" }'GET /api/instances/{slug}/provider-roles returns each role with capability, requiredProvider, inUse, connectionId, connection, readiness (ready, problem, message) and options, plus the agent’s private connections, whether it may create any (privateConnectionsAllowed), and the credential fields each reachable provider accepts.
connectionis the bound connection as{ id, name, provider, private }while the agent can still reach it, even when it no longer fits the role (a connection for the provider the agent had before), so the reader can name what is bound and why it is refused. It isnullwhen nothing is bound or the connection is out of reach: deleted, withdrawn from the workspace, or private in a managed-only organization.optionsholds the connections the agent may use that have the role’s capability and, whenrequiredProvideris set, are for that provider: the same test the binding applies. A private connection appears in no option list in a managed-only organization.privateConnectionslists every private connection of the agent, whatever the organization’s policy, each withusable, which isfalsein a managed-only organization.PUT …/provider-roles/{role}takes{ "connectionId": "<id>" }, ornullto clear the binding. It answers400for a connection the agent may not use, one whose provider cannot serve the role, or one for another provider than the agent chose, and404for a role an agent cannot bind.
GET /api/instances/{slug}/provider-connections, under agent:read, lists the agent’s private connections alone as { "connections": [{ "id", "name", "provider", "configuredFields", "ownerInstanceId", "usable" }] }: names and the fields that are set, never a value, with usable false in a managed-only organization. A private connection is created with POST …/provider-connections and a body of name, provider and credentials, renamed or rotated with PATCH …/provider-connections/{id}, and deleted with DELETE …/provider-connections/{id}. Creation is refused with 403 in a managed-only organization and with 400 for a provider the agent’s workspace does not admit. Deletion is allowed under managed-only too, so a connection made before the switch can be removed; it answers 409 while one of the agent’s roles is bound to the connection and 404 when the agent has no such connection.
Binding the organization’s roles
The organization’s only role today is library_embedding. It is bound in the Embedder card of Settings → Organization → Knowledge (see the library embedder), or with GET /api/organizations/{orgSlug}/providers/roles and PUT /api/organizations/{orgSlug}/providers/roles/library_embedding, under org.secret:read and org.secret:write. A workspace’s library, and the shared half of a search by an agent in that workspace, can use the connection only where it is lent to that workspace: elsewhere uploads are refused with that reason and the shared half of the search is skipped and reported on the agent’s Status section.
When a role cannot run
The engine resolves each role to its bound connection or to a refusal, in this order:
| Refusal | What happened |
|---|---|
connection_required | No connection is bound to the role. |
connection_unavailable | The bound connection was deleted, or is neither lent to nor owned by the workspace the call happens in. |
private_connection_not_allowed | The role is bound to a private or a workspace connection, and the organization accepts only its own connections. |
connection_mismatch | The connection’s provider cannot serve the role, or is not the provider chosen for it. |
ambient_aws_not_granted | A Bedrock connection holds a region and no key, and the organization has not been granted the deployment’s AWS identity. |
connection_incomplete | Speech-to-text on Amazon Transcribe is bound to a Bedrock connection without an access-key pair and a region, or another speech-to-text connection holds no key. |
Provider admission is checked as well: provider_not_admitted and model_not_admitted are described in AI Gateway. Every refusal is shown with a sentence naming what to fix in the agent’s Providers section, on its Status section, and in the memory banner when the embedder is the role refused.
Organization credentials only
The Organization credentials only switch on the organization’s Connections page (PUT /api/organizations/{orgSlug}/providers/managed-only with { "managedOnly": true }, under org.secret:write) makes the organization accept only the connections it prepares. Workspaces can no longer create their own connections and agents can no longer create private ones, and every role bound to an existing workspace or private connection stops with private_connection_not_allowed until someone binds one of the organization’s connections in its place. The existing workspace and private connections stay listed as not usable and can still be deleted, which is how their keys leave the database. The rule binds every role, chat, embeddings, transcription and the voice alike. Both states of the switch are written to the management audit trail.
Bedrock and the deployment’s AWS identity
A Bedrock connection that holds a region and no key would sign its calls with the AWS identity of the deployment itself (its instance or task role), and the operator’s AWS account would pay for them. That needs a grant per organization from a platform admin: Admin Console → Organizations → the organization → Access → Bedrock with the deployment’s AWS identity, or GET, PUT and DELETE on /api/platform/organizations/{targetOrgSlug}/ambient-aws. It is a platform-admin check, not a permission any organization role can hold, so no organization can grant it to itself.
- Without the grant a Bedrock connection needs a Bedrock API key or an access-key pair, both when it is written and at every call. Revoking the grant stops the agents relying on it with
ambient_aws_not_granted; the replica that handled the change applies it at once, and other replicas within 30 seconds. - The grant covers every role: the conversation, the agent’s embedder, the voice text model and the library embedder, whoever owns the connection.
- Amazon Transcribe never uses the deployment’s identity. Speech-to-text on Bedrock always needs a connection with an access-key pair and a region.
Granting and revoking are audited as ambient_aws.org_grant and ambient_aws.org_revoke. The 1.2.0 upgrade granted it to the organizations whose Bedrock credential was a region alone, with one ambient_aws.org_grant row each; see Upgrading.
Provider keys left in the secrets
The upgrade copies each provider key it finds in the secrets into a connection and leaves the original where it was, so a rollback still finds it. Nothing reads those copies any more. These keys are now held only by connections:
openai_api_key, anthropic_api_key, nebius_api_key, tensorx_api_key,
scaleway_api_key, regolo_api_key, bedrock_api_key,
aws_provider_access_key_id, aws_provider_secret_access_key, aws_provider_region,
deepgram_api_key, elevenlabs_api_key, typesafe_api_key- No tool, hook, plugin or dev-mode tool receives them, even one that declares them. A tool that requires one is treated as missing it. A tool’s
ctx.apiKeyscarries the keys of the agent’s chat connection only. - The secret routes refuse to write them.
PUT /api/instances/{slug}/secretsandPUT /api/organizations/{orgSlug}/secretsanswer400for the whole batch, nothing written, with a message pointing to the connection routes. The listings stop offering these keys; a stored copy is still listed and can be deleted. - Clean up once the upgrade is settled. The copies have no page in the managed-services panel: delete an agent’s with
DELETE /api/instances/{slug}/secrets/{key}and an organization’s withDELETE /api/organizations/{orgSlug}/secrets/{key}.
An agent export carries no credential and no binding, because a connection belongs to the organization that prepared it. An import answers a provider_role_required warning for each role the agent uses with nothing bound, naming the role in a role field; see Export and import an instance.
Permissions and audit
| Route | Permission |
|---|---|
GET /api/instances/{slug}/provider-roles, GET /api/instances/{slug}/provider-connections | agent:read |
PUT /api/instances/{slug}/provider-roles/{role} | agent:write |
POST, PATCH, DELETE /api/instances/{slug}/provider-connections[/{id}] | agent.secret:write |
GET /api/organizations/{orgSlug}/provider-connections, GET …/providers/roles | org.secret:read |
POST, PATCH, DELETE …/provider-connections[/{id}], PUT …/providers/roles/{role}, PUT …/providers/managed-only | org.secret:write |
PUT, POST, PATCH, DELETE /api/organizations/{orgSlug}/workspaces/{workspaceSlug}/provider-connections[/{id}] | workspace.assignment:manage |
GET, PUT, DELETE /api/platform/organizations/{targetOrgSlug}/ambient-aws | Platform admin |
Binding a role is recorded in the management audit trail as provider_role.bind with the connection id. A connection’s creation, update and deletion are provider_connection.create, provider_connection.update and provider_connection.delete, marked private: true for an agent’s own and owner: "workspace" for a workspace’s. A row names the connection and, on creation, its provider and the fields it holds; it never carries a value.
See also
- AI Gateway - provider admission and how a call picks its model.
- Organizations - who decides what an organization may run.
- Channels → Voice - which voice roles a call uses.
- Upgrading to 1.2.0 - how existing keys become connections.