docs/documentation/platform/agent-proxy/proxied-services.mdx
A proxied service tells the agent proxy how to handle traffic to a specific external service. It lives in a folder alongside your secrets, references those secrets by key name, and defines which hosts it applies to and how each secret is placed into the outbound request.
You manage proxied services in the secrets dashboard: open a folder, click the dropdown arrow next to Add Secret, and select Add Proxied Service. They appear in the folder view next to your secrets.
A service then applies one or more secrets in two ways, Header Rewriting and Credential Substitution. Both are independent; use either or both.
A host pattern routes requests to the right service. Each pattern is a host[:port][/path], and multiple patterns can be combined with commas:
api.stripe.com # exact host
*.github.com # wildcard: matches api.github.com, not a.b.github.com
api.stripe.com:443 # specific port
api.stripe.com/v1/* # path prefix
internal.corp.com:3000/api/* # port and path
api.stripe.com, dashboard.stripe.com # multiple patterns, matches either
A few rules to keep in mind:
*. wildcard matches exactly one label: *.github.com matches api.github.com but not a.b.github.com or bare github.com.https://); patterns are hosts, not URLs.When a request could match more than one service, the agent proxy picks the best match:
Header rewriting adds or replaces an HTTP header on the outbound request. The agent does not need to send any credential; if it sends a made-up one, the header is overwritten with the real value. This covers most APIs:
| Auth style | Configuration | Resulting header |
|---|---|---|
| Bearer token | Header name Authorization, prefix Bearer, one secret | Authorization: Bearer <secret> |
| API key header | Header name x-api-key, no prefix, one secret | x-api-key: <secret> |
| Basic auth | One secret as Username, and optionally a second as Password | Authorization: Basic base64(username:password) |
| Custom | Any header name and optional prefix | <name>: <prefix> <secret> |
The password is optional for basic auth. Many APIs pass an API key as the username with an empty password; omitting the password produces Authorization: Basic base64(username:).
A service can rewrite multiple distinct headers (for example, an API key header plus a tenant header), but each header name can only be set by one secret. To build one header value out of several secrets, or use a secret kept elsewhere, see reusing secrets from other folders and environments.
With credential substitution, the agent is handed a dummy placeholder value and the agent proxy swaps it for the real credential wherever it appears in the request. It is useful in two situations:
api.telegram.org/bot<token>/sendMessage.A few behaviors worth knowing:
Content-Encoding (compressed payloads), are forwarded unchanged without substitution.A proxied service uses secrets by key name, from its own folder. This keeps the relationship self-healing:
You cannot point a proxied service at another folder directly, but you can bring an outside value into its folder so the service can use it. There are two ways, both using features that already exist in Infisical:
| Approach | What you do | Example |
|---|---|---|
| Imported secret | Import another folder into the service's folder, then use the imported key by name | Import /shared-creds, then use its SHARED_API_KEY from the service's folder |
| Composed with references | Create a secret whose value is one or more secret references, then use that secret. Lets you combine several secrets, including ones from different environments | A secret set to ${dev.gateway.KEY}.${staging.gateway.KEY}.${prod.gateway.KEY} resolves to the three values joined together |
A folder-local secret always wins over an imported one with the same key. Read permission on an imported secret is checked where it actually lives, so an import cannot widen anyone's access.
Either way, the value is fully resolved before the proxy applies it.
A credential can reference a dynamic secret instead of a static secret. Instead of injecting a fixed value, the agent proxy mints a short-lived lease and injects one of its output fields (for example a database password, a GitHub App token, or a Kubernetes service-account token). Because the value rotates on its own at the lease TTL, a credential that leaks is worthless shortly after.
In the credential form, choose a dynamic secret from the Dynamic Secrets group of the secret picker, then pick which Output Field of the lease to inject. Each provider exposes different fields (SQL databases give DB_USERNAME / DB_PASSWORD, GitHub gives a TOKEN, and so on); pick the field you want to inject. Basic auth works by pointing the username and password at two fields of the same dynamic secret.
How the agent proxy handles the lease:
Proxied services can also be managed via the API. For example, creating the Telegram service described above:
curl -X POST https://app.infisical.com/api/v1/proxied-services \
-H "Authorization: Bearer $INFISICAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"projectId": "<project-id>",
"environment": "prod",
"secretPath": "/ai-agents",
"name": "telegram-bot-api",
"hostPattern": "api.telegram.org",
"credentials": [
{
"secretKey": "TELEGRAM_BOT_TOKEN",
"role": "credential-substitution",
"placeholderKey": "TELEGRAM_BOT_TOKEN",
"placeholderValue": "placeholder_tg_bot",
"substitutionSurfaces": ["path"]
}
]
}'
Header-rewrite credentials use "role": "header-rewrite" with headerName and an optional headerPrefix, or headerPurpose (username/password) for basic auth.
To reference a dynamic secret, replace secretKey on a credential with dynamicSecretName and dynamicSecretField:
{
"dynamicSecretName": "my-postgres",
"dynamicSecretField": "DB_PASSWORD",
"role": "header-rewrite",
"headerName": "Authorization",
"headerPrefix": "Bearer"
}