Build
Define the event before ingestion
Register an organization contract with type and required_fields, then send the matching payload version.
Prerequisites
You need a verified signed-in user session, membership in the target organization, and a stable event name. Event types are lowercase dotted text, contain only lowercase letters, digits, underscores, and dots, and are at most 120 characters.
Working flow
1. Name a completed fact
acme.deployment_completed
sales.opportunity_closed
user.signup_verifiedKeep changing values such as customer identifiers, versions, and dates in the payload rather than in type.
2. Register the organization contract
Use Dashboard → Contracts. The dashboard sends a session-authenticated, CSRF-protected request to POST /organizations/:organization_id/event-contracts.
Option A: Full JSON Schema validation (recommended)
{
"type": "acme.deployment_completed",
"version": 1,
"description": "A service deployment completed",
"required_fields": ["service", "version", "environment", "status"],
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["service", "version", "environment", "status"],
"properties": {
"service": { "type": "string", "minLength": 1 },
"version": { "type": "string" },
"environment": { "type": "string", "enum": ["production", "staging", "sandbox"] },
"status": { "type": "string", "enum": ["healthy", "degraded", "failed"] }
},
"additionalProperties": false
}
}When schema is provided, the API validates payloads against the full JSON Schema (type checks, enum, pattern, nested objects, additionalProperties).
Option B: Required fields only
{
"type": "acme.deployment_completed",
"version": 1,
"description": "A service deployment completed",
"required_fields": ["service", "version", "environment", "status"]
}Without a schema, only top-level field presence is enforced.
3. Emit the matching version
import type {
UseEventStackClient,
UseEventStackEnvironment,
} from '@useeventstack/sdk';
export async function sendDeployment(useeventstack: UseEventStackClient) {
const environment: UseEventStackEnvironment = 'sandbox';
return useeventstack.events.emit({
type: 'acme.deployment_completed',
environment,
schemaVersion: 1,
payload: {
service: 'api',
version: '1.0.0',
environment,
status: 'healthy',
},
});
}There are no built-in event types and no event catalogue in the SDK. The name is entirely yours — acme. above is just a namespace, use whatever your domain calls the fact. The SDK accepts any lowercase dotted name and takes your payload type as a type argument; the registered organization contract is the runtime check.
Expected response
Contract registration returns the active organization record:
{
"id": "…",
"organization_id": "…",
"type": "acme.deployment_completed",
"version": 1,
"description": "A service deployment completed",
"required_fields": ["service", "version", "environment", "status"],
"status": "active",
"updated_at": "…"
}After that record exists, an event with metadata.schema_version: 1 and all four payload keys can pass contract validation.
Failure diagnosis
- Invalid event type: include at least one dot and use only the supported lowercase characters.
- Contract not registered: confirm organization,
type, and version all match the event. invalid_event_payload: inspecterror.details.fieldfor the missing top-level payload key.- Dashboard save rejected: confirm the account is verified and the session request includes the current CSRF token.
Validation modes
Event contracts support two validation modes:
- JSON Schema validation (recommended) — when a
schemafield is provided during contract registration, incoming payloads are validated against the full JSON Schema (Draft-07). This includes type checking, nested object validation, format constraints, enum enforcement, and pattern matching. - Required fields validation (legacy) — when only
required_fieldsis provided, the API checks that each listed field is present as a top-level payload key. No type or structure validation is performed.
A matching contract does not automatically create or trigger a workflow — workflows must be configured separately with a matching trigger_event.
Next step
Use the complete client setup in the TypeScript SDK guide, or return to the quickstart to verify the event in Activity.