Pipelines API
API for managing filters, webhook destinations, routes, and delivery records.
Pipelines API is the management API for Pipelines.
It exposes the same account-owned sources, destinations, routes, and delivery records used by the dashboard UI. Use it when your own control plane needs to create, update, pause, resume, test, and manage pipeline resources programmatically.
Authentication
Section titled “Authentication”Pipelines API requests are authenticated with your account API key through the account API.
Required header:
X-Api-Key: evk_your_live_keyIf you are using the dashboard UI, account authentication gives you access to the same account and its API key. Direct Pipelines API resource requests do not use bearer session tokens.
Resource model
Section titled “Resource model”- sources define transaction, log, and block filters
- destinations define where resulting payloads should be delivered
- routes connect one source to one destination in a selected region
- deliveries expose destination tests, route tests, and live webhook delivery records
Accepted enum values:
- source
kind:tx,log,block - route
region:us,ca,eu - destination
kind:webhook - route
status:active,paused - delivery
kind:test,route_test,live - delivery
status:delivered,failed,retrying
Sources
Section titled “Sources”Endpoints:
GET /api/account/pipelines/sourcesGET /api/account/pipelines/sources/{sourceId}POST /api/account/pipelines/sourcesPATCH /api/account/pipelines/sources/{sourceId}DELETE /api/account/pipelines/sources/{sourceId}GET /sources returns source rows with stats and linkedDestinations.
GET /sources/{sourceId} returns the source definition and linked destinations for one source.
Source rules:
- at least one filter is required
- each filter field can contain up to
8values - the full filter set can contain up to
32values across all fields - addresses, selectors, and topics are normalized to lowercase
- numeric block filters accept decimal or
0xinput and normalize to decimal text
Supported filters by source kind:
| Source kind | Supported filters |
|---|---|
tx | from, to, contract, selector4 |
log | from, to, contract, selector4, topic0, topic1, topic2, topic3 |
block | transactionCount, graffitiContains, coinbasePayment |
Numeric filters use this shape:
{ "operator": "gt", "value": "250"}Accepted operator values are eq, gt, and lt. The API also accepts =, >, and < and normalizes them.
Example create request for a block source:
{ "name": "High activity blocks", "kind": "block", "filters": { "transactionCount": { "operator": "gt", "value": "250" }, "graffitiContains": "builder", "coinbasePayment": { "operator": "gt", "value": "0x0" } }}DELETE /sources/{sourceId} returns 409 if the source is still referenced by one or more routes.
Destinations
Section titled “Destinations”Endpoints:
GET /api/account/pipelines/destinationsGET /api/account/pipelines/destinations/{destinationId}POST /api/account/pipelines/destinationsPATCH /api/account/pipelines/destinations/{destinationId}POST /api/account/pipelines/destinations/{destinationId}/testDELETE /api/account/pipelines/destinations/{destinationId}The current destination kind is webhook.
GET /destinations accepts includeAnalytics=false when you only need the configured destinations without the analytics snapshot fields.
GET /destinations/{destinationId} returns the destination plus the routes that currently point to it.
Destination write rules:
POSTandPATCHvalidate the destination before saving it- non-
2xxresponses, timeouts, or request failures return400witherror: "stream_destination_test_failed" - responses never echo the stored webhook secret; they return
hasSigningSecretinstead - on
PATCH, omittingwebhook.signingSecretpreserves the existing webhook secret - on
PATCH, settingclearSigningSecret: trueremoves the stored webhook secret
Webhook settings:
| Field | Default | Rule |
|---|---|---|
url | none | https required outside development |
httpVersion | none | 1.1 or 2 |
timeoutMs | 5000 | maximum 15000 |
maxRetries | 5 | maximum 10 |
retryBaseMs | 1000 | maximum 60000 |
retryMaxMs | 60000 | maximum 300000, must be >= retryBaseMs |
headers | empty | up to 16; host, content-length, and content-type are not allowed |
signingSecret | optional | hidden in responses |
Example create request:
{ "name": "Primary webhook", "kind": "webhook", "webhook": { "url": "https://example.com/evmkit/pipelines", "httpVersion": "2", "timeoutMs": 5000, "maxRetries": 5, "retryBaseMs": 1000, "retryMaxMs": 60000, "headers": [ { "name": "X-App-Env", "value": "prod" } ], "signingSecret": "replace-me" }}POST /destinations/{destinationId}/test sends a destination test request with X-Evmkit-Test: true, X-Evmkit-Timestamp, and optional X-Evmkit-Signature.
DELETE /destinations/{destinationId} returns 409 if the destination is still referenced by one or more routes.
Routes
Section titled “Routes”Endpoints:
GET /api/account/pipelines/routesGET /api/account/pipelines/routes/{routeId}POST /api/account/pipelines/routesPATCH /api/account/pipelines/routes/{routeId}POST /api/account/pipelines/routes/{routeId}/testPOST /api/account/pipelines/routes/{routeId}/pausePOST /api/account/pipelines/routes/{routeId}/resumeDELETE /api/account/pipelines/routes/{routeId}GET /routes accepts optional sourceId and destinationId filters.
GET /routes/{routeId} returns a route detail payload with:
- the current route
- selectable sources for the account
- selectable destinations for the account
- delivery stats for the last hour and last 24 hours
Route rules:
regiondefaults toeuon createregionis locked after create and cannot be changed withPATCH- route uniqueness is enforced per route configuration
statuscan be set on create and defaults toactive- after creation, use
/pauseand/resumeto change lifecycle state - source, destination, and route capacity each scale per account by daily CU tier:
1M -> 5,5M -> 10,20M -> 30,60M+ -> 50 POST /routesreturns409withstream_route_limit_reachedwhen the route cap is exhausted
Example create request:
{ "sourceId": "11111111-1111-1111-1111-111111111111", "destinationId": "22222222-2222-2222-2222-222222222222", "region": "eu"}Example route response:
{ "id": "33333333-3333-3333-3333-333333333333", "sourceId": "11111111-1111-1111-1111-111111111111", "sourceName": "State update event", "sourceKind": "log", "region": "eu", "destinationId": "22222222-2222-2222-2222-222222222222", "destinationName": "Primary webhook", "destinationKind": "webhook", "status": "active", "consecutiveFailures": 0, "createdAt": "2026-03-28T09:00:00Z", "updatedAt": "2026-03-28T09:00:00Z", "lastDeliveredAt": null, "lastErrorAt": null, "lastErrorCode": null, "lastErrorMessage": null}POST /routes/{routeId}/test sends a route test payload with type: "stream.match.test" and records a delivery row with deliveryKind: "route_test".
Deleting a route does not remove historical delivery rows that were already recorded for that route.
Delivery history
Section titled “Delivery history”Endpoints:
GET /api/account/pipelines/deliveriesGET /api/account/pipelines/deliveries/events/{eventId}GET /deliveries supports:
pagepageSizerouteIdsourceIddestinationIdkindstatusgroupBycursorincludeSourceNameincludeDestinationName
Delivery history rules:
pageSizedefaults to25and has a maximum of100- the default response shape is attempt-based: one row per delivery attempt
- pass
groupBy=eventto get one row per logical event withattemptsCount,firstAttemptAt, andlastAttemptAt - pass
cursorwith thenextCursorfrom the previous response to continue pagination kindacceptstest,route_test, andlivestatusacceptsdelivered,failed, andretryingincludeSourceName=falseandincludeDestinationName=falseskip name hydration when callers only need ids
Example grouped query:
GET /api/account/pipelines/deliveries?routeId=33333333-3333-3333-3333-333333333333&groupBy=event&pageSize=2Example grouped response:
{ "items": [ { "eventId": "evt_live_3d6d2f5b3e8d4202b4c8a8b8e2f6a18a", "routeId": "33333333-3333-3333-3333-333333333333", "sourceId": "11111111-1111-1111-1111-111111111111", "sourceName": "State update event", "destinationId": "22222222-2222-2222-2222-222222222222", "destinationName": "Primary webhook", "deliveryKind": "live", "status": "retrying", "httpStatusCode": 503, "latencyMs": 142, "nextRetryAt": "2026-03-28T09:01:00Z", "deliveredAt": null, "errorCode": "http_error", "errorMessage": "destination returned HTTP 503", "firstAttemptAt": "2026-03-28T09:00:00Z", "lastAttemptAt": "2026-03-28T09:00:30Z", "attemptsCount": 2 } ], "nextCursor": null}Use GET /deliveries/events/{eventId} to load the full attempt history for one grouped event.
Delivery history includes destination tests, route tests, and live deliveries.
Account limits
Section titled “Account limits”Unlocked accounts can currently create up to:
5sources,5destinations, and5routes at1M / day10sources,10destinations, and10routes at5M / day10sources,10destinations, and10routes at10M / day30sources,30destinations, and30routes at20M / day50sources,50destinations, and50routes at60M / dayand above