Events#
Events are the core data model in Outeract. Every message, status update, and action is represented as an immutable event, providing a complete audit trail of all activity.
Overview#
Outeract uses an event-sourced architecture where:
- All state changes are captured as events
- Events are immutable (never modified after creation)
- Current state is derived from the event stream
- Full history is always available
flowchart LR
subgraph Stream["Event Stream"]
E1["message.inbound<br/>t=0"] --> E2["message.outbound<br/>t=1"]
E2 --> E3["message.delivered<br/>t=2"]
E3 --> E4["message.read<br/>t=3"]
E4 --> More["..."]
endEvent Model#
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
app_id | UUID | Application this event belongs to |
event_type_id | UUID | Reference to EventSchema |
status | string | pending, processing, completed, failed |
payload | JSON | Event-specific data |
origin_event_id | UUID | Parent event (for status updates) |
processed_at | datetime | When the event was processed |
created_at | datetime | When the event was created |
Event Types#
Events are categorized by type. Built-in types follow a hierarchical naming convention:
Message Events#
message.inbound - Incoming message from a user
message.outbound - Outgoing message to a userPayload Structure:
{
"type": "message",
"message": {
"text": "Hello, world!",
"role": "user"
},
"platform": "whatsapp",
"external_message_id": "wamid.xxx",
"created_at": "2024-01-15T10:30:00Z",
"sent_at": "2024-01-15T10:30:01Z",
"delivered_at": "2024-01-15T10:30:02Z",
"read_at": null,
"failed_at": null
}Link Code Events#
link_code.generated - A link code was created
link_code.activation - A link code was usedGeneration Payload:
{
"code": "1234-5678-9012-3456",
"expiry_minutes": 15,
"max_uses": 1,
"uses": 0,
"generated_by_platform_user_id": "pu_abc123"
}User Events#
user.merged - Two user records were mergedCustom Events#
You can define custom event types using any valid name. Event type names must:
- Use lowercase letters, numbers, dots, and underscores only
- Match the pattern:
^[a-z0-9_.]+$ - Not use reserved prefixes:
message.*,user.*,system.*,link_code.*
order.created
payment.completed
support.ticket.opened
purchase
subscription.renewedEvent Relationships#
Events are connected to other entities via edges:
flowchart TB
Event["Event<br/>(message.inbound)"]
Event --> SB["sent_by edge"]
Event --> ST["sent_to edge"]
Event --> AT["attachment edge"]
SB --> PU["Platform User"]
ST --> SU["System User"]
AT --> F["File"]Querying Events#
Get Recent Events#
query {
events(first: 20) {
edges {
node {
id
eventType
payload
status
createdAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}Filter by Event Type#
query {
events(
filters: {
eventType: { contains: "message" }
}
first: 50
) {
edges {
node {
id
eventType
payload
}
}
}
}Filter by Date Range#
query {
events(
filters: {
createdAt: {
gte: "2024-01-01T00:00:00Z"
lte: "2024-01-31T23:59:59Z"
}
}
) {
edges {
node {
id
eventType
createdAt
}
}
}
}Get Events with Edges#
query {
events(
filters: { eventType: { equals: "message.inbound" } }
first: 10
) {
edges {
node {
id
eventType
payload
edges {
edgeType
targetPlatformUser {
id
externalId
}
}
}
}
}
}Creating Events#
Via Message API#
When you send a message, an event is automatically created:
mutation {
sendMessage(
platformConnectionId: "pc_abc123"
toExternalId: "+14155551234"
message: "Hello!"
) {
id
status {
success
}
}
}This creates a message.outbound event with appropriate edges.
Custom Events#
Create custom events for your application:
mutation {
createEvent(
eventType: "order.created"
payload: {
order_id: "order_12345"
total: 99.99
currency: "USD"
}
) {
id
eventType
payload
}
}Event Status#
Events have a lifecycle status:
| Status | Description |
|---|---|
pending | Event created, not yet processed |
processing | Currently being processed |
completed | Successfully processed |
failed | Processing failed |
Status Updates#
Status updates create child events linked via origin_event_id:
flowchart TB
Parent["message.outbound<br/>id: evt_001<br/>status: completed"]
Parent -->|origin_event_id| Delivered["delivered status<br/>evt_002"]
Parent -->|origin_event_id| Read["read status<br/>evt_003"]
Parent -->|origin_event_id| Failed["failed status"]Query status updates:
query {
event(id: "evt_001") {
id
eventType
childEvents {
id
eventType
payload
}
}
}Event Schemas#
Event types are defined by EventSchemas:
query {
eventSchemas {
id
name
jsonSchema
enforceValidation
isGlobal
}
}Built-in (Global) Schemas#
Global schemas are available to all applications:
message.inboundmessage.outboundlink_code.generatedlink_code.activation
Custom Schemas#
Define custom event types with JSON Schema validation:
mutation {
createEventSchema(
name: "order.created"
jsonSchema: {
type: "object"
required: ["order_id", "total"]
properties: {
order_id: { type: "string" }
total: { type: "number", minimum: 0 }
currency: { type: "string", enum: ["USD", "EUR", "GBP"] }
}
}
enforceValidation: true
) {
id
name
}
}Event Subscriptions (Webhooks)#
Subscribe to events via outbound webhooks:
mutation {
createWebhookSubscription(
name: "My Webhook"
targetUrl: "https://myapp.com/webhooks/outeract"
eventPatterns: ["message.inbound", "order.*"]
secret: "my-webhook-secret"
) {
id
name
}
}When matching events occur, Outeract POSTs to your URL:
{
"event_id": "evt_abc123",
"event_type": "message.inbound",
"app_id": "app_xyz789",
"payload": {
"message": { "text": "Hello!" }
},
"edges": {
"sent_by": {
"platform_user_id": "pu_123",
"external_id": "+14155551234"
}
},
"created_at": "2024-01-15T10:30:00Z"
}Best Practices#
1. Use Event Types Consistently#
Follow the category.action naming convention for custom events.
2. Include Relevant Data in Payloads#
Store enough context in the payload to understand the event without external lookups.
3. Don’t Store Sensitive Data#
Avoid putting passwords, tokens, or PII in event payloads.
4. Use Edges for Relationships#
Link events to users and files via edges, not payload fields.
5. Handle Idempotency#
Events may be delivered multiple times. Use external_message_id for deduplication.
Related Concepts#
- Edges - Relationships between events and entities
- Users - How users relate to events
- Event Types Reference - Complete list of built-in types