Gateway HTTP
Gateway HTTP is the HTTP surface of an Agent Gateway environment: the MCP endpoint, the REST mirror, the documents it publishes and the sign-in endpoints. Use this page when you call a gateway from your own code or need to read an error.
URLs
Every URL of an environment starts with the same base. <workspace> is your workspace's slug and <gateway> is the gateway's slug.
https://gateway.faustine.ai/<workspace>/<gateway> the default environment
https://gateway.faustine.ai/<workspace>/<gateway>/<environment> any other environmentWith a custom domain, your domain replaces gateway.faustine.ai/<workspace>: https://<your-domain>/<gateway>[/<environment>]. Both addresses keep working.
| Path after the base | Methods | What it serves |
|---|---|---|
/mcp |
POST, GET, DELETE |
The MCP endpoint, over Streamable HTTP. POST carries JSON-RPC. The server keeps no state between requests. |
/api/<namespace>/<operation> |
POST, GET |
The REST mirror. One URL per operation. |
/openapi.json |
GET |
The OpenAPI document of the environment. |
/docs |
GET |
The docs page. |
/skill.md |
GET |
A skill file that describes the gateway to a coding agent. |
/.well-known/oauth-protected-resource |
GET |
OAuth protected resource metadata. |
/.well-known/oauth-authorization-server |
GET |
OAuth authorization server metadata. |
/oauth/register, /oauth/authorize, /oauth/token, /oauth/revoke |
The OAuth endpoints gateway users sign in through. |
/openapi.json, /docs and /skill.md are public by default. When an environment's docs are not public, they require a credential and show only the operations that credential can call. See Customize the gateway docs page.
In the REST path, <namespace> is the API's namespace and <operation> is the rest of the operation key. The operation crm.contacts.create is served at /api/crm/contacts.create.
Authentication
Every request to /mcp and /api carries a bearer token.
Authorization: Bearer fik_…| Credential | Token | How the client gets it |
|---|---|---|
| API key | Starts with fik_ |
You create the key in the portal and give it to the client. See Create an API key. |
| Gateway user | Starts with fot_ |
The client obtains it from the gateway's OAuth server after the person signs in. See Create a gateway user. |
A credential works on the environment it belongs to. On any other environment or gateway, the response is the same as for an unknown credential.
Sign-in with OAuth
The gateway is its own OAuth 2.0 authorization server, one per environment. A request without a valid token gets 401 with a challenge that names the metadata document:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://gateway.faustine.ai/<workspace>/<gateway>/.well-known/oauth-protected-resource"| Property | Value |
|---|---|
| Client registration | Dynamic, at /oauth/register. Public clients only (token_endpoint_auth_method: none). |
| Grant types | authorization_code, refresh_token |
| PKCE | Required, with S256. |
| Access token lifetime | 3600 seconds |
| Refresh token lifetime | 30 days |
A session is valid only on the host it was obtained through. A token issued on gateway.faustine.ai does not work on a custom domain, and the reverse.
Failed authentication
A 401 body is JSON with a message field.
| Message | Cause |
|---|---|
Invalid API key |
The key is unknown, or belongs to another environment or gateway. |
Invalid session token |
The session token is unknown, or belongs to another environment, gateway or host. |
API key revoked, Gateway user revoked |
The credential was revoked. |
API key rotated and its grace period has ended |
The key was rotated out. |
Denied (expired): API key expired |
The credential's Expires date has passed. |
Denied (not_yet_valid): … |
The credential's Not before date has not been reached. |
Access token expired, Session revoked |
The session has to be refreshed, or the person has to sign in again. |
After 30 failed authentications from one IP address in a minute, every request from that address gets 429 with the code auth_throttled and a Retry-After header, until the minute ends.
Request headers
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer and the key or the session token. |
Content-Type |
For POST with a body |
application/json |
X-Faustine-Connection |
No | The name of the connection to call, when the API's routing lets the caller choose. Same as the $connection input field. See Routing: fixed, dynamic and fan-out. |
X-Upstream-Authorization |
No | The caller's own credentials for your API, when the API passes credentials through. See Pass the caller's credentials through. |
Response headers
| Header | Description |
|---|---|
X-Faustine-Request-Id, x-request-id |
The ID of the request, starting with req_. Search the gateway's Logs tab by it. |
X-Faustine-Manifest-Version |
The versions of the APIs the environment serves. It changes when the served operations change. |
Retry-After |
Seconds to wait, on 429 responses. |
Allow |
The accepted methods, on 405 responses. |
REST requests
A REST call runs one operation. The request body is the operation's input.
| Method | Input | Accepted for |
|---|---|---|
POST |
A JSON object in the body. An empty body is an empty input. | Every operation. |
GET |
The query string. | Read operations only. A GET to a write operation returns 405. |
With GET, a query value is read as a boolean, a number, null or JSON when it looks like one, unless the operation's schema declares the field as a string. A repeated key becomes an array.
<GATEWAY_KEY> is an API key of the environment.
curl -X POST https://gateway.faustine.ai/<workspace>/<gateway>/api/crm/contacts.create \
-H "Authorization: Bearer <GATEWAY_KEY>" \
-H "Content-Type: application/json" \
-d '{"first_name": "Ada", "last_name": "Lovelace", "email": "[email protected]"}'REST responses
A successful call returns 200 with the status and the body your API answered.
{
"status": 201,
"body": { "id": 42, "first_name": "Ada", "last_name": "Lovelace", "email": "[email protected]" }
}Under fan-out routing, body is { "byConnection": [ … ] } with one entry per connection.
Errors
A failed call returns an error envelope.
{
"error": {
"code": "scope",
"message": "Denied (scope): This key is not scoped for \"crm.contacts.delete\"",
"requestId": "req_01JCD9T3W8Q2M4X6Z0V5B7N1KP"
},
"denyReason": "scope"
}| Field | Description |
|---|---|
error.code |
A stable code from the tables on this page. |
error.message |
A sentence for a person or a model. A refusal starts with Denied (<code>):. |
error.requestId |
The request's ID in the gateway's Logs tab. |
denyReason |
Present when the gateway refused the call. Same value as the code. |
status, body |
Present on upstream_error. The status and the body your API answered. |
Over MCP, a failed operation is a tool result marked as an error, with the same message as its text. A request refused before any tool runs (a paused gateway, a channel or an IP restriction) is an HTTP error with the envelope.
Refused by the credential or the environment
| Code | Status | Cause |
|---|---|---|
scope |
403 | The operation is not in the credential's scope. |
read_only |
403 | The credential is read-only and the operation writes. |
requires_confirmation |
403 | The operation requires confirmation and was not confirmed: the credential is set to Refuse, or the client cannot ask the person. See Confirmation. |
channel |
403 | The credential or the environment does not allow this channel. |
ip_not_allowed |
403 | The caller's address is not on the allowlist. |
ip_blocked |
403 | The caller's address is on a blocklist or belongs to a blocked country. |
write_not_available |
403 | The API uses fan-out routing and the write is disabled or names no connection. |
gateway_paused |
503 | The gateway is paused. |
Wrong request
| Code | Status | Cause |
|---|---|---|
unknown_operation |
404 | No operation with that key is exposed in this environment. |
method_not_allowed |
405 | GET on a write operation, or a method other than GET and POST. |
invalid_input |
400 | The input is not a JSON object. |
no_connection |
400 | The API has several connections and the request does not select one, or names one that is not available. |
body_too_large |
413 | The body exceeds the credential's limit. |
Limits
| Code | Status | Cause |
|---|---|---|
rate_limit |
429 | The credential's rate limit or the environment-wide rate limit was exceeded. |
quota |
429 | The hourly or daily quota is used up. |
concurrency |
429 | The credential has too many calls in flight. |
runner_busy |
429 | A recipe could not start because the code runner is at capacity. |
auth_throttled |
429 | Too many failed authentications from the caller's address. |
Every 429 carries Retry-After in seconds. See Limits and quotas for the defaults.
Repeated writes
These codes exist when the environment deduplicates repeated writes. A repeat of a finished write is not an error: it returns 200 with the stored response of the first call.
| Code | Status | Cause |
|---|---|---|
idempotency_in_flight |
409 | The same write was sent before and has not finished, or its outcome is unknown. |
idempotency_conflict |
409 | A write with the same identifying fields and different values ran inside the window. |
idempotency_duplicate |
409 | The same write already ran, and its response was larger than 64 KB and was not kept. |
See Repeated writes.
Your API and recipes
| Code | Status | Cause |
|---|---|---|
upstream_error |
502 | Your API answered with an error status or could not be reached. |
auth_failed |
502 | The gateway could not sign in to your API with the connection's credentials. |
no_credential |
502 | The connection has no credentials. |
no_base_url |
502 | The connection has no base URL. |
response_too_large |
502 | Your API's response is larger than the gateway reads. |
recipe_error |
422 | The code of a recipe threw an error. |
sandbox_limit |
422 | A recipe exceeded its time, memory or call limit. |
recipe_http_denied |
400 | A recipe tried to reach a URL it is not allowed to call. |
runner_unavailable |
503 | The code runner is not available. |
internal |
500 | An error inside the gateway. |
Next steps
- Call a gateway over REST and OpenAPI: generate a client from the OpenAPI document.
- Connect clients: connect an MCP client instead of calling HTTP yourself.
- Logs: find a request by its ID.
Last updated November 13, 2026