Skip to main content

APIs and Endpoints

The apis section defines the upstream APIs that Airnode calls and how their responses are processed.

apis:
- name: CoinGecko
url: https://api.coingecko.com/api/v3
timeout: 15000
headers:
x-cg-pro-api-key: ${COINGECKO_API_KEY}
auth:
type: apiKey
keys:
- ${CLIENT_API_KEY}
cache:
maxAge: 30000
endpoints:
- name: coinPrice
path: /simple/price
# ...

API-level fields

FieldTypeRequiredDefaultDescription
namestringYes--Human-readable name for this API.
urlstring (URL)Yes--Upstream API base URL. Must be a valid URL.
headersRecord<string, string>No--Headers sent with every upstream request. Use ${VAR} for secrets.
authobjectNo--Client-facing authentication. See Auth.
cacheobjectNo--Response caching. See Cache.
timeoutnumberNo10000Upstream request timeout in milliseconds.
endpointsarrayYes--One or more endpoint definitions. Minimum 1.

headers

Static headers sent with every upstream API request. Use environment variable interpolation for credentials:

headers:
x-cg-pro-api-key: ${COINGECKO_API_KEY}
Accept: application/json

These are upstream credentials -- they authenticate Airnode to the API provider. This is separate from auth, which controls who can call Airnode.

Auth

The auth field controls client-facing authentication -- who is allowed to call your Airnode endpoints. It can be set at the API level (applies to all endpoints) or overridden per endpoint.

Free access

Anyone can call the endpoint without credentials:

auth:
type: free

API key

Clients must send a valid key in the X-Api-Key header:

auth:
type: apiKey
keys:
- ${CLIENT_API_KEY}
- ${CLIENT_API_KEY_2}

Keys are checked against the X-Api-Key request header using constant-time comparison. Multiple keys are supported for key rotation.

x402 (HTTP-native payment)

Pay-per-request using on-chain transfers. When a client requests without payment, the server returns a 402:

auth:
type: x402
network: 8453 # chain ID for payment
rpc: https://mainnet.base.org
token: '0xA0b8...' # ERC-20 address (or 0x000...0 for ETH)
amount: '1000000' # in token's smallest unit (e.g. 1 USDC = 1000000)
recipient: '0x...' # operator's address
expiry: 300000 # payment window in ms (default 5 min)

Flow: client POSTs → gets 402 with payment details → sends on-chain transfer → retries with X-Payment-Proof: <txHash> → server verifies the receipt → serves the response. Each tx hash can only be used once.

Multiple auth methods

Auth can be an array. Any method succeeding is sufficient (any-of semantics):

auth:
- type: x402
network: 8453
rpc: https://mainnet.base.org
token: '0xA0b8...'
amount: '1000000'
recipient: '0x...'
- type: apiKey
keys:
- ${PARTNER_KEY}
- type: free

Methods are tried in order. The first success authenticates the request. If all fail, the error from the last method is returned (or a 402 if the last method was x402).

Cache

Response caching.

cache:
maxAge: 30000 # cache responses for 30 seconds
FieldTypeRequiredDescription
maxAgenumberYesCache TTL in milliseconds for responses. Positive integer.
delaynumberNoDelay in milliseconds before cached responses are served.

maxAge controls response caching — repeated POST /endpoints/{id} requests with the same parameters return the cached response until the TTL expires.

Endpoint-level fields

Each endpoint describes one upstream API route:

endpoints:
- name: coinPrice
path: /simple/price
method: GET
parameters:
- name: ids
in: query
required: true
encoding:
type: int256
path: $.ethereum.usd
times: '1e18'
auth:
type: free
cache:
maxAge: 30000
description: Get the current price of a coin
FieldTypeRequiredDefaultDescription
namestringYes--Endpoint name. Used in logging. Not part of endpoint ID derivation.
pathstringYes--URL path appended to the API's url.
methodstringNoGETHTTP method: GET, POST, PUT, PATCH, or DELETE.
modestringNosyncResponse mode: sync, async, or stream.
parametersarrayNo[]Parameter definitions. See Parameters.
encodingobjectNo--ABI encoding rules. When omitted, raw JSON is signed.
authobjectNo--Overrides API-level auth for this endpoint.
cacheobjectNo--Overrides API-level cache for this endpoint.
descriptionstringNo--Human-readable description. Does not affect runtime behavior.

mode

Controls how the server delivers the response:

  • sync (default) — call API, wait for result, respond with signed data in the same HTTP request.
  • async — return 202 immediately with a requestId and pollUrl. The API call runs in the background. Client polls GET /requests/{requestId} until the status is complete or failed.
  • stream — return the signed response as a Server-Sent Event (SSE). The response has Content-Type: text/event-stream. The full pipeline runs (including plugins), and the signed result is delivered as a single data: event with done: true.
endpoints:
- name: inference
path: /v1/completions
method: POST
mode: async # return 202, poll for result

- name: chat
path: /v1/chat/completions
method: POST
mode: stream # return SSE events

Parameters

Parameters define the inputs to an upstream API call. Each parameter specifies where to send its value and how it is resolved.

parameters:
- name: ids
in: query
required: true
description: Coin ID (e.g. ethereum, bitcoin)
- name: vs_currencies
in: query
default: usd

Parameter fields

