Architecture#
Junction has a single ingest entrypoint. Events are the central object — every inbound request is logged against an event type, and any destination subscribed to that event type receives a copy. Destinations are managed independently of the systems that produce events. If nothing is subscribed, the request is still logged; it’s just a no-op for delivery.
Every request is assigned a trace ID that persists across the entire lifecycle — from ingest, through queue processing, to a final delivery status per destination.
Ingest#
POST /relay| Header | Required | Description |
|---|---|---|
X-Junction-Token |
Yes | API token for authentication. 401 if missing or invalid. |
X-Junction-Event |
Yes | Event type identifier, e.g. do.something. 400 if missing or invalid. |
X-Junction-Trace-ID |
No | Caller-supplied UUIDv4 trace ID. Generated if absent. |
The request body is a JSON object with the caller’s data nested under a payload key: { "payload": { ... } }. Junction never inspects payload for routing — it’s forwarded to destinations exactly as received. See the API reference
for the full request/response contract.
Ingest flow#
POST /relay
│
▼
Validate X-Junction-Token → 401 if missing or invalid
│
▼
Validate X-Junction-Event → 400 if missing or malformed
│
▼
Resolve trace ID (caller-supplied or generated)
│
▼
Resolve or create the event record for this event type
│
▼
Log the inbound request (event_logs)
│
▼
Resolve subscribed destinations for this event type
│
▼
Log a delivery binding per destination, status: pending
│
▼
Build a queue envelope per destination
│
▼
Route each envelope to its destination type's queue
│
▼
Return X-Junction-Trace-ID to the caller (202 Accepted)Delivery is asynchronous — the response only confirms the event was accepted and routed, not that it was delivered. The trace ID is the caller’s handle for tracking the full delivery lifecycle via the management API .
Dispatch flow#
Destination-type queue (e.g. junction.destinations.http)
│
▼
Destination worker picks up the message
│
▼
Delivers the payload to the destination
│
▼
Reports delivery status back to the API (worker token)
│
▼
API updates the delivery binding → dispatched or erroredWorkers have no database access and no knowledge of the API’s internal schema — only the delivery contract (queue envelope in, status report out). See Components for what each service is responsible for.
Queue envelope#
One message is produced per destination, so a single event with N subscribed destinations produces N independent messages — each can be delivered, retried, and fail in isolation.
{
"payload": "<the original request body, untouched>",
"meta": {
"trace_id": "<UUIDv4>",
"log_id": "<delivery binding ID>",
"destination": {
"type": "http",
"config": { "...": "destination-type-specific configuration" }
}
}
}payload is the caller’s data and is never modified. meta is the platform envelope and is never forwarded to the destination itself. log_id lets the worker report status with a direct reference — no lookup required.
Data model#
events — registry of known event types, resolved or created on first sight at ingest, or explicitly when a destination subscribes to a new event type.
event_logs — one record per inbound request: payload, source IP, trace ID, and the event type it was logged against.
destinations — independently managed routing targets. Each has a type (drives the shape of its config), a status (active/disabled), and its own event subscription set.
destination_types — defines what destination types exist (e.g. http), which queue they consume from, and a config_schema used to validate a destination’s config at create/update time. New types are added by registering a new destination type record — no schema or code changes required. See Destination Types
.
destination_events — pivot table: which destinations are subscribed to which event types. Queried at ingest to resolve who should receive an event.
event_log_destinations — the delivery binding between one inbound request and one subscribed destination. Carries the delivery state machine: pending → dispatched | errored, with the attempt timestamp and error detail if applicable.
Observability#
Every record and log line carries the trace ID, so a request’s full lifecycle can be reconstructed end-to-end:
- By event type — all inbound requests logged against an event type over time
- By request — every destination delivery attempt for one inbound request
- By destination — full delivery history and health for one destination
- By trace ID — the complete lifecycle of a single request, from HTTP ingest through queue processing to final delivery status
Any delivery in errored status is available for manual retry via the management API.