Skip to main content

HTTP Client Integration

Airnode exposes a standard HTTP API. You call an endpoint, receive signed data, and optionally submit it on-chain yourself.

Making a request

Send a POST request to /endpoints/{endpointId} with parameters in the JSON body. Include an API key header if the endpoint requires authentication.

curl -X POST http://airnode.example.com/endpoints/0x... \
-H "Content-Type: application/json" \
-H "X-Api-Key: your-key" \
-d '{"parameters":{"ids":"bitcoin","vs_currencies":"usd"}}'

Response format

The response format depends on whether the endpoint has encoding configured.

Encoded response

When the endpoint defines encoding (type, path, times), the response contains ABI-encoded data as a hex string. This is the format you submit to on-chain contracts.

{
"airnode": "0x...",
"endpointId": "0x...",
"timestamp": 1700000000,
"data": "0x...",
"signature": "0x...",
"proof": { "...": "present when TLS proofs are enabled" }
}

Raw response

When the endpoint has no encoding, the response contains the upstream API's JSON output directly. The signature covers the hash of the JSON data.

{
"airnode": "0x...",
"endpointId": "0x...",
"timestamp": 1700000000,
"rawData": { "bitcoin": { "usd": 67432 } },
"signature": "0x...",
"proof": { "...": "present when TLS proofs are enabled" }
}

The proof field is only present when TLS proofs are enabled and the endpoint has responseMatches configured.

Signature format

Every response is EIP-191 personal-signed over keccak256(encodePacked(endpointId, timestamp, data)). The signature proves the airnode endorsed this data at this timestamp for this endpoint. Anyone can verify it without trusting the transport layer.

See Signing and Verification for the full format, the raw-response hashing variant, and the off-chain verification snippet using viem.

Authentication

Endpoints support three auth methods: free (no credentials), apiKey (via X-Api-Key header), and x402 (pay-per-request). Endpoints with auth.type: 'apiKey' require an X-Api-Key header. Endpoints with auth.type: 'free' accept unauthenticated requests.

# Free endpoint -- no auth header needed
curl -X POST http://airnode.example.com/endpoints/0x... \
-H "Content-Type: application/json" \
-d '{"parameters":{"id":"1"}}'

# API key endpoint
curl -X POST http://airnode.example.com/endpoints/0x... \
-H "Content-Type: application/json" \
-H "X-Api-Key: your-key" \
-d '{"parameters":{"id":"1"}}'

Async requests

For endpoints with mode: async, the initial response is a 202 with a poll URL:

{
"requestId": "0x...",
"status": "pending",
"pollUrl": "/requests/0x..."
}

Poll until complete:

curl http://airnode.example.com/requests/0x...
# → { "requestId": "0x...", "status": "complete", "data": "0x...", "signature": "0x...", ... }

Status transitions: pendingprocessingcomplete | failed.

SSE streaming

For endpoints with mode: stream, the response is a Server-Sent Event:

curl -X POST -N http://airnode.example.com/endpoints/0x... \
-H "Content-Type: application/json" \
-d '{"parameters":{"ids":"bitcoin"}}'
data: {"done":true,"airnode":"0x...","endpointId":"0x...","timestamp":1700000000,"data":"0x...","signature":"0x..."}

The full pipeline runs (including plugins), and the signed result is delivered as a single SSE event.

x402 payment

This is an x402-flavoured scheme — pay on-chain first, then prove the confirmed transaction. It is not the x402 wire protocol (no X-PAYMENT/EIP-3009 authorization).

For endpoints with x402 auth, the first request returns 402 with payment details:

{
"airnode": "0x...",
"endpointId": "0x...",
"amount": "1000000",
"token": "0xA0b8...",
"network": 8453,
"recipient": "0x...",
"expiresAt": 1700001000
}

After sending the on-chain transfer, the payer signs an authorisation binding the payment to this airnode and endpoint:

message = keccak256(encodePacked(airnode, endpointId, uint64(expiresAt)))
signature = EIP-191 personal-sign(message) with the EOA that sent the transaction

Retry with a JSON-encoded X-Payment-Proof header:

PROOF='{"txHash":"0x...","expiresAt":1700001000,"signature":"0x..."}'

curl -X POST http://airnode.example.com/endpoints/0x... \
-H "Content-Type: application/json" \
-H "X-Payment-Proof: $PROOF" \
-d '{"parameters":{"ids":"bitcoin"}}'

The server verifies the signature recovers to the transaction sender and checks that expiresAt is in the future and no more than 10 minutes ahead. This binds the payment to the specific airnode and endpoint (signatures can't be reused across either, nor after expiry), and each txHash can be redeemed only once — that on-chain hash is the per-payment uniqueness key.

Error responses

StatusMeaning
400Missing or invalid parameters
401Missing or invalid API key
402Payment required (x402 — includes payment details)
404Unknown endpoint ID
413Request body too large (> 64KB)
415Content-Type must be application/json
429Too many requests (rate limit exceeded)
502Upstream API error or internal processing failure

Health check

curl http://airnode.example.com/health
{ "status": "ok", "airnode": "0x..." }

Use this to verify the server is running and to discover the airnode address for signature verification. (No version field — build info isn't exposed on this endpoint.)