ChatGenius Developer Events Markdown

Webhook Events

Every event ChatGenius can deliver to your endpoint: the shared envelope, the attachment shape, and all 14 event types with full-profile JSON examples.

Webhook & API Add-on · $29/month · Requires Creator+ plan

The envelope

Every event is posted as JSON with Content-Type: application/json, in one of two styles. Standard, which every endpoint created since July 2026 receives, wraps the event body: {"type", "timestamp", "data"}, and you read the fields from data.*. Legacy, for integrations created before July 2026, posts the flat body with no wrapper. Everything inside is identical between the two; the style is fixed per endpoint and shown on the endpoint in the portal.

The event type also rides in the X-SumGenius-Event request header on every delivery, and every delivery is signed: see verifying signatures. How much customer data is included is controlled by your payload profile (full or minimal).

Event body fields

  • event_idstring

    32-character hex id, unique per event and stable across retries; it is also the delivery id header. Use it to deduplicate.

  • event_typestring

    One of the 14 types in the index.

  • occurred_atUTC ISO-8601

    When the event happened on the platform.

  • source.platformenum

    facebook · instagram · sms · whatsapp · telegram

  • source.channelenum

    meta_dm · twilio_sms · whatsapp_cloud · telegram

  • conversation.idinteger | null

    ChatGenius conversation id; pass it to the Send API to reply. Can be null on the very first inbound message from a new person.

  • conversation.assigned_to / assigned_to_namefull profile only

    Team member id and name the conversation is assigned to, or null.

  • customer.platform_user_idstring

    Platform-assigned user id. Always present, on both profiles: your stable join key.

  • customer enrichmentfull profile only

    platform_user_name, platform_user_username, contact_id, tags, stage, custom_fields. custom_fields is a reserved placeholder that is always {}.

  • messageobject

    {id, text_raw, attachments[]}. Non-message events replace this block with their own (comment, appointment, lead, escalation, send_failed).

  • metaobject

    version (currently v1), payload_profile, generated_at.

Standard envelope · message.received
{
  "type":      "message.received",
  "timestamp": "2026-02-20T08:15:03Z",
  "data": {
    "event_id":    "a3f8e1c2d4b567890abcdef012345678",
    "event_type":  "message.received",
    "occurred_at": "2026-02-20T08:15:00Z",
    "source": {
      "platform": "instagram",
      "channel":  "meta_dm"
    },
    "conversation": {
      "id":               10482,
      "assigned_to":      90011,
      "assigned_to_name": "Anna"
    },
    "customer": {
      "platform_user_id":       "17841400123456789",
      "platform_user_name":     "Jane Doe",
      "platform_user_username": "janedoe",
      "contact_id":    555,
      "tags":          ["VIP", "Returning"],
      "stage":         "qualified",
      "custom_fields": {}
    },
    "message": {
      "id":          "mid.1234567890abcdef",
      "text_raw":    "Hi, do you have availability next Tuesday?",
      "attachments": []
    },
    "meta": {
      "version":         "v1",
      "payload_profile": "full",
      "generated_at":   "2026-02-20T08:15:00Z"
    }
  }
}
Legacy (flat) equivalent
{
  "event_id":    "a3f8e1c2d4b567890abcdef012345678",
  "event_type":  "message.received",
  "occurred_at": "2026-02-20T08:15:00Z",
  "source": {
    "platform": "instagram",
    "channel":  "meta_dm"
  },
  ...
}

Attachments

Media the customer sent arrives in message.attachments. Four fields are always present; the rest ride on the full profile only.

  • typestring

    Attachment category, e.g. image · audio · video.

  • media_typestring

    MIME type when available.

  • media_idstring

    Platform media identifier.

  • received_atUTC ISO-8601

    When the attachment was received.

  • urlfull profile only

    Media URL. Time-limited, provided by the platform; download promptly if you need to keep it.

  • title / captionfull profile only

    Title or caption text when present.

Attachment object
{
  "type":        "image",
  "media_type":  "image/jpeg",
  "media_id":    "18025531234567890",
  "received_at": "2026-02-20T08:15:00Z",

  // full profile only:
  "url":     "https://lookaside.fbsbx.com/ig_messaging_cdn/...",
  "title":   null,
  "caption": null
}

Message events

Inbound DMs and comments on Facebook and Instagram.

message.received

A customer sent a direct message on Facebook or Instagram (source.platform is facebook or instagram). Fires on text and on attachments.

Share variants

message.reel_shared and message.post_shared fire in addition to message.received for the same message when an Instagram reel or post is shared into the thread, carrying the same message.id. Subscribe to them when you want to react to shares specifically; deduplicate against message.id if you consume both.

