Custom Events#
Create custom event types to track application-specific data alongside messaging events.
Overview#
While Outeract automatically creates events for messages, you can create custom events for:
- Order updates
- Payment confirmations
- Support ticket status
- User actions
- System events
Naming Rules#
Custom events can use any valid name - no special prefix required.
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.*
Examples#
order.created
payment.completed
support.ticket.opened
subscription.upgraded
purchase
analytics.page_view**Convention:** Many apps use a prefix like `order.*` or `support.*` to namespace events by domain. This is recommended but not required.
Creating Custom Events#
GraphQL#
mutation CreateCustomEvent {
createEvent(
eventType: "order.created"
payload: {
order_id: "order_12345"
customer_id: "cust_xyz"
total: 99.99
currency: "USD"
items: [
{ sku: "WIDGET-001", quantity: 2, price: 49.99 }
]
}
edges: [
{
edgeType: "placed_by"
targetNodeType: PLATFORM_USER
targetNodeId: "pu_abc123"
}
]
) {
id
eventType
payload
createdAt
edges {
edgeType
targetNodeType
}
}
}REST#
curl -X POST https://api.outeract.com/v1/events \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_type": "order.created",
"payload": {
"order_id": "order_12345",
"total": 99.99
},
"edges": [
{
"edge_type": "placed_by",
"target_node_type": "platform_user",
"target_node_id": "pu_abc123"
}
]
}'Event Schemas#
Define schemas to validate custom event payloads.
Create Schema#
mutation CreateOrderSchema {
createEventSchema(
name: "order.created"
description: "Order creation event"
jsonSchema: {
type: "object"
required: ["order_id", "total"]
properties: {
order_id: {
type: "string"
pattern: "^order_[a-zA-Z0-9]+$"
}
total: {
type: "number"
minimum: 0
}
currency: {
type: "string"
enum: ["USD", "EUR", "GBP"]
default: "USD"
}
items: {
type: "array"
items: {
type: "object"
properties: {
sku: { type: "string" }
quantity: { type: "integer", minimum: 1 }
price: { type: "number" }
}
}
}
}
}
enforceValidation: true
) {
id
name
}
}Schema Validation#
When enforceValidation: true, events that don’t match the schema are rejected:
{
"errors": [
{
"message": "Validation failed: 'total' is required",
"extensions": {
"code": "VALIDATION_ERROR",
"path": ["payload", "total"]
}
}
]
}Querying Custom Events#
By Event Type#
query {
events(
filters: {
eventType: { equals: "order.created" }
}
first: 20
) {
edges {
node {
id
payload
createdAt
}
}
}
}By Payload Field#
query {
events(
filters: {
eventType: { startsWith: "order" }
payload: {
path: "total"
gte: 100
}
}
) {
edges {
node {
id
payload
}
}
}
}With Related Entities#
query {
events(
filters: {
eventType: { equals: "order.created" }
hasEdge: {
edgeType: "placed_by"
targetNodeId: { equals: "pu_abc123" }
}
}
) {
edges {
node {
id
payload
edges {
edgeType
targetPlatformUser {
externalId
name
}
}
}
}
}
}Linking Events#
Link to User#
mutation {
createEvent(
eventType: "support.ticket.opened"
payload: {
ticket_id: "ticket_123"
subject: "Help with order"
priority: "high"
}
edges: [
{
edgeType: "opened_by"
targetNodeType: PLATFORM_USER
targetNodeId: "pu_abc123"
}
]
) {
id
}
}Link to Previous Event#
mutation {
createEvent(
eventType: "order.shipped"
payload: {
order_id: "order_12345"
tracking_number: "1Z999AA10123456784"
}
originEventId: "evt_order_created_123"
) {
id
originEvent {
id
eventType
}
}
}Link to File#
mutation {
createEvent(
eventType: "document.uploaded"
payload: {
document_type: "invoice"
document_number: "INV-2024-001"
}
edges: [
{
edgeType: "attachment"
targetNodeType: FILE
targetNodeId: "file_xyz789"
}
]
) {
id
}
}Subscribing to Custom Events#
Webhook Subscription#
mutation {
createWebhookSubscription(
name: "Order Events"
targetUrl: "https://myapp.com/webhooks/orders"
eventPatterns: ["order.*"]
secret: "webhook-secret"
) {
id
}
}Webhook Payload#
{
"id": "whd_abc123",
"event_id": "evt_xyz789",
"event_type": "order.created",
"payload": {
"order_id": "order_12345",
"total": 99.99,
"currency": "USD"
},
"edges": {
"placed_by": {
"platform_user_id": "pu_abc123",
"external_id": "+14155551234"
}
},
"created_at": "2024-01-15T10:30:00Z"
}Use Cases#
E-commerce Integration#
# When order is placed
async def create_order_event(order, platform_user_id):
await client.execute("""
mutation CreateOrderEvent($payload: JSON!, $platformUserId: UUID!) {
createEvent(
eventType: "order.created"
payload: $payload
edges: [{
edgeType: "placed_by"
targetNodeType: PLATFORM_USER
targetNodeId: $platformUserId
}]
) { id }
}
""", {
"payload": {
"order_id": order.id,
"total": order.total,
"items": order.items
},
"platformUserId": platform_user_id
})
# When order ships
async def create_shipped_event(order, original_event_id):
await client.execute("""
mutation CreateShippedEvent($payload: JSON!, $originId: UUID!) {
createEvent(
eventType: "order.shipped"
payload: $payload
originEventId: $originId
) { id }
}
""", {
"payload": {
"order_id": order.id,
"tracking_number": order.tracking
},
"originId": original_event_id
})Support Ticketing#
async def create_ticket_events(ticket, platform_user_id):
# Ticket opened
result = await client.execute("""
mutation {
createEvent(
eventType: "support.ticket.opened"
payload: {
ticket_id: "%s"
subject: "%s"
priority: "%s"
}
edges: [{
edgeType: "opened_by"
targetNodeType: PLATFORM_USER
targetNodeId: "%s"
}]
) { id }
}
""" % (ticket.id, ticket.subject, ticket.priority, platform_user_id))
return result["createEvent"]["id"]Analytics Events#
async def track_user_action(action, platform_user_id, metadata=None):
await client.execute("""
mutation TrackAction($eventType: String!, $payload: JSON!, $puId: UUID!) {
createEvent(
eventType: $eventType
payload: $payload
edges: [{
edgeType: "performed_by"
targetNodeType: PLATFORM_USER
targetNodeId: $puId
}]
) { id }
}
""", {
"eventType": f"analytics.{action}",
"payload": {
"action": action,
"timestamp": datetime.utcnow().isoformat(),
**(metadata or {})
},
"puId": platform_user_id
})Best Practices#
1. Consistent Naming#
Use a clear hierarchy: {domain}.{action} or {domain}.{subdomain}.{action}
2. Include Timestamps#
Add timestamps in payload for events with delayed processing.
3. Link Everything#
Use edges to connect events to users, files, and other events.
4. Define Schemas#
Create schemas for validation and documentation.
5. Use Origin Events#
Chain related events using originEventId.
6. Keep Payloads Focused#
Include relevant data, not entire objects.