Skip to main content

What is a ticket?

A ticket is a work item your team tracks from first contact until it is resolved or closed. Think of it as a case file: it has a title, a priority, an owner, a pipeline, a current stage on the board, and links to related records (reviews, customers, journeys, campaigns, or events). Tickets live in the CRM → Tickets area of the dashboard. You can also create and update them through the Storefront API if you integrate Masivo with your own tools (help desk, inbox connector, custom portal, etc.).

The three layers you need to understand

Masivo separates case management from conversation storage. This keeps the ticket board fast while still storing full message history. Important: listing threads returns thread shells (summary fields only). To read the full conversation, call the messages endpoint for each thread.

Ticket lifecycle (pipelines, stages, and status)

Every ticket belongs to one pipeline and one stage inside that pipeline. An account starts with a default Support Pipeline. Create another pipeline only when the support process has genuinely different stages; teams that share a process should share a pipeline. Each stage has a stable internal code, a display name, an order, and an internal stage_type: Status (open, resolved, closed) is derived from the stage. The stage’s internal type—not its name—decides whether the ticket is open. You normally change pipeline/stage, not status directly. The default pipeline includes new, in_progress, waiting_customer, waiting_internal, resolved, and closed. Custom pipelines receive their own stable stage codes. Some stages require extra text before the move is allowed: Configure pipelines under CRM → Pipelines. Every active pipeline must keep exactly one open default stage, at least one open stage, and at least one closed stage. A used stage cannot be removed or change its internal state until its tickets are moved. When an inbound customer message arrives on a closed ticket, Masivo reopens the same ticket in the first open stage of its current pipeline. It does not create a replacement ticket.

Category hierarchy

Classification describes the problem independently from its workflow stage. Configure it under CRM → Categories as one hierarchy. A top-level category groups related categories and defines their e-commerce availability. A leaf can end at the second or third level; it is selectable on tickets and owns the schema that agents complete. When an agent creates or edits a ticket, category selectors appear progressively, for example Orders › Payments › Card declined. Only a leaf can be selected. Selecting it displays its Schema and restricts Brand, Channel, and Store to the availability inherited from the top-level category. The database validates the same restrictions. All levels live in ticket_categories. A top-level category has a null parent_id; every other category references its parent. The leaf Schema is stored in ticket_categories.schema. Tickets reference the selected leaf through category_id and store validated values in category_answers. A category in use cannot be removed until its tickets are moved.

Ticket sources

Review-sourced tickets automatically get a review communication thread with the review answers as the first inbound message.

Assignees

Each ticket can have team members in two roles: Being linked to a ticket only as a watcher makes it read-only for that person: they cannot change its stage, edit it, comment, reply, reassign, or delete it, even when their account role allows writing tickets. Admins keep their global bypass, and anyone with no link to the ticket still acts according to their role, so supervisors can pick up unassigned work. Assignee changes emit journey events (TICKET_ASSIGNEE_ADDED, TICKET_ASSIGNEE_REMOVED) that you can use in Ticket Journey Triggers.

Agents and automatic assignment

Everyone who owns a ticket is a ticket agent. Assigning a team member by hand adds them to the roster automatically, with automatic routing switched off so they only receive what you hand them. Each agent declares how much work they can take and when: A ticket created without an assignee goes to the available agent with the lightest open load, breaking ties by who was assigned least recently. The agent must be on shift, under capacity, subscribed to the ticket’s pipeline, and skilled in its category or in one of that category’s parents. Accounts with no roster keep creating unassigned tickets. Skipping routing for a single ticket is possible by creating it with auto_assign: false; the decision is stored on the ticket, so later sweeps respect it too.

When every agent is busy

If nobody can take the ticket at creation time it stays unassigned instead of failing. An externally scheduled job (POST /api/cron/tickets/auto_assign) sweeps the pending backlog. The first sweep after an agent closes work, comes back from a break, or starts their shift assigns the waiting ticket. The sweep interleaves pipeline/category routes so an unsupported category cannot block unrelated work; within each route, urgent and older tickets go first. Agents can also be pulled in manually from the ticket detail with Auto-assign, which runs the same routing on demand.

Agent profiles and performance

Open CRM → Agents to inspect an agent’s current load, shift, pipeline and category routing, recent ticket flow, average resolution time, reopen rate, and open work by priority. The summary compares the latest 30-day window with the previous one. Lifetime metrics keep tickets the agent previously held after reassignment and count each ticket once. The ticket tabs show the agent’s current active assignments, split into open, resolved, and closed work.

Communication threads

A thread represents one external conversation identity, for example:
  • One email mailbox thread (channel: email, external_thread_id from your provider)
  • One WhatsApp number conversation (channel: whatsapp)
  • One web chat session (channel: chat)
  • The review submission tied to a ticket (channel: review, created automatically)

Thread fields that matter day to day

Thread uniqueness (avoid duplicates)

If you sync from an external system, always send external_thread_id (and usually channel_account_id) when creating threads and messages. Masivo deduplicates on:
  • Thread: (account, channel, channel_account_id, external_thread_id)
  • Message: (account, channel, external_message_id)
Sending the same external ids again returns the existing record instead of creating duplicates.

Communication messages

Each message has: Rules to remember:
  • Replies must reference a parent_message_id that exists in the same thread. Cross-thread replies are rejected.
  • At least one of subject, body_text, or body_html is required when creating a message.
  • Internal notes (direction: internal, message_type: internal_note) are visible to agents only. They do not emit customer reply journey events.

Ticket communication_summary

When you fetch a single ticket (GET /tickets/{id}), the response includes communication_summary: a rollup across all threads on that ticket (thread count, latest preview, total unread, dominant channel). Use this for list views and board cards without loading every message.

Events emitted (for journeys and webhooks)

Ticket and communication actions publish internal behavior events. Common ones: See Ticket Journey Triggers to automate follow-ups when these events occur.

Dashboard vs API

For step-by-step API recipes and copy-paste examples, continue with the Ticket management guide.