Conversations API

The Conversations API manages replies, comments, and notes within tickets. A conversation represents a single message in the ticket thread.

Conversation Object

{
  id: string;                    // UUID
  ticket_id: string;             // UUID of parent ticket
  author_id: string;             // UUID of message author
  content: object;               // Rich text content (TipTap JSON)
  content_text: string;          // Plain text version
  content_html?: string;         // HTML version
  type: string;                  // comment, note, email, sms
  internal: boolean;             // Whether this is an internal note
  parent_id?: string;            // UUID for threaded replies
  translated_content?: object;   // Translated TipTap JSON (for outgoing)
  translated_content_text?: string;
  translated_content_html?: string;
  metadata?: object;             // Additional metadata
  attachments?: Attachment[];    // Array of file attachments
  created_at: string;            // ISO timestamp
  updated_at: string;            // ISO timestamp
  deleted_at?: string;           // ISO timestamp (soft delete)

  // Joined relations
  author?: {
    name: string;
    email: string;
    avatar_url?: string;
  };
}

Type Values

TypeDescription
commentStandard customer-visible reply
noteInternal note (only visible to agents)
emailReply sent via email channel
smsReply sent via SMS channel

List Conversations

Retrieve all conversations for a ticket, ordered chronologically.

Procedure: conversations.list

Authentication: Required

Input:

{
  ticketId: string;  // UUID of the ticket
}

Example:

curl -X GET "https://your-domain.com/api/trpc/conversations.list?input=%7B%22ticketId%22:%22uuid-here%22%7D" \
  -H "Cookie: your-session-cookie"

Response:

{
  "result": {
    "data": {
      "json": [
        {
          "id": "uuid",
          "ticket_id": "ticket-uuid",
          "author_id": "user-uuid",
          "content": {
            "type": "doc",
            "content": [
              {
                "type": "paragraph",
                "content": [
                  {"type": "text", "text": "Thank you for reaching out..."}
                ]
              }
            ]
          },
          "content_text": "Thank you for reaching out...",
          "type": "comment",
          "internal": false,
          "author": {
            "name": "Support Agent",
            "email": "agent@company.com",
            "avatar_url": "https://..."
          },
          "attachments": [],
          "created_at": "2024-01-15T10:35:00.000Z"
        }
      ]
    }
  }
}

Notes:

  • Results are ordered by created_at ascending (oldest first)
  • Soft-deleted conversations are excluded
  • Includes author details and attachments

Create Conversation

Add a new reply or note to a ticket.

Procedure: conversations.create

Authentication: Required

Input:

{
  ticketId: string;              // Required, ticket UUID
  content: object;               // Required, rich text content (TipTap JSON)
  contentText: string;           // Required, plain text version
  contentHtml?: string;          // Optional HTML version
  type?: 'comment' | 'note' | 'email' | 'sms';  // default: comment
  internal?: boolean;            // default: false
  parentId?: string;             // UUID for threaded replies
  translateToLanguage?: string;  // ISO 639-1 code for outgoing translation
}

Example - Public Reply:

curl -X POST "https://your-domain.com/api/trpc/conversations.create" \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{
    "json": {
      "ticketId": "ticket-uuid",
      "content": {
        "type": "doc",
        "content": [
          {
            "type": "paragraph",
            "content": [
              {"type": "text", "text": "Thank you for reaching out. I will look into this issue and get back to you shortly."}
            ]
          }
        ]
      },
      "contentText": "Thank you for reaching out. I will look into this issue and get back to you shortly.",
      "type": "comment",
      "internal": false
    }
  }'

Example - Internal Note:

curl -X POST "https://your-domain.com/api/trpc/conversations.create" \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{
    "json": {
      "ticketId": "ticket-uuid",
      "content": {
        "type": "doc",
        "content": [
          {
            "type": "paragraph",
            "content": [
              {"type": "text", "text": "Escalating to tier 2 support due to complexity."}
            ]
          }
        ]
      },
      "contentText": "Escalating to tier 2 support due to complexity.",
      "type": "note",
      "internal": true
    }
  }'

Example - Translated Reply:

curl -X POST "https://your-domain.com/api/trpc/conversations.create" \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{
    "json": {
      "ticketId": "ticket-uuid",
      "content": {...},
      "contentText": "Thank you for contacting us...",
      "translateToLanguage": "es"
    }
  }'

Response:

{
  "result": {
    "data": {
      "json": {
        "id": "uuid",
        "ticket_id": "ticket-uuid",
        "author_id": "user-uuid",
        "content": {...},
        "content_text": "Thank you for reaching out...",
        "content_html": "<p>Thank you for reaching out...</p>",
        "type": "comment",
        "internal": false,
        "author": {
          "name": "Support Agent",
          "email": "agent@company.com",
          "avatar_url": "https://..."
        },
        "created_at": "2024-01-15T10:35:00.000Z"
      }
    }
  }
}

