Skip to main content
The ingest API lets you send message events into Modem from your own integrations. This is a server-to-server API for developers who want to push messages from tools Modem does not natively connect to yet.
Only message events are supported in this first pass: message.created, message.updated, and message.deleted.

Authentication

Send your project key in the x-modem-public-key header.
Project keys are managed per project, not per organization. To get a key:
  1. Open your organization in the Modem dashboard.
  2. Go to OrganizationProjects.
  3. Open the project you want to ingest into.
  4. In Public Keys, create a key or copy an existing active key.
Only org admins and owners can create, deactivate, or revoke keys.
Despite the name, treat this key like a server-side bearer credential. Do not ship it in browser code or mobile apps.

Endpoint

Send a JSON event body with your project key in the x-modem-public-key header:

Event Envelope

Every request sends a single event. Modem assigns received_at internally when the event is accepted and stored. Do not send received_at in the request body.

client

client.name identifies the producer that submitted the event to Modem.
  • Use a lowercase package-style identifier such as @your-company/teams-sync.
  • @modem/* is reserved for Modem-managed integrations.
  • client.name is descriptive producer metadata. It is not a trusted provenance boundary.
client.version must use semantic versioning, for example 1.0.0.

Message Payload

For message.created and message.updated, body looks like this:

Required fields

Important rules

  • channel.source_name must exactly match data.source_name.
  • source_name should stay stable within your organization. Modem uses it as part of deterministic IDs.
  • Custom sources use plain slugs directly in source_name. Do not prefix them with custom_.
  • Built-in values like slack, discord, and github remain reserved for those sources.
  • is_internal is optional and defaults to false; send true for a message withheld from the external participant (such as an agent’s internal note).

Threading and replies

Use these optional pairs when you have them:
  • source_thread_id and source_thread_type
  • source_reply_to_id and source_reply_to_type
Each pair must be sent together or omitted together.

Custom Sources

Custom message sources are supported for message events.
  • Good source_name values: microsoft-teams, intercom, zendesk-chat
  • Better when one upstream app needs multiple distinct feeds: teams-support, teams-sales
  • Avoid renaming a source later by changing the slug. That creates a new source identity inside Modem.
source_name is the source identity. There is no separate source_key.

Examples

message.created

message.updated

message.deleted

Responses

Successful requests return 200 OK.
Common error responses:

Processing Behavior

  • message.created stores the message, runs attachment OCR when needed, then sends the message into grouping and topic processing.
  • message.updated updates the stored message and can OCR newly added image attachments. It does not re-run grouping or topic generation for existing conversations.
  • message.deleted marks the stored message deleted and clears message content.

Deduplication

Most integrations should not set source_nonce. Only use it when your upstream provider has at-least-once delivery guarantees and may send you the same event more than once. If you are constructing events yourself, leave source_nonce empty.
source_nonce exists for one specific scenario: your upstream source gives you a delivery ID that is unique to each delivery attempt, and that source may retry or redeliver the same payload. Setting source_nonce to that delivery ID lets Modem drop the duplicate. Good example — GitHub webhooks: GitHub assigns every webhook delivery an X-GitHub-Delivery header. GitHub may redeliver the same webhook multiple times within seconds. Using that delivery ID as source_nonce is correct because it is scoped to the delivery, not to the underlying resource.
Bad example — constructing a nonce from message properties: If you build a source_nonce from characteristics of the message itself (such as source_message_id, channel ID, or a combination of fields), you will block all future events that touch that message. A message.updated event with the same nonce as the original message.created would be silently dropped as a duplicate — the update never gets applied.

How it works

When source_nonce is present, Modem generates a deterministic event ID from:
A second request with the same nonce produces the same event ID and is treated as a duplicate delivery of the same event. This means the nonce must identify the delivery, not the resource. If you omit source_nonce, each request gets a unique event ID and Modem treats it as a new delivery — which is the correct behavior for most integrations.

Current Limits

  • Public ingest is message-only in this version.
  • Pull request and issue event families remain built-in-only.
  • This ingest endpoint is not yet part of the OpenAPI spec; the rest of the public API is documented under API Reference.
  • Internal vs external producer provenance is not enforced by auth yet.

Integrations

See Modem’s built-in integrations and how they capture data.

Security & Privacy

Review the current security model for data sent to Modem.