Interfaces
An interface is an endpoint. Add any number of them to a config under
interfaces: — each key is the interface name (and default route). When an
interface is triggered it runs its ordered list of actions.
interfaces:
prod/user-login:
summary: Log a user in
description: Verify credentials and return a token
tags: [auth]
output: http
method: POST
actions:
- name: CheckInput
- name: VerifyUser
- name: VerifyPassword
An interface can also run on a schedule, be exposed as an MCP tool, and carry a network policy. All fields follow.
Interface
Air Pipe interface definition. An interface represents an endpoint that can be invoked (via HTTP, schedule, etc.) and executes a chain of actions.
Example
myApiEndpoint: # Interface name (can be used as route path)
summary: Get users # Short description for documentation
description: | # Long description (optional)
Retrieves a list of all
users in the organization.
method: POST # HTTP method (for HTTP interfaces)
route: /users # URL path (optional, defaults to interface name)
tags: # OpenAPI tags for grouping
- Users
- API
output: http # Output type: http
templates: # Interface-specific response templates
success_template: |
{ "status": "ok" }
actions: # Ordered list of actions to execute
- name: ValidateJwt # Action name (used for references)
input: a|headers| # Input source (a|headers|, a|body|, etc.)
- name: FetchData
database: main # Database connection to use, assuming global is defined
query: SELECT * FROM users WHERE org_uuid = $1
params:
- a|CheckBody::organization_uuid|
assert: # Final assertion against action results
tests:
- value: count()
is_equal_to: 1
response: # Response configuration
http_code_on_error: 400 # HTTP status code on error
http_code_inherit_error: [FetchData] # Inherit error code from action
| Field | Type | Description |
|---|---|---|
summary | string (nullable) | |
description | string (nullable) | |
log | CustomLog (nullable) | |
tags | Array<string> (nullable) | |
templates | Map<string, string> (nullable) | |
mqtt | string (nullable) | MQTT trigger name. When set, this interface is triggered by an MQTT PUBLISH to the topic <environment>/<interface_name>/<this value> (carried over MQTT-over-WebSocket at… |
ws | string (nullable) | WebSocket marker. When set (to any value), this interface is reachable over WebSocket at /ws/<org>/<environment>/<interface_name>; each inbound JSON text frame runs the… |
subscribe_authorizer | string (nullable) | Realtime-channel access control. The name of an interface run to authorize a socket's ap_subscribe to a channel: it runs with { "channel": "<name>" } as a|body and the… |
public | boolean (nullable) | Public realtime opt-in. When true, this WebSocket interface accepts END-USER connections with NO credential at all — no org API key and no JWT — for non-sensitive public… |
schedule | Schedule (nullable) | |
silence | boolean (nullable) | |
method | string (nullable) | |
route | string (nullable) | |
show_error_detail | boolean (nullable) | |
actions | Array<Action> (nullable) | |
url | string (nullable) | |
conn_string | string (nullable) | |
query | string (nullable) | |
params | Map<string, Param> (nullable) | |
tests | Array<Test> (nullable) | |
assert | Assert (nullable) | |
output | InterfaceOutput (nullable) | |
response | InterfaceResponse (nullable) | |
disable_fastpath | boolean (nullable) | Opt this interface out of the compiled fast path (AP_FASTPATH), forcing every request through the interpreter. The fast path is byte-identical, so this never changes output —… |
request_example | any | Example request body shown in generated API documentation. |
response_example | any | Example successful response body shown in generated API documentation. |
notes | string (nullable) | Additional free-form documentation notes shown under the endpoint description. |
network | NetworkPolicy (nullable) | Network access-control policy for this interface (IP/geo/ASN/rate-limit). Inherits and tightens the config-wide network policy unless inherit: false. Evaluated before any… |
mcp | McpTool (nullable) | Expose this interface as an MCP tool (opt-in). When set with enabled: true, the interface is listed by the MCP server (tools/list) and callable via tools/call, reusing… |
InterfaceResponse
| Field | Type | Description |
|---|---|---|
http_code_on_error | number (nullable) | |
http_code_inherit_error | Array<string> (nullable) | |
headers | object (nullable) | |
custom_body | string (nullable) | |
http_code_fallback | number (nullable) | |
http_code_fallback_strategy | ErrorFallbackStrategy (nullable) | |
logs | Array<InterfaceLog> (nullable) |
InterfaceLog
| Field | Type | Description |
|---|---|---|
on | InterfaceLogOn | Required. |
database | string (nullable) |
InterfaceLogOn
Type: string — one of: error, success, any
InterfaceOutput
Type: string — one of: http, cli, none
ErrorFallbackStrategy
Type: string — one of: last_action, last_action_with_error, any_action
McpTool
Opt-in MCP tool exposure for an interface. See [Interface::mcp].
The MCP server auto-generates the tool's inputSchema from the interface's
assert tests (the same schema that powers the OpenAPI docs), so no separate
schema needs to be authored here.
| Field | Type | Description |
|---|---|---|
enabled | boolean | Expose this interface as an MCP tool. Default false. Default: false. |
tool_name | string (nullable) | Override the tool name shown to MCP clients. Defaults to the interface name. |
description | string (nullable) | Override the tool description. Defaults to the interface summary/description. |
list_authorizer | string (nullable) | Optional per-tool tools/list authorizer: the name of an interface in this config that is RUN (with the forwarded request headers) when a client lists tools. The tool appears… |
server | string (nullable) | Which declared MCP server this tool belongs to (see [IntegrationConfig::mcp_servers]). Omitted = the default server, which is what every pre-existing config gets. The id may… |
McpServer
A named MCP server: an identity, plus the tools that join it by id.
Declared under [IntegrationConfig::mcp_servers] and joined by [McpTool::server]. Declaring
and contributing are deliberately separate. Air Pipe's own management MCP is assembled from many
configs but is one server with one identity, so repeating the identity in each contributing
config would leave no single source of truth; conversely one org may publish several distinct
MCP offerings from different subsets of its configs.
title and instructions exist because MCP registries (mcp.so, Glama, Smithery, PulseMCP) read
a remote server's listing metadata straight off the initialize response — there is no separate
place to write a description. Without them a listing renders as a bare name and a wall of tool
descriptions.
| Field | Type | Description |
|---|---|---|
title | string (nullable) | Display name shown to MCP clients and registries (serverInfo.title). Absent = clients fall back to the protocol-level server name. |
instructions | string (nullable) | Server-level description, emitted as the initialize result's instructions. This is the field MCP registries surface as the listing description. |
default | boolean | Serve this identity on the bare /<org>/<env>/mcp route, i.e. adopt the tools that name no server. At most one per org+environment; ties resolve deterministically by config name. Default: false. |
Param
Parameter definition for interface-level URL parameters with optional validation and default values.
Example
interfaces:
getUser:
method: GET
params:
id:
value: a|params::id|
error_message: "User ID is required"
validate:
is_not_empty: true
regex: "^[0-9]+$"
page:
value: a|params::page|
default_value: "1"
| Field | Type | Description |
|---|---|---|
value | string (nullable) | Source value expression (e.g., a|params::id|). |
default_value | string (nullable) | Default value if the parameter is not provided. |
error_message | string (nullable) | Custom error message when validation fails. |
validate | Test (nullable) | Validation test to run against the parameter value. Example ↓ |
Field examples
validate
Validation test to run against the parameter value.
Example
validate:
is_not_empty: true
is_less_than: 100
regex: "^[a-zA-Z0-9]+$"
Schedule
AirPipe schedule configuration. Defines when and how an interface should be executed automatically via the scheduler.
Example
myScheduledEndpoint: # Interface name
method: POST
actions:
- name: MyAction
http:
url: https://api.example.com/trigger
schedule: # Schedule configuration (enables auto-execution)
cron: "0 9 * * *" # Required: Cron expression (5 fields: minute-hour-day-month-weekday)
enabled: true # Optional: Enable/disable the schedule (default: false)
# Retry configuration
max_attempts: 3 # Optional: Max retry attempts on failure (default: 1)
retry_backoff_seconds: 60 # Optional: Initial backoff in seconds (default: 60)
retry_backoff_multiplier: 2.0 # Optional: Backoff multiplier for exponential backoff (default: 2.0)
max_backoff_seconds: 3600 # Optional: Maximum backoff cap in seconds (default: 3600)
| Field | Type | Description |
|---|---|---|
cron | string | Required. Cron expression in 5-field format (minute hour day month weekday) |
enabled | boolean | Required. Whether the schedule is enabled |
max_attempts | number (nullable) | Max retry attempts on failure Default: 1. |
retry_backoff_seconds | number (nullable) | Initial retry backoff in seconds Default: 60. |
retry_backoff_multiplier | number (nullable) | Exponential backoff multiplier Default: 2. |
max_backoff_seconds | number (nullable) | Maximum retry backoff cap in seconds Default: 3600. |
timezone | string (nullable) | IANA timezone for cron interpretation (e.g. 'America/New_York'); defaults to UTC Default: null. |