Skip to main content

Send your first events

Before the batch upload, prove the streaming path works: send two events for one user through the ingestion endpoint, then read them back from the entity's timeline.

Two things happen on first contact that matter for the rest of the quickstart:

  • the entity type user is auto-registered for your project the first time an event about a user flows through the stream — step 4's label definition requires a registered entity type. Batch syncs perform the same registration for every type their mapping produces before committing, but this step proves the streaming path independently;
  • idempotency is on from the start: the event_id you supply makes any retry of the same fact a no-op.
01-first-events.sh
#!/usr/bin/env bash
# Quickstart step 1 — send your first events through the ingestion API.
# Works against any Tessera deployment: only the environment changes.
set -euo pipefail

: "${TESSERA_API_BASE:?e.g. https://api.staging.tessera.zone/v1}"
: "${TESSERA_INGEST_BASE:?e.g. https://ingest.staging.tessera.zone/v1}"
: "${TESSERA_API_KEY:?your tsk_test_… key}"

NOW="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

# Two events for one user. `event_id` makes retries idempotent: sending the
# same batch twice can never double-count (the Idempotency-Key header
# additionally dedupes the whole HTTP request).
curl -sS -X POST "$TESSERA_INGEST_BASE/events" \
-H "Authorization: Bearer $TESSERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-first-events" \
-d '{
"events": [
{
"event_id": "hello-0001",
"entity": {"type": "user", "id": "u_hello_1"},
"event_type": "order.placed",
"timestamp": "'"$NOW"'",
"attributes": {"order_value": 42.5, "item_count": 2, "category": "apparel"}
},
{
"event_id": "hello-0002",
"entity": {"type": "user", "id": "u_hello_1"},
"event_type": "support.ticket_opened",
"timestamp": "'"$NOW"'",
"attributes": {"ticket_topic": "delivery"}
}
]
}' | python3 -m json.tool

# Acceptance means durably enqueued; within a couple of seconds the events
# appear on the entity's timeline.
for _ in $(seq 1 30); do
TIMELINE="$(curl -sS "$TESSERA_API_BASE/entities/user/u_hello_1/events" \
-H "Authorization: Bearer $TESSERA_API_KEY")"
COUNT="$(printf '%s' "$TIMELINE" | python3 -c 'import json,sys; print(len(json.load(sys.stdin)["data"]))')"
if [ "$COUNT" -ge 2 ]; then break; fi
sleep 1
done

echo "$TIMELINE" | python3 -m json.tool
echo "timeline events for u_hello_1: $COUNT"

Download quickstart/01-first-events.sh — this exact file runs in CI on every change (hosts shown are for this environment).

The POST /events response tells you the batch was durably enqueued (accepted), not that every event passed every check — contract-level violations found downstream land in your project's dead-letter view, replayable after you fix the cause. Within a couple of seconds the events are on the timeline: that read (GET /entities/user/u_hello_1/events) comes from the per-entity ledger that scoring will later replay.

Next: upload the historical data.