Start
Register a contract, then send an event
Use the signed-in dashboard for organization setup, then use a sandbox API key for event ingestion.
Prerequisites
- Node.js 22 or newer
- A verified useEventStack account and organization; create an account if needed
- Permission to register an event contract and create an API key for that organization
Working flow
1. Register the organization contract while signed in
Open Dashboard → Contracts. The dashboard uses your user session and CSRF token to call the organization management route. Register this contract before making the API-key ingestion request:
{
"type": "deployment.completed",
"version": 1,
"description": "A service deployment completed",
"required_fields": [
"service",
"version",
"environment",
"status"
]
}Two access boundaries
Contract registration requires a verified signed-in user session. The API key used later is for event ingestion and cannot register the contract.
2. Create a sandbox API key
Open Dashboard → API keys. Create a key for sandbox with the events:write scope, then store the one-time value outside source control:
USEEVENTSTACK_API_KEY=useeventstack_replace_me
USEEVENTSTACK_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000
USEEVENTSTACK_API_BASE=https://api.useeventstack.com3. Install the TypeScript SDK
npm install @useeventstack/sdk4. Emit the complete payload
Create emit-event.ts. The environment is explicit on both the client request and the event payload:
import {
UseEventStackClient,
type UseEventStackEnvironment,
} from '@useeventstack/sdk';
function requiredEnv(name: 'USEEVENTSTACK_API_KEY' | 'USEEVENTSTACK_ORGANIZATION_ID'): string {
const value = process.env[name];
if (!value) throw new Error(`Missing ${name}`);
return value;
}
const environment: UseEventStackEnvironment = 'sandbox';
const useeventstack = new UseEventStackClient({
apiKey: requiredEnv('USEEVENTSTACK_API_KEY'),
organizationId: requiredEnv('USEEVENTSTACK_ORGANIZATION_ID'),
projectId: process.env.USEEVENTSTACK_PROJECT_ID ?? 'default',
baseUrl: process.env.USEEVENTSTACK_API_BASE ?? 'http://localhost:3001',
environment,
});
const receipt = await useeventstack.events.emit({
type: 'deployment.completed',
environment,
payload: {
service: 'api',
version: '1.0.0',
environment,
status: 'healthy',
},
idempotencyKey: 'deploy-api-1.0.0',
});
console.log(receipt.event.id, receipt.event.type);
console.log(receipt.idempotent_replay ?? false);npx tsx emit-event.tsExpected response
events.emit() resolves to an object with the stored event and an optional replay marker:
{
"event": {
"id": "01900000-0000-7000-8000-000000000000",
"type": "deployment.completed",
"organization_id": "00000000-0000-0000-0000-000000000000",
"metadata": {
"schema_version": 1,
"source": "api_key",
"trace_depth": 0,
"environment": "sandbox"
},
"payload": {
"service": "api",
"version": "1.0.0",
"environment": "sandbox",
"status": "healthy"
}
}
}Open Activity and select the sandbox environment to find the event.
Failure diagnosis
| Symptom | Check |
|---|---|
401 | The API key is present, current, and passed as a Bearer credential by the SDK. |
403 | The key has events:write and its assigned environment is sandbox. |
| Contract not registered | deployment.completed version 1 was saved for the same organization before ingestion. |
invalid_event_payload | All four required payload keys are present with the names shown above. |
| Event absent from Activity | The dashboard environment filter is set to sandbox and the selected organization matches the key. |
What storing an event does not do
A stored event does not by itself produce a workflow or projection result. Those outcomes require a matching enabled workflow and configured action. Verify the stored event first.
Next step
Read Authentication before adding UseEventStack to another service, then use Event contracts to define its payload boundary.