ingestlayer/ingestion

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.

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

from your app · TypeScript
// 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,
  },
});
from any host · curl
# 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.

next: transformation →back to the spec

Ready to put something through the gate?

sign upread the docs