FieldTypeRequiredDefaultDescription
namestringYes--Parameter name as the upstream API expects it.
instringNoqueryWhere to send: query, header, path, cookie, or body.
requiredbooleanNofalseIf true, the client must provide this parameter.
fixedstring | number | booleanNo--Hardcoded value. Always overrides the client's value.
defaultstring | number | booleanNo--Fallback value when the client does not provide one.
secretbooleanNofalseIf true, excluded from endpoint ID derivation.
descriptionstringNo--Human-readable description.

Fixed vs default

  • fixed -- the value is locked. The client cannot override it. Use this for parameters the client should never control (e.g., forcing localization: false to reduce response size).
  • default -- a fallback. The client can override it. Use this for sensible defaults that clients may want to change (e.g., vs_currencies defaulting to usd).

Resolution order:

  1. fixed -- if set, always wins
  2. Client-provided value -- from the request body
  3. default -- fallback when the client provides nothing

If none produce a value and required: true, the request fails with a validation error.

A parameter cannot have both required: true and a default value. If you set a default, the parameter is implicitly optional — there is always a fallback value. The schema validator rejects this combination.

Secret parameters

Parameters marked secret: true are excluded from endpoint ID derivation. This means changing a secret parameter does not change the endpoint ID.

Parameters with fixed values that use ${VAR} interpolation are also treated as secret automatically.

Query parameters

The default. Appended to the upstream URL query string:

parameters:
- name: ids
in: query
required: true
- name: vs_currencies
in: query
default: usd

Request to /simple/price?ids=ethereum&vs_currencies=usd.

Path parameters

Use {paramName} placeholders in the endpoint path:

endpoints:
- name: coinMarketData
path: /coins/{coinId}
parameters:
- name: coinId
in: path
required: true

When the client provides coinId: ethereum, the URL becomes /coins/ethereum.

Header parameters

Sent as HTTP headers on the upstream request:

parameters:
- name: X-Custom-Header
in: header
fixed: special-value

Body parameters

For POST endpoints. All in: body parameters are collected into a flat JSON object:

endpoints:
- name: generateInteger
path: /json-rpc/4/invoke
method: POST
parameters:
- name: jsonrpc
in: body
fixed: '2.0'
- name: method
in: body
fixed: generateIntegers
- name: min
in: body
default: 0
- name: max
in: body
default: 100

Produces the request body:

{ "jsonrpc": "2.0", "method": "generateIntegers", "min": 0, "max": 100 }

Sent as cookies on the upstream request:

parameters:
- name: session_token
in: cookie
fixed: ${SESSION_TOKEN}
secret: true

Encoding

The encoding field controls how the API response is ABI-encoded before signing. When omitted, the raw JSON response is signed directly.

encoding:
type: int256
path: $.ethereum.usd
times: '1e18'
FieldTypeRequiredDescription
typestringNoSolidity type(s) for ABI encoding: int256, uint256, bool, bytes32, etc.
pathstringNoJSONPath expression to extract the value from the API response.
timesstringNoMultiplier applied before encoding. Converts decimals to integers for Solidity.

All fields are optional individually. The encoding is complete when both type and path are present — either from the config, from the requester's request parameters, or a combination of both. See requester-specified encoding below.

Multi-value encoding

Encode multiple values from a single API response using comma-separated type, path, and times:

encoding:
type: int256,uint256
path: $.ethereum.usd,$.ethereum.usd_24h_vol
times: '1e18,1e18'

Entries are positionally matched -- the first type pairs with the first path and first times value.

Raw JSON (no encoding)

Omit the encoding field entirely. The raw JSON response is hashed and signed:

endpoints:
- name: coinPriceRaw
path: /simple/price
method: GET
parameters:
- name: ids
in: query
required: true
# No encoding -- raw JSON response is signed

Empty responses (204 No Content)

When the upstream API returns an empty body (e.g. HTTP 204), the behavior depends on the encoding mode:

  • Raw mode — returns rawData: null with a valid signature. The signature covers keccak256(toHex("null")), providing a verifiable attestation that the API returned no content.
  • Encoded mode — returns HTTP 502 with "API returned no data to encode". There is no value to extract via JSONPath, so encoding cannot proceed.

Empty JSON objects ({}) behave similarly — raw mode signs them as-is, while encoded mode fails if the JSONPath finds no value at the configured path.

Requester-specified encoding

Clients can control encoding by passing reserved parameters in their request body: _type, _path, and optionally _times. These parameters are consumed by the pipeline and never sent to the upstream API.

Three modes:

  1. Operator-fixed — the endpoint has a complete encoding block (type + path). Client reserved parameters are ignored. The endpoint ID commits to this encoding.
  2. Partial — the endpoint has an encoding block with some fields (e.g. type only). The client fills in the missing fields via _path or _times. Operator fields take precedence.
  3. Requester-only — no encoding block. The client provides _type and _path. If neither is provided, raw JSON mode is used.
# Requester chooses what to extract from a raw endpoint
curl -X POST http://localhost:3000/endpoints/{endpointId} \
-H "Content-Type: application/json" \
-d '{"parameters":{"ids":"ethereum","vs_currencies":"usd","_type":"int256","_path":"$.ethereum.usd","_times":"1e18"}}'
# Partial: operator fixes the type, requester chooses the path
endpoints:
- name: flexiblePrice
path: /simple/price
encoding:
type: int256
# path comes from the requester's _path parameter

If the merged result has _type without _path (or vice versa), the server returns 400.