message.received · full profile
{
  "event_id":    "a3f8e1c2d4b567890abcdef012345678",
  "event_type":  "message.received",
  "occurred_at": "2026-02-20T08:15:00Z",
  "source": {
    "platform": "instagram",
    "channel":  "meta_dm"
  },
  "conversation": {
    "id":               10482,
    "assigned_to":      90011,
    "assigned_to_name": "Anna"
  },
  "customer": {
    "platform_user_id":       "17841400123456789",
    "platform_user_name":     "Jane Doe",
    "platform_user_username": "janedoe",
    "contact_id":    555,
    "tags":          ["VIP", "Returning"],
    "stage":         "qualified",
    "custom_fields": {}
  },
  "message": {
    "id":          "mid.1234567890abcdef",
    "text_raw":    "Hi, do you have availability next Tuesday?",
    "attachments": []
  },
  "meta": {
    "version":         "v1",
    "payload_profile": "full",
    "generated_at":   "2026-02-20T08:15:00Z"
  }
}

comment.received

A customer left a comment on one of your Instagram or Facebook posts, reels, or live videos. Fires for every inbound comment, whether or not a ChatGenius comment trigger is configured.

There is no message block; the payload carries source_post and comment instead. conversation.id is null for comments: the follow-up DM, if a trigger sends one, arrives as its own message.received event.

  • source_postobject

    id is always present: the attribution join key. url is the permalink, populated when the comment matched a trigger targeting a specific post, otherwise null.

  • commentobject

    {id, text_raw, matched_keyword, trigger_id, trigger_name, source_type}. source_type is comment · live. The trigger fields (matched_keyword, trigger_id, trigger_name) are null unless a comment trigger matched.

comment.received · trigger matched
{
  "event_id":    "b7c2e1a4f9d063518adef0129876dcba",
  "event_type":  "comment.received",
  "occurred_at": "2026-02-20T08:15:00Z",
  "source": {
    "platform": "instagram",
    "channel":  "meta_dm"
  },
  "conversation": {
    "id": null
  },
  "customer": {
    "platform_user_id":       "17841400123456789",
    "platform_user_name":     null,
    "platform_user_username": "janedoe"
  },
  "source_post": {
    "id":  "17912345678901234",
    "url": "https://www.instagram.com/p/CtExAmple/"
  },
  "comment": {
    "id":              "17987654321098765",
    "text_raw":        "PRICE",
    "matched_keyword": "price",
    "trigger_id":      42,
    "trigger_name":    "Pricing DM",
    "source_type":     "comment"
  },
  "meta": {
    "version":         "v1",
    "payload_profile": "full",
    "generated_at":   "2026-02-20T08:15:00Z"
  }
}

sms · whatsapp · telegram .message_received

A customer messaged you on SMS, WhatsApp, or Telegram. Same envelope as every other event, plus one channel sub-block under message. The channel pages cover routing identifiers, supported actions, and limits.

  • message.smsobject

    {to_phone, from_phone, num_segments, num_media, encoding}. encoding is GSM-7 · UCS-2.

  • message.whatsappobject

    {wa_id, phone_number, business_phone_number_id, profile_name, message_type, context_message_id}.

  • message.telegramobject

    {chat_id, chat_type, username, message_type}. chat_id is the recipient identifier for the Send API.

sms.message_received · full profile
{
  "event_id":    "7f7a80c84bf17c4b5b72974c97365a77",
  "event_type":  "sms.message_received",
  "occurred_at": "2026-04-27T23:22:10Z",
  "source": {
    "platform": "sms",
    "channel":  "twilio_sms"
  },
  "conversation": {
    "id": 119301
  },
  "customer": {
    "platform_user_id": "+15551234567",
    "phone":            "+15551234567"
  },
  "message": {
    "id":          "SMdb4342728f73bca6a83770a705e27b31",
    "text_raw":    "Hi, what time do you open Saturday?",
    "attachments": [],
    "sms": {
      "to_phone":     "+15559876543",
      "from_phone":   "+15551234567",
      "num_segments": 1,
      "num_media":    0,
      "encoding":     "GSM-7"
    }
  },
  "meta": {
    "version":         "v1",
    "payload_profile": "full",
    "generated_at":   "2026-04-27T23:22:10Z"
  }
}
Channel sub-blocks
// sms.message_received
"sms": {
  "to_phone":     "+15559876543",
  "from_phone":   "+15551234567",
  "num_segments": 1,
  "num_media":    0,
  "encoding":     "GSM-7"
}

// whatsapp.message_received
"whatsapp": {
  "wa_id":                    "15551234567",
  "phone_number":             "+15551234567",
  "business_phone_number_id": "108765432109876",
  "profile_name":             "Jane Doe",
  "message_type":             "text",
  "context_message_id":       null
}

// telegram.message_received
"telegram": {
  "chat_id":      "820032950394075",
  "chat_type":    "private",
  "username":     "janedoe",
  "message_type": "text"
}

Lead events

Contact info captured from conversation content, ready for your CRM.

lead.email_captured · lead.phone_captured

Fires once per conversation, the first time an email (or phone) is captured from the conversation content, on any channel. A conversation that captures an email and later a phone produces one of each; the two events are identical except for event_type.

The lead block {email, phone, captured_at} is always included regardless of payload profile: contact info is the point of the event. Fields not yet captured are null.

lead.phone is a phone collected from message content, not the SMS or WhatsApp sender number; on those channels the sender number is already delivered as customer.platform_user_id on every event.

