Skip to main content

Overview

We’ve expanded our webhook system with many new event types and a new event schema. This guide covers how to migrate from legacy webhooks to the new format.
Legacy webhooks only supported three campaign target events. The new system adds support for threads, messages, prospects, tags, statuses, and campaigns—all using a consistent dot notation format.

What’s changed

Event types

Legacy webhooks only supported three events in camelCase format:
  • targetContacted
  • targetFollowUpSent
  • targetReplied
The new system uses dot notation (resource.action) and adds many more event types. See the full event reference below.

Payload schema

The payload structure has changed significantly. The legacy format uses a flat structure with an external field, while the new format uses nested objects with a prospect field and additional context. Legacy format:
{
  "event": "targetContacted",
  "version": "1.0",
  "timestamp": "2025-01-15T12:00:00.000Z",
  "platform": "twitter",
  "data": {
    "team": { ... },
    "accountLink": { ... },
    "message": { ... },
    "external": {
      "id": "hzcai5t59nn9vsck3rbuepyg",
      "platformId": "1954360649393295360",
      "platform": "twitter",
      "displayName": "John Doe",
      "username": "johndoe",
      "image": "https://pbs.twimg.com/...",
      "data": { }
    },
    "thread": { ... },
    "campaign": { ... }
  }
}
New format:
{
  "id": "ck9v2m5nj0xp4wq7ybftrae8",
  "seq": 42,
  "teamId": "hzcai5t59nn9vsck3rbuepyg",
  "type": "target.contacted",
  "timestamp": "2025-01-15T12:00:00.000Z",
  "version": "1.0",
  "data": {
    "campaign": { ... },
    "thread": { ... },
    "message": { ... },
    "prospect": {
      "id": "hzcai5t59nn9vsck3rbuepyg",
      "platformId": "1954360649393295360",
      "platform": "twitter",
      "displayName": "John Doe",
      "username": "johndoe",
      "image": "https://pbs.twimg.com/...",
      "context": {
        "tags": [...],
        "status": { ... },
        "notes": "...",
        "valuation": 1000
      }
    }
  }
}
Key differences:
  • The external field is now prospect and includes full context (tags, status, notes, valuation)
  • New envelope fields: id, seq, teamId at the top level
  • The event field is now type
  • The platform field has moved from the top level into the data objects

Retry behavior

Legacy webhooks used aggressive retry logic (up to 10 retries over 24 hours). The new system attempts delivery once. Use the Events API to recover any missed events.

Events API

A new endpoint is available to replay missed events from the last 7 days:
GET /api/v1/events?afterSeq=0&limit=100
Parameters:
  • afterSeq - Return events after this sequence number (omit to start from the beginning)
  • limit - Maximum events to return (default: 100, max: 1000)
Response:
{
  "events": [
    {
      "id": "ck9v2m5nj0xp4wq7ybftrae8",
      "seq": 1,
      "teamId": "hzcai5t59nn9vsck3rbuepyg",
      "type": "target.contacted",
      "timestamp": "2025-01-15T12:00:00.000Z",
      "version": "1.0",
      "data": { ... }
    }
  ],
  "hasMore": true,
  "lastSeq": 100
}
Use lastSeq as the afterSeq parameter for subsequent requests to paginate through all events.

Migration steps

1. update your webhook handler

Since the schema is different, you’ll need to update your handler to process the new format. You can switch over at any time—disabling “Use legacy events” in your webhook configuration will immediately start sending the new format.
function handleEvent(event) {
  // New format
  if (event.type === "target.contacted") {
    const { campaign, thread, message, prospect } = event.data;
    // prospect.context contains tags, status, notes, valuation
  }
}

2. implement missed event recovery

Add a background job that periodically polls the Events API to catch any missed webhooks:
let lastSeq = await getStoredSequenceNumber(); // Persist this value

async function syncMissedEvents() {
  const response = await fetch(
    `https://api.inboxapp.com/v1/events?afterSeq=${lastSeq}&limit=1000`,
    { headers: { Authorization: `Bearer ${API_TOKEN}` } },
  );

  const { events, hasMore, lastSeq: newSeq } = await response.json();

  for (const event of events) {
    await processEvent(event); // Deduplicate using event.id
  }

  if (newSeq) {
    lastSeq = newSeq;
    await storeSequenceNumber(lastSeq);
  }

  if (hasMore) {
    await syncMissedEvents(); // Continue pagination
  }
}

3. update webhook configuration

Once your handler supports the new format, go to Settings → Webhooks and disable the “Use legacy events” option on your webhook configuration.

4. subscribe to new event types

With the new system, you can now subscribe to many more event types beyond the original three. Update your webhook configuration to include any additional events you want to receive.

Event reference

All available event types in the new system: Thread events
  • thread.created - A new thread was created
  • thread.deleted - A thread was deleted
  • thread.assigned - A thread was assigned to a team member
  • thread.unassigned - A thread was unassigned from a team member
  • thread.archived - A thread was archived
  • thread.unarchived - A thread was unarchived
  • thread.typing - Someone is typing in a thread
Message events
  • message.created - A new message was sent or received
  • message.edited - A message was edited
  • message.deleted - A message was deleted
  • message.reactionAdded - A reaction was added to a message
  • message.reactionRemoved - A reaction was removed from a message
Prospect events
  • prospect.created - A new prospect was added
  • prospect.statusChanged - A prospect’s pipeline status changed
  • prospect.tagsChanged - A prospect’s tags were updated
  • prospect.notesChanged - A prospect’s notes were updated
  • prospect.valuationChanged - A prospect’s valuation was updated
  • prospect.enriched - A prospect was enriched with additional data
Tag events
  • tag.created - A new tag was created
  • tag.updated - A tag was updated
  • tag.deleted - A tag was deleted
Status events
  • status.created - A new pipeline status was created
  • status.updated - A pipeline status was updated
  • status.deleted - A pipeline status was deleted
Campaign events
  • campaign.created - A new campaign was created
  • campaign.started - A campaign was started
  • campaign.paused - A campaign was paused
  • campaign.resumed - A campaign was resumed
  • campaign.completed - A campaign completed
Target events (previously the only events available)
  • target.contacted - A prospect was first contacted by a campaign (previously targetContacted)
  • target.followUpSent - A follow-up message was sent to a prospect (previously targetFollowUpSent)
  • target.replied - A prospect replied to a campaign message (previously targetReplied)

Need help?

If you have questions about migrating your webhooks, reach out to us at support@inboxapp.com.