Skip to main content

UC-018 — Manage the Inbox

FieldValue
IDUC-018
GoalManage inbound conversations: triage, reading, archiving
ChannelAll (SMS, RCS, WhatsApp, Messenger)
ComplexityIntermediate
Estimated time15 minutes
APIs involvedGET /api/partner-gateway/v1/inbox/conversations, GET /api/partner-gateway/v1/inbox/conversations/{chatId}, GET /api/partner-gateway/v1/inbox/conversations/{chatId}/messages, PATCH /api/partner-gateway/v1/inbox/conversations/{chatId}/archive, PATCH /api/partner-gateway/v1/inbox/conversations/{chatId}/unarchive, PATCH /api/partner-gateway/v1/inbox/conversations/{chatId}/read, POST /api/partner-gateway/v1/inbox/conversations/{chatId}/assignee, DELETE /api/partner-gateway/v1/inbox/conversations/{chatId}/assignee, GET /api/partner-gateway/v1/inbox/conversations/assignable-users

Real-world scenarios

  • Customer support triage: The ShopOnline support team uses the API to feed their internal dashboard and assign conversations to available operators.
  • Archive resolved conversations: After closing a ticket, the operator archives the conversation to keep the inbox clean and focused on open cases.
  • Monitor unread messages: The supervisor checks how many unread conversations there are to assess team workload.
  • Workload distribution: The supervisor lists assignable team members and assigns each conversation to a specific agent via API; the agent is notified of the new work and the assignment shows up in their personalised inbox view.

Inbox management flow

The diagram shows the typical workflow: listing, reading, marking, archiving, and optionally assigning the conversation to a teammate.

Prerequisites

  • Active API Key with inbox management permissions
  • At least one active channel with inbound messages configured
  • Receiving webhook configured (optional, for real-time notifications)

Step 1 — Retrieve active conversations

List conversations in the inbox, with filters for status and channel.

curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations?status=active&limit=20" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Conversation list

{
"conversations": [
{
"chatId": "chat_abc123",
"channel": "WHATSAPP",
"contact": {
"phoneNumber": "+393471234567",
"name": "Marco Rossi"
},
"lastMessage": {
"body": "Buongiorno, vorrei informazioni sulla spedizione del mio ordine",
"direction": "INBOUND",
"timestamp": "2026-04-09T14:30:00+02:00"
},
"unreadCount": 3,
"status": "ACTIVE",
"createdAt": "2026-04-09T14:25:00+02:00"
},
{
"chatId": "chat_def456",
"channel": "SMS",
"contact": {
"phoneNumber": "+393489876543",
"name": "Giulia Bianchi"
},
"lastMessage": {
"body": "STOP",
"direction": "INBOUND",
"timestamp": "2026-04-09T13:45:00+02:00"
},
"unreadCount": 1,
"status": "ACTIVE",
"createdAt": "2026-04-09T13:45:00+02:00"
}
],
"total": 2,
"hasMore": false
}

:::tip Filter for unread Add &unreadOnly=true to the query to display only conversations with unread messages, useful for triage. :::

Behind the scenes — How the inbox works
  1. Aggregation: The inbox aggregates messages from all active channels (SMS, RCS, WhatsApp, Messenger) into a single unified view.
  2. Threading: Messages are grouped into conversations based on the contact's phone number. A channel switch from the same number creates a new conversation.
  3. Sorting: Conversations are sorted by last message timestamp (most recent first).
  4. Pagination: The endpoint supports limit and offset for pagination. The hasMore field indicates whether there are additional results.

Step 2 — Read messages in a conversation

Retrieve the complete message history of a specific conversation.

curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/chat_abc123/messages?limit=50" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Thread messages

{
"chatId": "chat_abc123",
"messages": [
{
"messageId": "msg_001",
"direction": "INBOUND",
"body": "Buongiorno, vorrei informazioni sulla spedizione del mio ordine",
"timestamp": "2026-04-09T14:25:00+02:00",
"status": "RECEIVED"
},
{
"messageId": "msg_002",
"direction": "INBOUND",
"body": "Il numero ordine e #ORD-20260405",
"timestamp": "2026-04-09T14:26:00+02:00",
"status": "RECEIVED"
},
{
"messageId": "msg_003",
"direction": "INBOUND",
"body": "Potete aiutarmi?",
"timestamp": "2026-04-09T14:30:00+02:00",
"status": "RECEIVED"
}
],
"total": 3,
"hasMore": false
}

Step 3 — Mark as read and archive

After handling the conversation, mark it as read and then archive it.

# Mark as read
curl -X PATCH https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/chat_abc123/read \
-H "X-Api-Key: YOUR_API_KEY"

Response — Marked as read

{
"chatId": "chat_abc123",
"unreadCount": 0,
"updatedAt": "2026-04-09T15:00:00+02:00"
}
# Archive the resolved conversation
curl -X PATCH https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/chat_abc123/archive \
-H "X-Api-Key: YOUR_API_KEY"

