The Proxy API sends authenticated HTTP requests to connected services. STACK injects the stored OAuth token or API key into the outbound request. A proxy-only agent does not receive the credential.
The Proxy API is available on every tier, including Free. A valid X-Passport-Token header is required on every proxy request.
Send an HTTP request through STACK to a connected service. STACK resolves the credential, injects authentication headers, forwards the request to the full target URL, and returns the upstream response.
curl -X POST https://api.getstack.run/v1/proxy \
-H "Authorization: Bearer sk_live_your_key" \
-H "X-Passport-Token: eyJhbGciOiJFZERTQSIs..." \
-H "Content-Type: application/json" \
-d '{
"service": "github",
"method": "GET",
"url": "https://api.github.com/user/repos?per_page=5"
}'The url must be a full URL on an allowed host for the selected service.
The proxy returns the upstream response wrapped in a STACK envelope with status, headers, and body.
{
"status": 200,
"headers": {
"content-type": "application/json; charset=utf-8",
"x-ratelimit-remaining": "4999"
},
"body": [
{
"id": 123456,
"name": "my-repo",
"full_name": "user/my-repo",
"private": false
}
]
}Each service connection has a proxy_enabled flag that must be set to true before the proxy can be used for that service. Toggle it using the service proxy-toggle endpoint:
curl -X POST https://api.getstack.run/v1/services/conn_abc123/proxy-toggle \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "proxy_enabled": true }'If proxy_enabled is false on the target service connection, proxy requests return 403 Forbidden.
curl -X POST https://api.getstack.run/v1/proxy \
-H "Authorization: Bearer sk_live_your_key" \
-H "X-Passport-Token: eyJ..." \
-H "Content-Type: application/json" \
-d '{
"service": "github",
"method": "GET",
"url": "https://api.github.com/user/repos",
"query": { "sort": "updated", "per_page": "10" }
}'curl -X POST https://api.getstack.run/v1/proxy \
-H "Authorization: Bearer sk_live_your_key" \
-H "X-Passport-Token: eyJ..." \
-H "Content-Type: application/json" \
-d '{
"service": "slack",
"method": "POST",
"url": "https://slack.com/api/chat.postMessage",
"body": {
"channel": "C0123456789",
"text": "Deployed v2.1.0 to production"
}
}'curl -X POST https://api.getstack.run/v1/proxy \
-H "Authorization: Bearer sk_live_your_key" \
-H "X-Passport-Token: eyJ..." \
-H "Content-Type: application/json" \
-d '{
"service": "openai",
"method": "POST",
"url": "https://api.openai.com/v1/chat/completions",
"body": {
"model": "gpt-4o",
"messages": [{ "role": "user", "content": "Hello" }]
}
}'STACK verifies that the requested service is within the passport's scope. The passport JWT contains intent_services and services arrays. The proxy checks that the service field matches one of these.
If the service is not in scope, the behavior depends on the passport's accountability mode:
Additionally, proxy requests are blocked if the passport has already been checked out. This generates a credential_after_checkout security event.
When the Passport carries authority_refs, STACK resolves the exact active binding and enforces its pinned agent key, receiver, action, resource, Mission, validity, approval, and limits before forwarding the request. Missing, stale, revoked, or unavailable required state denies the action.
A proxy-mediated authority use proves STACK enforcement. It is not a native receiver proof. Native verification uses a signed receiver request and a signed-then-encrypted presentation delivered directly to the receiver. See Authority API.
STACK determines the correct authentication method based on the service provider and injects the appropriate headers into the outbound request. The agent's original request never contains the credential.
Proxy requests use the shared monthly action allowance.
Above the allowance, STACK debits the Wallet. A request returns 402 when the Wallet cannot cover the overage.
Check shared action use for the current billing period.
curl https://api.getstack.run/v1/proxy/usage \
-H "Authorization: Bearer sk_live_your_key"{
"tier": "pro",
"limit": 1500000,
"used": 205411,
"remaining": 1294589,
"period": "2026-04"
}For Enterprise tier, limit and remaining are null (unlimited).
// Missing X-Passport-Token
{ "error": "FORBIDDEN", "message": "X-Passport-Token header required for proxy requests" }
// Wallet cannot cover overage
{ "error": "INSUFFICIENT_BALANCE", "message": "Monthly action allowance exceeded on developer tier and wallet has insufficient balance for overage." }
// Service not in passport scope (enforced mode)
{ "error": "FORBIDDEN", "message": "Service notion not in passport scope" }
// Proxy disabled on connection
{ "error": "FORBIDDEN", "message": "Proxy access disabled for service notion" }
// Passport already checked out
{ "error": "FORBIDDEN", "message": "Passport already checked out" }The proxy forwards the response body as-is from the upstream service. If the upstream response contains sensitive data (e.g., customer PII from a Stripe response), that data will be visible to the agent. Scope your API calls appropriately.