Skip to main content

Overview

The hooks ingest endpoint receives telemetry events from the Promptster CLI and MCP server. This is the primary path through which session data enters Promptster. The CLI handles this automatically when a candidate runs promptster start — you only need to call this endpoint directly if you are building a custom integration. Each call to POST /v1/hooks/ingest delivers a single event. The server normalizes the event kind, upserts the session, appends the event to the timeline, and enqueues background analytics jobs.

Ingest an event

POST /v1/hooks/ingest Authentication: X-API-Key header with a valid candidate key (PST-XXXX-XXXX). Rate limit: 100 requests per minute per API key.
Sessions are created automatically on first event ingest. You do not need to create a session before sending events.

Event envelope

id
string (UUID)
required
Stable event ID. Re-posting an event with the same id is safe — the duplicate is silently ignored (idempotent).
sessionId
string
required
The session this event belongs to. Sessions are created on-demand the first time a new sessionId is seen.
ts
string (ISO-8601)
required
Event timestamp, including timezone offset (e.g. 2026-04-01T10:15:00Z).
kind
string
required
Event type. See canonical kinds below.
source
object
required
Metadata about where the event originated.
actor
object
The actor that triggered the event.
provenance
object
Attribution metadata for this event.
v
integer
required
Schema version. Use 1.
data
object
required
Event-specific payload. Schema requirements vary by kind — see the table below.

Responses

  • 201 — Event accepted. Returns { ok: true, id: "<event-id>" }.
  • 200 — Event was a duplicate (same id was already processed). Returns { ok: true, skipped: true }.
  • 400 — Invalid event envelope or strict schema validation failed for the event kind.
  • 401 — Missing or invalid X-API-Key.
  • 429 — Rate limit exceeded (100 req/min per key).

Canonical event kinds

Every event you send must have a kind from this list. The data payload requirements differ by kind.
Strict payload schemas are enforced for command, file_diff, file_create, test_run, git_action, and checkpoint. All other kinds accept any data payload.
KindRequired data fieldsNotes
prompttext, tokenCountAI prompt sent by the candidate
ai_responseResponse from the AI tool
file_diffpathdiff, linesAdded, linesRemoved are optional but recommended
file_createpathcontent, linesAdded, sizeBytes are optional
file_delete
commandcommandexitCode, durationMs, stdout, stderr optional
test_runsuite, passed, failed, skipped, durationMs optional
build_run
git_actionactionref, message, commit optional
decision_eventtitle, chosenOption, context, tradeoffs, rationale, impactScore are indexed by the reviewer dashboard
session_startcwd and assessmentId in data are auto-promoted into session metadata
session_endTriggers session finalization and scoring pipeline
checkpointlabel, trigger, summary optional
tool_use
tool_resulttool_call is accepted as a legacy alias and normalized to tool_result
planning
mcp_call
For decision_event, the following data fields are indexed in the decisions table and surfaced in the reviewer dashboard:
FieldTypeDescription
titlestringShort description of the decision
chosenOptionstringThe option the candidate selected
contextstringBackground and constraints
tradeoffsstringAlternatives considered
rationalestringReasoning for the chosen option
impactScoreinteger (1–5)Estimated impact of the decision

Example: ingest a command event

curl -X POST https://api.promptster.ai/v1/hooks/ingest \
  -H "X-API-Key: PST-ABCD-1234" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "01234567-89ab-cdef-0123-456789abcdef",
    "sessionId": "my-session-uuid",
    "ts": "2026-04-01T10:15:00Z",
    "kind": "command",
    "source": {
      "channel": "cli",
      "integration": "shell",
      "emitter": "promptster-hook"
    },
    "actor": { "type": "human" },
    "provenance": {
      "attribution": "likely_human",
      "confidence": 0.9,
      "observability": "high"
    },
    "v": 1,
    "data": {
      "command": "pnpm test",
      "exitCode": 0,
      "durationMs": 4200
    }
  }'

Example: ingest a decision event

curl -X POST https://api.promptster.ai/v1/hooks/ingest \
  -H "X-API-Key: PST-ABCD-1234" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "aaaabbbb-cccc-dddd-eeee-ffffffffffff",
    "sessionId": "my-session-uuid",
    "ts": "2026-04-01T11:02:00Z",
    "kind": "decision_event",
    "source": { "channel": "mcp", "integration": "claude-code", "emitter": "promptster-mcp" },
    "actor": { "type": "human" },
    "provenance": { "attribution": "likely_human", "confidence": 0.95, "observability": "high" },
    "v": 1,
    "data": {
        "title": "Use JSONB for event payloads over a typed columns approach",
        "chosenOption": "JSONB payload column",
        "context": "Event schema is still evolving across multiple integrations",
        "tradeoffs": "Harder to query individual fields without GIN indexes",
        "rationale": "Avoids migrations as schema changes; read performance is acceptable for our access patterns",
      "impactScore": 4
    }
  }'