# Contact Updated Webhook

Webhook event triggered when an existing contact is updated in iClosed.io.

## Overview

The Contact Updated webhook is triggered whenever an existing contact's information is modified in your iClosed.io account. This event provides the complete updated contact object, including all current data and any changes that were made.

## Event Details

| Property | Value |
|  --- | --- |
| **Event Type** | `contactUpdated` |
| **Trigger** | When a contact's information is updated through any channel (form submission, manual edit, API, etc.) |
| **Payload** | Complete updated contact object with all current data |


## Webhook Payload

The HTTP body is a single JSON object (not an array). It contains the full updated contact object with the following structure:

```json
{
  "id": 239,
  "accountId": 4,
  "firstName": "Morgan",
  "lastName": "Name",
  "email": "morgan.lee@example.com",
  "phoneNumber": "+1 415 555 0192",
  "secondary_email": null,
  "secondary_phoneNumber": null,
  "status": "POTENTIAL",
  "createdAt": "2026-04-09T09:13:03.507Z",
  "previewId": "contact_We1Ztdhvcii0",
  "timeZone": "Asia/Karachi",
  "joinedTime": "2026-04-09T09:13:03.506Z",
  "country": "PK",
  "ipAddress": "::1",
  "updatedAt": "2026-04-09T09:14:19.108Z",
  "questionsAndAnswers": {
    "1_question": "Full Name",
    "1_response": "Morgan Lee",
    "Full Name": "Morgan Lee"
  },
  "contactFields": {},
  "updatedAttributes": [
    "Email"
  ],
  "event": {
    "id": 2,
    "name": "Strategy intro call",
    "color": "#0099FF",
    "linkPrefix": "acme/strategy-call",
    "eventType": "STRATEGY_EVENT",
    "disableDuplicateBooking": false
  },
  "tracking": {
    "first_utm_term": "strategy consultation",
    "first_utm_source": "google",
    "first_utm_medium": "cpc",
    "first_utm_content": "hero_cta_variant_b",
    "first_utm_campaign": "q2_2026_demo_requests",
    "utm_term": "sales scheduling software",
    "utm_source": "linkedin",
    "utm_medium": "paid_social",
    "utm_content": "carousel_ad_3",
    "utm_campaign": "b2b_outbound_apr",
    "utmKey_0": "gclid",
    "utmValue_0": "EAIaIQobChMIexampleValue123",
    "utmKey_1": "li_fat_id",
    "utmValue_1": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "utmKey_2": "referrer_domain",
    "utmValue_2": "newsletter.partner.io",
    "utmKey_3": "landing_path",
    "utmValue_3": "/events/strategy-call",
    "utmKey_4": "experiment_id",
    "utmValue_4": "exp_booking_flow_v2"
  },
  "Referrer_Url_Embed": "https://app.iclosed.io/e/acme/strategy-call",
  "previewUrl": "https://app.iclosed.io/app/global-data/contacts?preview=contact_We1Ztdhvcii0",
  "latestCall": null,
  "disqualifyingGroup": [],
  "dataIntelligence": {
    "credit": {
      "scoreLabel": null
    },
    "debtToIncome": {
      "dtiLabel": null
    },
    "qualification": {
      "leadType": null
    },
    "emailValidation": {
      "isValid": null
    },
    "phoneValidation": {
      "isValid": null,
      "country_code": null
    }
  },
  "hookType": "Contact updated"
}
```

## Key Differences from Contact Created

| Field | Behaviour |
|  --- | --- |
| `updatedAt` | Shows when the contact was last modified |
| `createdAt` | Remains the original creation timestamp (unchanged) |
| `joinedTime` | Original join timestamp (unchanged) |
| `updatedAttributes` | Array of fields that were modified in this update |
| `hookType` | Set to `"Contact updated"` to distinguish from creation events |


## Key Fields Explained

### Basic Contact Information

| Field | Description |
|  --- | --- |
| `id` | Unique contact identifier (unchanged) |
| `firstName`, `lastName` | Contact's name (may be updated) |
| `email` | Primary email address (may be updated) |
| `phoneNumber` | Primary phone number (may be updated) |
| `secondary_email`, `secondary_phoneNumber` | Additional contact methods |
| `status` | Contact qualification status (may change) |


### Event Information

The `event` object contains details about the event the contact was originally created from. This typically doesn't change unless the contact is moved to a different event.

| Field | Description |
|  --- | --- |
| `id` | Event identifier |
| `name` | Event name |
| `linkPrefix` | Event URL prefix |
| `color` | Event color code |
| `eventType` | Type of event (e.g., `"STRATEGY_EVENT"`) |
| `disableDuplicateBooking` | Whether duplicate bookings are blocked for this event |


### Questions and Answers

The `questionsAndAnswers` object contains all current form responses from the contact. It may include new or updated responses, and contains both a numbered format (`1_question`, `1_response`, etc.) and direct key-value pairs.

### Tracking Data

The `tracking` object contains UTM parameters and tracking information. It may be updated if new tracking data is available. Note that `first_utm_*` fields preserve the original first-touch attribution.

### Call information

`latestCall` is either an object for the most recent scheduled call or `null` if there is no call on the contact at this time.

### Custom contact fields

`contactFields` holds custom field values keyed by slug when present.

### Data intelligence

`dataIntelligence` mirrors the contact-created payload: optional enrichment blocks that may remain `null`.

### Disqualification logic

`disqualifyingGroup` lists current disqualification evaluations and may be empty when no rules apply.

## Use Cases

This webhook is useful for:

- **CRM Synchronization** – Keep your CRM updated with the latest contact information
- **Data Validation** – Verify that contact updates are properly processed
- **Audit Trails** – Track changes to contact information over time
- **Workflow Triggers** – Initiate follow-up actions when specific fields are updated
- **Analytics** – Monitor contact engagement and information changes
- **Lead Scoring Updates** – Re-evaluate contact quality based on new information


## Response Requirements

Your webhook endpoint should:

- Return a `2xx` status code to acknowledge receipt
- Respond within **5 seconds** to avoid retries
- Handle duplicate events (idempotency)
- Log the contact `id` and `updatedAttributes` for debugging
- Consider the `updatedAttributes` field to determine what changed


## Best Practices

1. **Check `updatedAttributes`** – Use this field to identify what specifically changed
2. **Compare with Previous State** – Store previous contact state to track changes
3. **Handle Partial Updates** – Not all fields may be present in every update
4. **Validate Changes** – Ensure the updated data meets your business rules
5. **Update Timestamps** – Use `updatedAt` to determine if you have the latest data