Response — Conversation archived

{
"chatId": "chat_abc123",
"status": "ARCHIVED",
"archivedAt": "2026-04-09T15:01:00+02:00"
}
Behind the scenes — Archiving and restoring
  1. Archiving: The conversation is moved to the archive and no longer appears in the active list. Messages remain accessible.
  2. Restoring: Use PATCH /conversations/{chatId}/unarchive to bring a conversation back to the active inbox.
  3. New message: If a contact with an archived conversation sends a new message, the conversation is automatically restored to the active inbox.
  4. Retention: Archived conversations are kept for 12 months, then moved to long-term storage.

Step 4 — Assign or release a conversation

Distribute the inbox workload by assigning a conversation to a specific team member, or release it back to the unassigned queue.

List assignable team members

curl -X GET https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/assignable-users \
-H "X-Api-Key: YOUR_API_KEY"

Response — Team members

[
{
"id": 4521,
"fullName": "Anna Bianchi",
"profilePicture": "https://cdn.example.com/users/4521/avatar.png"
},
{
"id": 4522,
"fullName": "Luca Verdi",
"profilePicture": "https://cdn.example.com/users/4522/avatar.png"
},
{
"id": 4523,
"fullName": "Marco Rossi",
"profilePicture": null
}
]

Assign the conversation to a user

curl -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/98765/assignee \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"userId": 4521}'

Response

204 No Content — the conversation is now owned by user 4521. A subsequent GET /inbox/conversations/98765 will reflect the new assignedUserId.

Release the conversation

curl -X DELETE https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/98765/assignee \
-H "X-Api-Key: YOUR_API_KEY"

Response

204 No Content — the conversation is back to unassigned. The operation is idempotent: calling it on an already-unassigned conversation still returns 204.

:::tip One assignee at a time Each conversation can have at most one assignee. A new POST .../assignee replaces the previous assignment without requiring an explicit DELETE. :::

Behind the scenes — Assignment lifecycle
  1. Exclusive ownership: Only one team member can own a conversation at a time. Re-assigning silently replaces the previous owner.
  2. Notifications: The new assignee receives a real-time notification about the assignment and any subsequent inbound messages on that conversation.
  3. Idempotent release: DELETE .../assignee returns 204 whether or not there was a previous assignee, so retry logic is safe.
  4. Cross-company guard: The userId in the assign request must belong to your company. Attempts to assign to a user from another account return 404, not 403, to avoid leaking user existence across tenants.

Expected result

StepActionResult
1GET /inbox/conversationsConversation list with preview and unread count
2GET /inbox/conversations/{chatId}/messagesComplete message history of the thread
3PATCH /{chatId}/read + PATCH /{chatId}/archiveConversation read and archived
4POST /{chatId}/assignee + DELETE /{chatId}/assigneeConversation assigned to a teammate and later released

Complete end-to-end example

Scenario ShopOnline: automatic triage of unread conversations.

# 1. Retrieve unread conversations
echo "=== Unread Conversations ==="
CHATS=$(curl -s -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations?status=active&unreadOnly=true" \
-H "X-Api-Key: YOUR_API_KEY")

echo "$CHATS" | jq '.conversations[] | {chatId, channel: .channel, contact: .contact.name, unread: .unreadCount}'

# 2. Read messages of the first conversation
FIRST_CHAT=$(echo "$CHATS" | jq -r '.conversations[0].chatId')
echo "=== Messages for $FIRST_CHAT ==="
curl -s -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/${FIRST_CHAT}/messages" \
-H "X-Api-Key: YOUR_API_KEY" | jq '.messages[] | {direction, body, timestamp}'

# 3. Mark as read
curl -s -X PATCH "https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/${FIRST_CHAT}/read" \
-H "X-Api-Key: YOUR_API_KEY" | jq .

Variants

Restore an archived conversation

If a conversation was archived by mistake, restore it:

curl -X PATCH https://lora-api.agiletelecom.com/api/partner-gateway/v1/inbox/conversations/chat_abc123/unarchive \
-H "X-Api-Key: YOUR_API_KEY"

Common errors

404 Not Found — Conversation not found

{
"status": "fail",
"data": {
"conversation": "Conversation not found: chat_invalid_id"
}
}

Solution: Verify that the chatId is correct. Use GET /inbox/conversations to get the list of valid IDs.

404 Not Found — User not in your company

{
"status": "fail",
"data": {
"user": "User 9999 does not belong to your company"
}
}

Solution: The userId you tried to assign does not exist in your team. Call GET /inbox/conversations/assignable-users to list the valid IDs before retrying.

409 Conflict — Conversation already archived

{
"status": "fail",
"data": {
"conversation": "Conversation is already archived"
}
}

Solution: The conversation is already in the archive. If you want to restore it, use the unarchive endpoint.

Next steps

References