Skip to content
EVMKit Docs EVMKit Docs
Back to site
EVMKit Docs EVMKit Docs
Site

Docs Pipelines API

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.

Pipelines API requests are authenticated with your account API key through the account API.

Required header:

X-Api-Key: evk_your_live_key

If 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.

  • 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

Endpoints:

GET /api/account/pipelines/sources
GET /api/account/pipelines/sources/{sourceId}
POST /api/account/pipelines/sources
PATCH /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 8 values
  • the full filter set can contain up to 32 values across all fields
  • addresses, selectors, and topics are normalized to lowercase
  • numeric block filters accept decimal or 0x input and normalize to decimal text

Supported filters by source kind:

Source kindSupported filters
txfrom, to, contract, selector4
logfrom, to, contract, selector4, topic0, topic1, topic2, topic3
blocktransactionCount, 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.

Endpoints:

GET /api/account/pipelines/destinations
GET /api/account/pipelines/destinations/{destinationId}
POST /api/account/pipelines/destinations
PATCH /api/account/pipelines/destinations/{destinationId}
POST /api/account/pipelines/destinations/{destinationId}/test
DELETE /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:

  • POST and PATCH validate the destination before saving it
  • non-2xx responses, timeouts, or request failures return 400 with error: "stream_destination_test_failed"
  • responses never echo the stored webhook secret; they return hasSigningSecret instead
  • on PATCH, omitting webhook.signingSecret preserves the existing webhook secret
  • on PATCH, setting clearSigningSecret: true removes the stored webhook secret

Webhook settings:

FieldDefaultRule
urlnonehttps required outside development
httpVersionnone1.1 or 2
timeoutMs5000maximum 15000
maxRetries5maximum 10
retryBaseMs1000maximum 60000
retryMaxMs60000maximum 300000, must be >= retryBaseMs
headersemptyup to 16; host, content-length, and content-type are not allowed
signingSecretoptionalhidden 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.

Endpoints:

GET /api/account/pipelines/routes
GET /api/account/pipelines/routes/{routeId}
POST /api/account/pipelines/routes
PATCH /api/account/pipelines/routes/{routeId}
POST /api/account/pipelines/routes/{routeId}/test
POST /api/account/pipelines/routes/{routeId}/pause
POST /api/account/pipelines/routes/{routeId}/resume
DELETE /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:

  • region defaults to eu on create
  • region is locked after create and cannot be changed with PATCH
  • route uniqueness is enforced per route configuration
  • status can be set on create and defaults to active
  • after creation, use /pause and /resume to 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 /routes returns 409 with stream_route_limit_reached when 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.

Endpoints:

GET /api/account/pipelines/deliveries
GET /api/account/pipelines/deliveries/events/{eventId}

GET /deliveries supports:

  • page
  • pageSize
  • routeId
  • sourceId
  • destinationId
  • kind
  • status
  • groupBy
  • cursor
  • includeSourceName
  • includeDestinationName

Delivery history rules:

  • pageSize defaults to 25 and has a maximum of 100
  • the default response shape is attempt-based: one row per delivery attempt
  • pass groupBy=event to get one row per logical event with attemptsCount, firstAttemptAt, and lastAttemptAt
  • pass cursor with the nextCursor from the previous response to continue pagination
  • kind accepts test, route_test, and live
  • status accepts delivered, failed, and retrying
  • includeSourceName=false and includeDestinationName=false skip name hydration when callers only need ids

Example grouped query:

GET /api/account/pipelines/deliveries?routeId=33333333-3333-3333-3333-333333333333&groupBy=event&pageSize=2

Example 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.

Unlocked accounts can currently create up to:

  • 5 sources, 5 destinations, and 5 routes at 1M / day
  • 10 sources, 10 destinations, and 10 routes at 5M / day
  • 10 sources, 10 destinations, and 10 routes at 10M / day
  • 30 sources, 30 destinations, and 30 routes at 20M / day
  • 50 sources, 50 destinations, and 50 routes at 60M / day and above