lead.email_captured
{
  "event_id":    "c7a3b5d1e9f2468013579bdf2468ace0",
  "event_type":  "lead.email_captured",
  "occurred_at": "2026-07-23T07:20:00Z",
  "source": {
    "platform": "instagram",
    "channel":  "meta_dm"
  },
  "conversation": {
    "id": 119789
  },
  "customer": {
    "platform_user_id": "992584566622479"
  },
  "lead": {
    "email":       "jane@example.com",
    "phone":       "+15551234567",
    "captured_at": "2026-07-23T07:20:00Z"
  },
  "meta": {
    "version":         "v1",
    "payload_profile": "full",
    "generated_at":   "2026-07-23T07:20:00Z"
  }
}

Appointment events

In-chat bookings made through the AI booking agent. Calendar syncs do not fire these.

appointment.booked · .cancelled · .rescheduled

All three carry the same appointment block; the event_type and the appointment's status tell you what happened. appointment.rescheduled fires again on each subsequent reschedule, with the new datetime. The block is always full regardless of payload profile.

  • appointmentobject

    {id, confirmation_code, datetime, service_type, duration_minutes, cost, status, timezone, location {city, state}, customer {name, email, phone}}.

  • datetimeUTC ISO-8601

    Always UTC. timezone is the appointment's own booking timezone; convert back to display the time the customer chose.

  • appointment.customerobject

    The contact details captured during booking. The top-level customer remains the messaging identity.

appointment.booked
{
  "event_id":    "a1b2c3d4e5f60718293a4b5c6d7e8f90",
  "event_type":  "appointment.booked",
  "occurred_at": "2026-07-24T06:30:00Z",
  "source": {
    "platform": "instagram",
    "channel":  "meta_dm"
  },
  "conversation": {
    "id": 187765
  },
  "customer": {
    "platform_user_id":   "820032950394075",
    "platform_user_name": "Jared"
  },
  "appointment": {
    "id":                1234,
    "confirmation_code": "AB12CD",
    "datetime":          "2026-07-30T15:00:00Z",
    "service_type":      "consultation",
    "duration_minutes":  30,
    "cost":              null,
    "status":            "confirmed",
    "timezone":          "America/New_York",
    "location": {
      "city":  "Austin",
      "state": "TX"
    },
    "customer": {
      "name":  "Jane Doe",
      "email": "jane@example.com",
      "phone": "+15551234567"
    }
  },
  "meta": {
    "version":         "v1",
    "payload_profile": "full",
    "generated_at":   "2026-07-24T06:30:00Z"
  }
}

Conversation events

Human handoff.

conversation.escalated

Fires every time a conversation is handed to a human, triggered by negative sentiment or an explicit hand-off, including repeat escalations on the same conversation. Wire it to Slack or a ticketing system, and match it to a thread via conversation.id.

There is no de-escalation event: the AI stays paused on an escalated conversation by design.

  • escalationobject

    {reason, assigned_to, escalated_at}. assigned_to is the agent the conversation was routed to, or null if no agent was available.

conversation.escalated
{
  "event_id":    "9d4f7a3b1c2e5d6f8091a2b3c4d5e6f7",
  "event_type":  "conversation.escalated",
  "occurred_at": "2026-07-24T05:40:00Z",
  "source": {
    "platform": "instagram",
    "channel":  "meta_dm"
  },
  "conversation": {
    "id": 187765
  },
  "customer": {
    "platform_user_id":       "820032950394075",
    "platform_user_name":     "Jared",
    "platform_user_username": "jaredr.media"
  },
  "escalation": {
    "reason":       "Negative sentiment detected",
    "assigned_to":  "Alex",
    "escalated_at": "2026-07-24T05:40:00Z"
  },
  "meta": {
    "version":         "v1",
    "payload_profile": "full",
    "generated_at":   "2026-07-24T05:40:00Z"
  }
}

Delivery events

Outbound sends that permanently failed.

message.send_failed

Fires when an outbound Send API request permanently fails: the platform returned a non-retryable error (most commonly an expired Meta messaging window) or retries were exhausted. Your system believed the send succeeded; this event lets it reconcile. Match it back to your original request via send_failed.idempotency_key.

  • send_failedobject

    {action, idempotency_key, request_id, error_code, error_message, http_code, attempts, text_attempted}.

  • text_attemptedfull profile only

    The message text you tried to send. null on the minimal profile.

message.send_failed
{
  "event_id":    "b2f1e0d9c8b7a695847362514f0e1d2c",
  "event_type":  "message.send_failed",
  "occurred_at": "2026-07-23T06:40:00Z",
  "source": {
    "platform": "instagram",
    "channel":  "meta_dm"
  },
  "conversation": {
    "id": 42
  },
  "customer": {
    "platform_user_id": "178414"
  },
  "send_failed": {
    "action":          "send_message",
    "idempotency_key": "your-key-abc-123",
    "request_id":      "req-xyz-789",
    "error_code":      "10",
    "error_message":   "Meta 7-day window expired.",
    "http_code":       400,
    "attempts":        1,
    "text_attempted":  "Hi, following up on your order"
  },
  "meta": {
    "version":         "v1",
    "payload_profile": "full",
    "generated_at":   "2026-07-23T06:40:00Z"
  }
}