Skip to main content

Overview

The multi-type ingestion endpoint allows you to send various types of conversation data to Moda, not just LLM chat messages. This is useful for:
  • Chat/messaging platforms (Slack, Discord, etc.)
  • Customer support tools with tool/function calls
  • Email thread analytics
  • Call center transcripts and voice analytics
All data types flow through the standard Moda analytics pipeline, including embeddings, evaluations, and clustering.

Endpoint

POST https://moda-ingest.modas.workers.dev/v1/ingest/multi

Authentication

Include your Moda API key in the Authorization header:
-H "Authorization: Bearer YOUR_MODA_API_KEY"

Message types

Channel messages

Text messages from chat platforms or messaging systems.
{
  "messageType": "channel",
  "id": "msg-123",
  "conversationId": "thread-456",
  "message": "Hello, how can I help you today?",
  "role": "assistant",
  "userId": "user-789",
  "timestamp": "2025-01-04T12:00:00Z"
}
FieldTypeRequiredDescription
messageTypestringYesMust be "channel"
idstringYesUnique message ID
conversationIdstringYesThread/channel ID for grouping messages
messagestringYesMessage content
rolestringYesOne of: user, assistant, system
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp (defaults to now)
metadataobjectNoCustom metadata

Tool calls

Function/tool invocations with request and response data.
{
  "messageType": "tool_call",
  "id": "tool-123",
  "conversationId": "thread-456",
  "name": "search_knowledge_base",
  "toolCallRequest": {
    "query": "refund policy",
    "limit": 5
  },
  "toolCallResponse": {
    "results": [
      {"title": "Refund Policy", "content": "..."}
    ]
  }
}
FieldTypeRequiredDescription
messageTypestringYesMust be "tool_call"
idstringYesUnique tool call ID
conversationIdstringYesConversation ID for grouping
namestringYesTool/function name
toolCallRequestanyYesRequest payload (can be any JSON)
toolCallResponseanyYesResponse payload (can be any JSON)
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp

Emails

Email messages with threading support via inReplyTo.
{
  "messageType": "email",
  "id": "email-123",
  "subject": "Re: Order #12345 - Shipping question",
  "body": "Thank you for reaching out. Your order is scheduled to arrive...",
  "inReplyTo": "email-thread-001",
  "from": "support@example.com",
  "to": ["customer@example.com"]
}
FieldTypeRequiredDescription
messageTypestringYesMust be "email"
idstringYesUnique email ID
inReplyTostringYesThread ID (becomes conversation_id for threading)
bodystringYesEmail body content
subjectstringNoEmail subject line
fromstringNoSender email address
toarrayNoRecipient email addresses
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp
The inReplyTo field is used as the conversation_id in Moda, allowing you to thread emails together. Use the same inReplyTo value for all emails in a thread.

Call transcripts

Phone or video call transcripts with speaker turns.
{
  "messageType": "call",
  "id": "call-123",
  "conversationId": "call-session-456",
  "transcript": [
    {"role": "user", "content": "Hi, I'm having trouble with my account."},
    {"role": "assistant", "content": "I'd be happy to help. Can you tell me more about the issue?"},
    {"role": "user", "content": "I can't log in after resetting my password."}
  ],
  "duration": 180,
  "callType": "phone"
}
FieldTypeRequiredDescription
messageTypestringYesMust be "call"
idstringYesUnique call ID
conversationIdstringYesCall session ID
transcriptarrayYesArray of transcript entries (see below)
durationnumberNoCall duration in seconds
callTypestringNoOne of: phone, video, voice
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp
Transcript entry format:
FieldTypeRequiredDescription
rolestringYesSpeaker role (e.g., user, assistant, customer, agent)
contentstringYesWhat was said
timestampstringNoWhen this was said
Call transcripts are stored as a single record containing the full transcript. The complete transcript is included in the message field for embedding/search, and the structured data is preserved in content_blocks for detailed analysis.

Request format

Send an array of events in the request body. You can mix different message types in a single request.
{
  "events": [
    {
      "messageType": "channel",
      "id": "msg-1",
      "conversationId": "conv-123",
      "message": "Hello!",
      "role": "user"
    },
    {
      "messageType": "tool_call",
      "id": "tool-1",
      "conversationId": "conv-123",
      "name": "lookup_order",
      "toolCallRequest": {"order_id": "12345"},
      "toolCallResponse": {"status": "shipped"}
    }
  ]
}

Example

curl https://moda-ingest.modas.workers.dev/v1/ingest/multi \
  -H "Authorization: Bearer YOUR_MODA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "messageType": "channel",
        "id": "msg-001",
        "conversationId": "support-thread-123",
        "message": "I need help with my subscription",
        "role": "user",
        "userId": "customer-456"
      },
      {
        "messageType": "tool_call",
        "id": "tool-001",
        "conversationId": "support-thread-123",
        "name": "get_subscription",
        "toolCallRequest": {"user_id": "customer-456"},
        "toolCallResponse": {"plan": "pro", "status": "active"}
      },
      {
        "messageType": "channel",
        "id": "msg-002",
        "conversationId": "support-thread-123",
        "message": "I can see you have an active Pro subscription. How can I help?",
        "role": "assistant"
      }
    ]
  }'

Response

Success response

{
  "success": true,
  "count": 4,
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "details": {
    "channel": 2,
    "tool_call": 1,
    "email": 0,
    "call": 1,
    "call_transcript_messages": 0
  }
}
FieldTypeDescription
successbooleanWhether the request succeeded
countnumberTotal records created
requestIdstringUnique request ID for debugging
detailsobjectBreakdown by message type
details.call_transcript_messagesnumberAlways 0 (kept for backwards compatibility)

Error response

{
  "success": false,
  "count": 0,
  "message": "Event 2: Channel message missing 'conversationId'",
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "retryable": false
}

Batch limits

LimitValue
Max events per request1,000
Max message size100 KB
Max request size5 MB

Error handling

StatusMeaningRetryable
200Success-
400Invalid request format or validation errorNo
401Invalid or missing API keyNo
413Request too largeNo
503Service temporarily unavailableYes
Each event is validated individually. The error message will indicate which event failed and why (e.g., “Event 2: Email missing ‘inReplyTo’”).