Skip to main content

Boardy Migration Guide

This guide covers migrating from the basic /v1/ingest endpoint to the new /v1/ingest/multi endpoint for multi-channel data (emails, calls, tool calls, and chat messages).

What’s Changing

AspectOld (/v1/ingest)New (/v1/ingest/multi)
Endpoint/v1/ingest/v1/ingest/multi
Data typesOnly chat messagesEmails, calls, tool calls, channels
Email threadingNot supportedinReplyTo field
Call transcriptsNot supportedFull transcript array
Tool callsEmbedded in messageFirst-class tool_call type
EnvironmentNot supportedenvironment field for dev/staging/prod

Authentication

No change - same API key, same header:
Authorization: Bearer moda_xxx

New Request Format

Endpoint

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

Request Body

{
  "environment": "production",  // Optional: "development", "staging", or "production" (default)
  "events": [
    // Array of events - can mix types in one request
  ]
}

Environment

The environment field lets you differentiate data from development, staging, and production environments. This is useful for:
  • Filtering analytics by environment
  • Keeping dev/test data separate from production in clustering
  • Debugging issues in specific environments
FieldTypeRequiredDefaultDescription
environmentstringNo"production"Deployment environment
Valid values:
  • "development" - Local development or dev servers
  • "staging" - Staging/QA environment
  • "production" - Production environment (default)
If you don’t specify an environment, all data defaults to "production". This is backwards compatible with existing integrations.

Event Types

Channel Messages (Chat/Slack)

For text conversations between users and assistants.
{
  "messageType": "channel",
  "id": "msg-123",
  "conversationId": "thread-456",
  "message": "Hello, I need help with my order",
  "role": "user",
  "userId": "user-789",
  "timestamp": "2025-01-09T12:00:00Z"
}
FieldTypeRequiredDescription
messageTypestringYesMust be "channel"
idstringYesUnique message ID
conversationIdstringYesThread/conversation ID
messagestringYesMessage content
rolestringYes"user", "assistant", or "system"
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp

Tool Calls

For logging tool/function invocations.
{
  "messageType": "tool_call",
  "id": "tool-123",
  "conversationId": "thread-456",
  "name": "lookup_order",
  "toolCallRequest": {
    "order_id": "ORD-999"
  },
  "toolCallResponse": {
    "status": "shipped",
    "tracking": "1Z999..."
  },
  "timestamp": "2025-01-09T12:00:05Z"
}
FieldTypeRequiredDescription
messageTypestringYesMust be "tool_call"
idstringYesUnique tool call ID
conversationIdstringYesAssociated conversation
namestringYesTool/function name
toolCallRequestobjectYesRequest payload (any JSON)
toolCallResponseobjectYesResponse payload (any JSON)
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp

Emails

For email conversations. Uses inReplyTo for threading.
{
  "messageType": "email",
  "id": "email-123",
  "subject": "Re: Support request #456",
  "body": "Thanks for reaching out. I've looked into your issue and found that...",
  "inReplyTo": "email-thread-001",
  "from": "support@boardy.com",
  "to": ["customer@example.com"],
  "timestamp": "2025-01-09T12:00:00Z"
}
FieldTypeRequiredDescription
messageTypestringYesMust be "email"
idstringYesUnique email ID
bodystringYesEmail body content
inReplyTostringYesThread ID (becomes conversation_id)
subjectstringNoEmail subject line
fromstringNoSender email address
tostring[]NoRecipient email addresses
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp
The inReplyTo field is used as the conversation_id to group emails into threads. Use the same inReplyTo value for all emails in a thread.

Call Transcripts

For phone/video call recordings.
{
  "messageType": "call",
  "id": "call-123",
  "conversationId": "call-session-456",
  "transcript": [
    { "role": "customer", "content": "Hi, I'm calling about my bill" },
    { "role": "agent", "content": "I'd be happy to help. Can I get your account number?" },
    { "role": "customer", "content": "Sure, it's 12345" },
    { "role": "agent", "content": "Thank you. I see the issue - let me fix that for you." }
  ],
  "duration": 180,
  "callType": "phone",
  "timestamp": "2025-01-09T12:00:00Z"
}
FieldTypeRequiredDescription
messageTypestringYesMust be "call"
idstringYesUnique call ID
conversationIdstringYesCall session ID
transcriptarrayYesArray of transcript entries
transcript[].rolestringYesSpeaker role (e.g., customer, agent)
transcript[].contentstringYesWhat was said
durationnumberNoCall duration in seconds
callTypestringNo"phone", "video", or "voice"
userIdstringNoUser identifier
timestampstringNoISO 8601 timestamp
Call transcripts are stored as a single record with the full transcript. This optimizes for embedding generation and semantic search across entire calls.

Mixed Batch Example

You can send multiple event types in a single request:
{
  "environment": "staging",
  "events": [
    {
      "messageType": "channel",
      "id": "msg-1",
      "conversationId": "conv-123",
      "message": "Hi, I need to check on order #456",
      "role": "user"
    },
    {
      "messageType": "tool_call",
      "id": "tool-1",
      "conversationId": "conv-123",
      "name": "lookup_order",
      "toolCallRequest": { "order_id": "456" },
      "toolCallResponse": { "status": "delivered" }
    },
    {
      "messageType": "channel",
      "id": "msg-2",
      "conversationId": "conv-123",
      "message": "Your order #456 was delivered yesterday at 3pm.",
      "role": "assistant"
    },
    {
      "messageType": "email",
      "id": "email-1",
      "inReplyTo": "support-thread-789",
      "subject": "Order confirmation",
      "body": "Your order has been confirmed...",
      "from": "orders@boardy.com",
      "to": ["customer@example.com"]
    }
  ]
}

Response Format

Success

{
  "success": true,
  "count": 4,
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "details": {
    "channel": 2,
    "tool_call": 1,
    "email": 1,
    "call": 0,
    "call_transcript_messages": 0
  }
}

Error

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

Migration Checklist

  1. Update endpoint URL
    • Old: /v1/ingest
    • New: /v1/ingest/multi
  2. Add messageType to all events
    • Chat messages: "messageType": "channel"
    • Tool calls: "messageType": "tool_call"
    • Emails: "messageType": "email"
    • Calls: "messageType": "call"
  3. Rename fields for channel messages
    • conversation_idconversationId (camelCase)
  4. Add type-specific fields
    • Emails: inReplyTo, subject, from, to
    • Calls: transcript, duration, callType
    • Tool calls: name, toolCallRequest, toolCallResponse
  5. (Optional) Add environment
    • Add "environment": "staging" at the top level to tag non-production data
    • Omit for production (defaults to "production")
  6. Test with a small batch first
    • Send a few events to verify the format is correct
    • Check the response details breakdown

Limits

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

Questions?

Contact the Moda team for integration support.