The intelligence layer for your event pipeline.
Track events from anywhere, send them through elaborate data processing pipelines, and route each one to the destinations you need.
Overview00
What this is.
One process sits between everything that produces signals at your company and everything that consumes them. It accepts the signal, runs an ordered stack of typed transformations on it, and fans the result out. Fourteen actions today, in three categories. Pick the ones each event family needs.
- enrich.entity
- enrich.person
- enrich.company
- classify
- summarize
- translate
- ai.transform
- http.request
- upsert.entity
- redact.pii
- transform
- dedupe
- throttle
- filter
fig. 1 — the spine. Three stages per signal. The middle is a stack you compose.
Pipeline01
Three stages. Any stack.
Every signal walks the same three stages. The middle one is a stack of typed actions you compose per event family. Page views skip the stack and go straight to route. Signups get the whole kitchen.
- 01
- ingest
- Accept the signal as it arrives. Durable, typed, idempotent.
- 02
- transform
- An ordered stack of typed actions. Pick from fourteen today: enrichment that adds fields, mutation that rewrites them, control that may drop the event.
- 03
- route
- Branch on the typed result. Fan out. Retry. Dead-letter. Replay.
enrichment
· adds new fieldsENR- enrich.entity
- lookup against your identity graph
- enrich.person
- email → person profile
- enrich.company
- domain → company facts
- classify
- LLM labels with a typed schema
- summarize
- short summary of long text
- translate
- into a target language
- ai.transform
- free-form prompt over event data
- http.request
- call any API → merge into $http
mutation
· rewrites in placeMUT- upsert.entity
- write event fields into the identity graph
- redact.pii
- per-destination PII matrix
- transform
- escape hatch · custom template
control
· may drop the eventCTL- dedupe
- drop if seen recently
- throttle
- rate-limit per key
- filter
- drop unless predicate matches
Order matters. Dedupe before classify saves model calls. Redact before route enforces PII at the wire.
Sources03
Where signals come from.
Anywhere signals come from. SDK, webhook, AI agent, and GitHub are live today. Python SDK and Stripe land next.
- sdk.eventTypeScript SDK[ready]
- webhook.inHTTP webhook[ready]
- agentAI agent[ready]
- githubGitHub events[ready]
- emailInbound email[ready]
- sdk.pyPython SDK[soon]
- stripeStripe events[soon]
Destinations04
Where they need to land.
Anywhere they need to land. One signal, many destinations, shaped differently for each consumer.
- slackSlack[ready]
- telegramTelegram[ready]
- webhook.outHTTP webhook[ready]
- email.outEmail[ready]
- warehouse.pgPostgres[ready]
- discordDiscord[ready]
- notion.dbNotion[ready]
- warehouse.bqBigQuery[soon]
- linear.issueLinear issue[soon]
- s3S3 / object[soon]
Example05
Tracking a new team invite
Events arrive from the TypeScript SDK matching team.member.invited. The pipeline enriches with the user entity matched on $event.inviter_id, enriches with person data from $event.invitee_email, enriches with the account entity matched on $entity.user.account_id, classifies along pattern (4 labels) and priority (4 labels), and redacts PII (with per-destination overrides). Routed to Slack in #cs, email to cs-leads@ingestlayer.io, and Postgres (table events.team_invite).
representation
01source
02pipeline · 5 steps
- 01ENRenrich.entityuser by $event.inviter_id
- 02ENRenrich.person$event.invitee_email · entity → internal
- 03ENRenrich.entityaccount by $entity.user.account_id
- 04ENRclassifypattern (4) · priority (4) · balanced
- 05MUTredact.pii6 types · slack overrides email + phone
03destinations · 3
- toslackSlackchannel#cs
- toemail.outEmailtocs-leads@ingestlayer.io
- towarehouse.pgPostgrestableevents.team_invite
Quickstart06
Install, init, track.
$ pnpm add @ingestlayer/sdk
$ echo "INGESTLAYER_KEY=il_…" >> .env
# in your app code:
import { init, track } from "@ingestlayer/sdk";
init({ apiKey: process.env.INGESTLAYER_KEY! });
track({ type: "user.signup", payload: { email: user.email } });