Skip to Content
Polyant is open source under AGPL-3.0 — star us on GitHub.
Admin PanelProvider Connections

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:

ProviderFields
OpenAI, Anthropic, Nebius, TensorX, Scaleway, Regolo.ai, ElevenLabs, Deepgram, Typesafeapi_key
Bedrockregion, 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 409 while 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.

ProviderCapabilitiesNeeds admission
OpenAIchat, embeddings, speech to text, rewriting, decisionsyes
Anthropicchat, rewritingyes
Bedrockchat, embeddings, speech to text (Amazon Transcribe)yes
Nebius, Scalewaychatyes
TensorX, Regolo.aichat, embeddingsyes
ElevenLabsspeech to text, text to speechno
Deepgramspeech to textno
Typesafedecisions (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.

RoleOwnerWhat it authenticatesProvider
chatagentThe conversation: the agent’s turns and the model calls made on its behalfThe provider chosen in the agent’s Model section
embeddingagentThe agent’s memories, its own documents and its search queries. In use only with memory or knowledge onThe agent’s embedder
sttagentVoice notes received on messaging channels. In use unless transcription is disabledOpenAI, Bedrock (Amazon Transcribe) or Deepgram, by the agent’s transcription setting
voice_ttsagentThe voice the caller hears on a phone callElevenLabs
voice_sttagentThe transcription of the callerElevenLabs, or Deepgram when the channel runs on Deepgram Flux alone
voice_turn_detectionagentDeciding when the caller has finished, beside ElevenLabs transcription. In use with the default recognition optionDeepgram
voice_text_modelagentThe voice layer’s own sentences: wait lines and replies joined to an interruptionThe provider of the voice text model the channel selects: OpenAI, Anthropic or Bedrock (a connection in eu-central-1 or eu-west-1)
voice_decisionsagentThe classifier behind the call’s judges. Optional: without it the judges are skippedTypesafe or OpenAI, by the judges’ classifier setting
library_embeddingorganizationThe organization’s and its workspaces’ shared knowledge librariesThe 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.

  • connection is 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 is null when nothing is bound or the connection is out of reach: deleted, withdrawn from the workspace, or private in a managed-only organization.
  • options holds the connections the agent may use that have the role’s capability and, when requiredProvider is set, are for that provider: the same test the binding applies. A private connection appears in no option list in a managed-only organization.
  • privateConnections lists every private connection of the agent, whatever the organization’s policy, each with usable, which is false in a managed-only organization. PUT …/provider-roles/{role} takes { "connectionId": "<id>" }, or null to clear the binding. It answers 400 for a connection the agent may not use, one whose provider cannot serve the role, or one for another provider than the agent chose, and 404 for 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:

RefusalWhat happened
connection_requiredNo connection is bound to the role.
connection_unavailableThe bound connection was deleted, or is neither lent to nor owned by the workspace the call happens in.
private_connection_not_allowedThe role is bound to a private or a workspace connection, and the organization accepts only its own connections.
connection_mismatchThe connection’s provider cannot serve the role, or is not the provider chosen for it.
ambient_aws_not_grantedA Bedrock connection holds a region and no key, and the organization has not been granted the deployment’s AWS identity.
connection_incompleteSpeech-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.apiKeys carries the keys of the agent’s chat connection only.
  • The secret routes refuse to write them. PUT /api/instances/{slug}/secrets and PUT /api/organizations/{orgSlug}/secrets answer 400 for 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 with DELETE /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

RoutePermission
GET /api/instances/{slug}/provider-roles, GET /api/instances/{slug}/provider-connectionsagent: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/rolesorg.secret:read
POST, PATCH, DELETE …/provider-connections[/{id}], PUT …/providers/roles/{role}, PUT …/providers/managed-onlyorg.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-awsPlatform 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

Last updated on