Side Effects:

  • Updates first_response_at on ticket if this is the first response
  • Sets ticket status to pending if public reply (waiting for customer)
  • Triggers conversation.created automation event
  • Sends reply through appropriate channel (email, SMS, etc.) for public comments
  • Content is sanitized to prevent XSS
  • Rate limited to prevent abuse

Update Conversation

Update an existing conversation. Users can only update their own conversations.

Procedure: conversations.update

Authentication: Required

Input:

{
  id: string;            // Required, conversation UUID
  content?: object;      // Rich text content
  contentText?: string;  // Plain text version
  contentHtml?: string;  // HTML version
}

Example:

curl -X POST "https://your-domain.com/api/trpc/conversations.update" \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{
    "json": {
      "id": "conversation-uuid",
      "content": {...},
      "contentText": "Updated message content"
    }
  }'

Response:

{
  "result": {
    "data": {
      "json": {
        "id": "uuid",
        "content": {...},
        "content_text": "Updated message content",
        "updated_at": "2024-01-15T11:00:00.000Z"
      }
    }
  }
}

Notes:

  • Users can only update conversations they authored
  • Updates are reflected in the ticket thread

Delete Conversation

Soft delete a conversation. Users can only delete their own conversations.

Procedure: conversations.delete

Authentication: Required

Input:

{
  id: string;  // Conversation UUID
}

Example:

curl -X POST "https://your-domain.com/api/trpc/conversations.delete" \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{"json":{"id":"conversation-uuid"}}'

Response:

{
  "result": {
    "data": {
      "json": {
        "success": true
      }
    }
  }
}

Notes:

  • Users can only delete conversations they authored
  • Soft delete - data is retained but excluded from queries

Bulk Reply

Send the same reply to multiple tickets at once. Useful for responding to similar issues.

Procedure: conversations.bulkReply

Authentication: Required (admin or agent)

Input:

{
  ticketIds: string[];      // Array of ticket UUIDs (1-100)
  content: object;          // Rich text content (TipTap JSON)
  contentText: string;      // Plain text version
  contentHtml?: string;     // HTML version
  internal?: boolean;       // default: false
}

Example:

curl -X POST "https://your-domain.com/api/trpc/conversations.bulkReply" \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{
    "json": {
      "ticketIds": ["uuid1", "uuid2", "uuid3"],
      "content": {
        "type": "doc",
        "content": [
          {
            "type": "paragraph",
            "content": [
              {"type": "text", "text": "We have released a fix for this issue. Please update to the latest version."}
            ]
          }
        ]
      },
      "contentText": "We have released a fix for this issue. Please update to the latest version.",
      "internal": false
    }
  }'

Response:

{
  "result": {
    "data": {
      "json": {
        "success": true,
        "repliedCount": 3
      }
    }
  }
}

Side Effects:

  • Creates a conversation on each ticket
  • Updates first_response_at on tickets without prior responses
  • Sets ticket status to pending for public replies
  • Sends replies through appropriate channels
  • Triggers conversation.created automation events
  • Rate limited to prevent abuse

Notes:

  • Maximum 100 tickets per bulk operation
  • Only tickets in the user's organization are processed
  • Soft-deleted tickets are skipped
  • Agent cannot send to their own tickets

Translation Support

Relay supports automatic translation for both incoming and outgoing messages.

Outgoing Translation

When creating a conversation with translateToLanguage, the content is translated before being sent to the customer:

{
  ticketId: "...",
  content: {...},
  contentText: "Thank you for your message",
  translateToLanguage: "es"  // Translate to Spanish
}

The original English content is stored in content, content_text, and content_html. The translated content is stored in translated_content, translated_content_text, and translated_content_html.

When sending through channels (email, etc.), the translated content is used if available.

Supported Languages

Translation supports all major languages. Common language codes:

CodeLanguage
enEnglish
esSpanish
frFrench
deGerman
itItalian
ptPortuguese
jaJapanese
koKorean
zhChinese
arArabic
hiHindi
ruRussian

Rate Limits

OperationLimit
Create conversation100 per minute per user
Bulk reply10 per minute per user

Webhooks

The following webhook event is available for conversations:

EventDescription
conversation.createdTriggered when a conversation is created

Event payload includes:

  • ticketId: Parent ticket UUID
  • ticketNumber: Human-readable ticket number
  • commentText: Plain text content
  • channel: The conversation type/channel
  • isPublic: Whether the conversation is visible to customers

See Webhooks for configuration details.