Ingestion.
The first of three stages. Where every event enters the pipeline, and where every malformed one gets stopped at the door. Past the gate, we pay for the compute. Before the gate, no one does.
fig. 1 — five checks at the gate. An event either passes all of them and enters the pipeline, or becomes a dead-letter entry with a typed reason. Nothing is silently dropped.
The gate01
What ingest actually does.
Five jobs, in order. Each one fails closed: an event that does not pass becomes a dead-letter entry with a typed reason, not a silent drop.
- i.
- authenticate
- API key on SDK calls. Signed headers on inbound webhooks. Rotating without downtime.
- ii.
- validate
- Typed schema match. Unknown fields are rejected, not silently dropped.
- iii.
- deduplicate
- Idempotency keys per source. Configurable window. Retries are free, replays you trigger are counted.
- iv.
- rate-limit
- Your plan's burst and sustained ceilings. Excess gets a 429, not a queue. The 429 carries a Retry-After.
- v.
- accept or DLQ
- Typed event into the pipeline, or a DLQ entry with the reason. Both are visible in the dashboard.
Sources02
Where events come from.
Four flavors. SDKs for events you produce in code. Inbound HTTP for everything that already speaks webhook. Native integrations for vendors we ship signed verification against. And agents, for code that calls pipelines by id like named functions.
- sdk.eventTypeScript SDKtyped object[ready]
- webhook.inHTTP webhookJSON POST[ready]
- agentAI agentbearer token[ready]
- githubGitHub eventssigned webhook[ready]
- emailInbound emailRFC 5322[ready]
- sdk.pyPython SDKtyped object[soon]
- stripeStripe eventssigned webhook[soon]
Don't see yours? Open a source request on GitHub. The hosted integrations land in cohorts of three.
Schema03
One event, one declaration.
Every event type is declared once, in your repo, in YAML. The declaration drives the gate's validation, the SDK's types, the dashboard's search, and the downstream step's branch logic. One file, four consumers.
# events/user-signup.yaml event: user.signup schema: email: string, required source: enum [web, app, partner] plan: string? utm: object? idempotency: key: $payload.email window: 24h
Optional fields end in ?. Enums are inline. Idempotency lives next to the schema because deduplication is a property of the event, not the source.
Quickstart04
Zero to an event.
Two ways in. The SDK if you control the code that produces the event. The HTTP gateway if you do not.
// install
$ pnpm add @ingestlayer/sdk
// .env
INGESTLAYER_KEY=il_live_***
// in your app
import { init, track } from "@ingestlayer/sdk";
init({ apiKey: process.env.INGESTLAYER_KEY! });
track({
type: "user.signup",
payload: {
email: user.email,
source: "marketing-site",
plan: user.intendedPlan,
utm: session.utm,
},
});# any HTTP server, no SDK required.
$ curl -X POST https://in.ingestlayer.com/v1/ingest \
-H "Authorization: Bearer $INGESTLAYER_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": [{
"type": "user.signup",
"payload": { "email": "alice@acme.co" },
"idempotencyKey": "alice@acme.co"
}]
}'Next05
Where the event goes from here.
Once an event passes the gate, it walks the transform stack: any ordered subset of ten typed actions, grouped into enrichment, mutation, and control. Then route fans it out to the destinations.

