n8n Event Data Reference¶
This document describes how WhiteLabelCRO Integration API events are structured and accessed in n8n workflows.
Event to API Mapping¶
The Integration API emits 10 event types. In n8n, you work directly with the API event structure.
| API Event Type | Description | Common Use Case |
|---|---|---|
client.created |
When a new client is enrolled | Send welcome email, create CRM record |
client.status_changed |
When client moves to different stage | Trigger stage-specific workflows |
lead.created |
When a new lead is captured | Add to nurture campaign |
invoice.created |
When invoice is generated | Send payment reminder |
invoice.status_changed |
When invoice payment status changes | Update accounting system |
payment.succeeded |
When payment processes successfully | Send receipt, update billing |
payment.failed |
When payment is declined | Alert finance team, retry payment |
affiliate.created |
When referral partner is added | Send onboarding materials |
document.uploaded |
When file is attached to record | Process document, extract data |
agreement.signed |
When e-signature is completed | Trigger post-signature workflow |
Event Envelope Structure¶
The Integration API returns events in this format:
{
"id": 12345,
"type": "client.created",
"createdUtc": "2026-01-28T10:30:00Z",
"companyId": 92,
"payload": {
"client_id": 5678,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com"
},
"metadata": {
"source": "web_portal",
"user_id": 42
}
}
Accessing Fields in n8n¶
Standard Fields (All Events)¶
Present in every event:
In n8n expressions:
- Event ID: {{ $json.id }}
- Event type: {{ $json.type }}
- Timestamp: {{ $json.createdUtc }}
- Company ID: {{ $json.companyId }}
Payload Fields¶
Payload structure varies by event type. Access using dot notation:
Examples:
- Client ID: {{ $json.payload.client_id }}
- First name: {{ $json.payload.first_name }}
- Email: {{ $json.payload.email }}
- Invoice amount: {{ $json.payload.amount }}
- Payment status: {{ $json.payload.invoice_status }}
See the Event Catalog (/03-events/event-catalog.md) for complete field definitions per event type.
Metadata Fields¶
Optional context provided with some events:
- Source:
{{ $json.metadata.source }} - User ID:
{{ $json.metadata.user_id }}
Field Naming Conventions¶
Common Field Patterns¶
Across all event types:
- IDs: client_id, employee_id, affiliate_id, invoice_id, payment_id
- Status fields: status, previous_status, new_status, invoice_status
- Date fields: created_date, changed_date, signed_date, due_date (ISO 8601 strings)
- Person fields: first_name, last_name, full_name, email, phone
Handling Nested Data¶
For nested objects (if present):
{
"payload": {
"address": {
"street": "123 Main St",
"city": "Springfield"
}
}
}
Access in n8n:
- Street: {{ $json.payload.address.street }}
- City: {{ $json.payload.address.city }}
Array Handling¶
If the payload contains arrays:
{
"payload": {
"tags": ["vip", "high_priority"]
}
}
Access in n8n:
- First tag: {{ $json.payload.tags[0] }}
- All tags: {{ $json.payload.tags }}
- Iterate: Use Split In Batches or Loop Over Items node
Working with Event Data¶
Routing by Event Type¶
Use Switch node to route based on event type:
Add case:
- Mode: Expression
- Value: {{ $json.type }}
- Cases: client.created, payment.succeeded, etc.
Or use IF node:
{{ $json.type === 'client.created' }}
Extracting Specific Fields¶
Use Set node to create simplified data structure:
Example:
{
"clientId": "{{ $json.payload.client_id }}",
"fullName": "{{ $json.payload.first_name }} {{ $json.payload.last_name }}",
"email": "{{ $json.payload.email }}"
}
Handling Missing Fields¶
Some optional fields may be null. Use default values:
{{ $json.payload.phone || 'No phone provided' }}
{{ $json.payload.affiliate_id !== null ? $json.payload.affiliate_id : 'None' }}
Or use IF node to check existence:
{{ $json.payload.phone !== null }}
Field Type Handling¶
Date/Time Fields¶
- API returns: ISO 8601 strings (e.g.,
2026-01-28T10:30:00Z) - In n8n: Use Date & Time nodes to parse and format
- Access as string:
{{ $json.createdUtc }} - Parse to date: Use Date & Time node with "Parse Date" operation
Boolean Fields¶
- API returns:
trueorfalse(JSON boolean) - In n8n expressions:
{{ $json.payload.is_approved }} - In conditions:
{{ $json.payload.is_approved === true }}
Numeric Fields¶
- IDs: Always integers (e.g.,
client_id: 5678) - Amounts: May be decimal (e.g.,
amount: 99.99) - Access:
{{ $json.payload.amount }} - Math operations:
{{ $json.payload.amount * 1.1 }}
Null/Missing Fields¶
- If a field is null or absent:
{{ $json.payload.field }}returns null - Check for null:
{{ $json.payload.field !== null }} - Optional fields may not appear in every event
Debugging Event Data¶
View Full Event Structure¶
- Add Edit Fields or Code node after webhook/HTTP node
- Log full event:
console.log(JSON.stringify($input.all(), null, 2)) - Check execution data in n8n UI
Common Issues¶
Undefined field errors: - Field doesn't exist for this event type - Check Event Catalog for event-specific fields - Use optional chaining or null checks
Type mismatch:
- Ensure numeric fields aren't treated as strings
- Use parseInt() or parseFloat() if needed
- Check field type in API response
JSON Processing¶
Parsing Full Payload¶
If you need to process the entire payload programmatically:
// In Code node
const event = $input.first().json;
const payload = event.payload;
// Process fields
const result = {
id: event.id,
type: event.type,
clientName: `${payload.first_name} ${payload.last_name}`,
email: payload.email
};
return result;
Transforming Data¶
Use Code node for complex transformations:
const events = $input.all().map(item => {
const data = item.json;
return {
eventId: data.id,
clientId: data.payload.client_id,
timestamp: new Date(data.createdUtc).toISOString(),
source: data.metadata?.source || 'unknown'
};
});
return events;
Performance Considerations¶
Minimize Expression Complexity¶
For repeatedly accessed fields, use Set node to extract once:
Instead of:
{{ $json.payload.client_id }}
{{ $json.payload.client_id }}
{{ $json.payload.client_id }}
Do:
{
"clientId": "{{ $json.payload.client_id }}"
}
Then reference: {{ $json.clientId }}
Batch Processing¶
For high-volume workflows: 1. Use Split In Batches to process events in groups 2. Aggregate before external API calls 3. Cache frequently accessed data
Version Stability¶
Current Implementation¶
The Integration API uses v1 (/api/v1/...). Event structures are stable within v1.
Backward Compatibility¶
Event payload structures are stable within v1: - New fields may be added (non-breaking) - Existing fields will not change type or be removed - Always check for field existence before accessing
If a v2 API is introduced in the future, migration guidance will be provided in advance.
Related Documentation¶
- Event Catalog - Complete field definitions per event type
- Event Delivery Model - Delivery guarantees and retry behavior
- Events API - Polling implementation details
- Webhooks API - Webhook subscription management