message.created, message.updated, and message.deleted. All use the standard envelope.
The source container reference
Every message carries a reference to the source container it belongs to:source_name plus these two fields, so all three must match the source container’s identity exactly.
The reference is what connects a message to processing. Messages are queued against their source container and drained in order, with the source container’s kind, title, description, and lifecycle state as context. Without a matching source container:
- A message with a reference to a source container Modem has not seen yet is stored and waits. It is processed once the source container’s
source_container.createdevent arrives. A dangling reference is fine; it just delays processing. - A message with no reference at all is stored but not processed.
Message payload
Formessage.created and message.updated, body.data looks like this:
Required fields
channel
channel describes the broader place a message came from and is used for filtering and display. It is coarser than the source container.
channel.source_name must equal data.source_name.
author
author is optional, but a message without one contributes nothing to the people and companies Modem tracks. Send it whenever you can.
Bot-authored content is filtered during extraction. If a bot relays human-written text (an alert feed that quotes a customer, a form
that posts submissions), leave
is_bot false or Modem will discard the content.Optional fields
Threading and replies
Source containers scope the conversation; threads and replies describe structure inside it.source_thread_idandsource_thread_typeidentify the thread a message belongs to (a reply thread in a chat channel, for example). Modem treats distinct threads inside one source container as distinct concerns by default.source_reply_to_idandsource_reply_to_typeidentify the specific message this one replies to.
support_thread, issue, email_thread), you can omit both.
Examples
message.created
The first message in a chat channel source container:
message.updated
Same body as message.created, with the new content and an edited_at:
message.deleted
Processing behavior
message.createdstores the message, runs OCR on image attachments, and queues the message for processing in its source container. Modem drains each source container serially: messages are read in order, in windows, with earlier concerns from the same source container available so restatements are merged rather than duplicated.message.updatedupdates the stored content and OCRs newly added images. It does not re-run extraction for content that was already processed.message.deletedmarks the message deleted and clears its content.
Deduplication
source_nonce exists for one scenario: your upstream source gives you a delivery ID that is unique per delivery attempt, and that source may redeliver the same payload. Setting source_nonce to that delivery ID lets Modem drop the duplicate.
Good example: a webhook provider assigns every delivery a unique ID header and may redeliver the same webhook within seconds. Using that delivery ID as source_nonce is correct because it is scoped to the delivery, not to the underlying resource.
source_nonce from properties of the message (its ID, channel, or a combination). A message.updated with the same nonce as the original message.created would be silently dropped as a duplicate, and the update never applies.
How it works
Whensource_nonce is present, Modem generates a deterministic event ID from:
source_nonce, each request gets a unique event ID, which is the correct behavior for most integrations.
The same applies to source_container.* events.
Related
Source Containers
Source container kinds, identity, lifecycle state, and the source container events.
Ingest API overview
Authentication, the event envelope, and the end-to-end protocol.