# Webhook Payload Format

> Source: https://docs.trailspark.ai/docs/webhook-payload-format

## Basic Structure

```json
{
  "email": "lead@example.com",
  "event": "event_name",
  "properties": {
    "key": "value"
  }
}
```

## Field Reference

No single field is strictly required for the webhook to accept a payload. However, for a signal to be processed into a lead, at least one persistent identifier must be present.

### Identifying Fields

At least one of these should be present for the signal to create or match a lead:

| Field | Type | Description |
|-------|------|-------------|
| **email** | string | Lead's email address. Primary identifier for matching signals to leads. Case-insensitive. Can appear at top level, in `traits`, `properties`, or `context.traits` |
| **userId** | string | Your internal user identifier (product user ID) |
| **anonymousId** | string | Anonymous visitor identifier (for identity resolution). Not sufficient alone to create a lead, but enables cold storage rehydration when later identified |

### Recommended

| Field | Type | Description |
|-------|------|-------------|
| **event** | string | Event name (e.g., `form_submission`, `page_view`, `demo_request`) |
| **type** | string | Segment event type (`track`, `page`, `identify`). Used for source auto-detection |
| **properties** | object | Event-specific data |

### Optional

| Field | Type | Description |
|-------|------|-------------|
| **timestamp** | string | ISO 8601 timestamp (e.g., `2024-01-15T14:30:00Z`). Defaults to receipt time if omitted |
| **source** | string | System that generated the signal (overrides auto-detection) |
| **traits** | object | User traits (common in Segment identify calls) |
| **context** | object | Contextual metadata (page info, device, etc.) |

## Payload Examples

### Form Submission

```json
{
  "email": "prospect@company.com",
  "event": "form_submission",
  "timestamp": "2024-01-15T11:15:00Z",
  "properties": {
    "form_name": "Request Demo",
    "form_id": "demo-form-main",
    "page_url": "https://yoursite.com/demo",
    "company": "TechCorp",
    "company_size": "100-500",
    "job_title": "Marketing Director"
  }
}
```

### Page View

```json
{
  "email": "visitor@example.com",
  "event": "page_view",
  "properties": {
    "page_url": "https://yoursite.com/pricing",
    "page_title": "Pricing - Your Product",
    "referrer": "https://google.com",
    "time_on_page": 45
  }
}
```

### Product Trial Signup

```json
{
  "email": "newuser@startup.io",
  "event": "trial_started",
  "properties": {
    "plan": "pro_trial",
    "trial_length_days": 14,
    "signup_source": "website",
    "company": "StartupIO"
  }
}
```

## How Properties Map to Signal Rules

Signal mapping rules can access any field using dot notation:

| Example Condition | Matches |
|-------------------|---------|
| `event` equals `demo_request` | Signals with event "demo_request" |
| `properties.company_size` equals `Enterprise` | Enterprise company signals |
| `properties.page_url` contains `/pricing` | Pricing page activity |

Design your payload structure with your signal mapping rules in mind. Consistent field names across sources simplify rule creation.

## Validation

| Rule | Requirement |
|------|-------------|
| JSON | Valid JSON syntax |
| Content-Type | Must be `application/json` |
| Encoding | UTF-8 |

The universal webhook is lenient with payload structure. If payload standardization fails, the raw payload is stored as-is with event type defaulting to the `type` or `event` field, or `"universal"` if neither is present.

## Next Steps

- [Webhook Configuration](/docs/webhook-configuration)
- [API Keys](/docs/api-keys)
- [Creating Signal Mapping](/docs/creating-signal-mapping)