VitrinaAPI

Automate replies and assignment

Saved replies an agent applies in one click, and the routing that places conversations.

You fire a macro yourself, from the inbox. An assignment rule runs on its own, with nobody calling it, every time a new conversation arrives.

Macros

A macro holds customer-facing text (content, or a send_message step) and an ordered list of actions. That list takes notes, labels, status changes, snoozing, assigning an agent or a team, and moving a lead's stage. A failing step is recorded and the rest still run. So a 200 with failures inside it is normal.

Reading needs macros:read; CRUD needs macros:write. Running one also needs only macros:read, even though it sends the customer a message and changes ticket state. Keep that in mind when you hand out that scope.

curl -X POST https://api.vitrinadev.com/api/v1/macros \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Grateful close",
    "content": "Thanks for reaching out, [[name]]. Anything else, we are here.",
    "actions": [{ "type": "change_status", "value": "resolved" }],
    "params": [{ "key": "name", "label": "Customer name", "input_type": "text" }]
  }'
{
  "data": {
    "id": "d3d3d3d3-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "name": "Grateful close",
    "content": "Thanks for reaching out, [[name]]. Anything else, we are here.",
    "actions": [{ "id": "a1", "type": "change_status", "value": "resolved" }],
    "params": [{ "key": "name", "label": "Customer name", "input_type": "text" }],
    "active": true,
    "usage_count": 0,
    "created_at": "2026-09-22T13:00:00.000Z",
    "updated_at": "2026-09-22T13:00:00.000Z"
  }
}

Templates carry two kinds of placeholder. {{auto}} resolves on its own from the conversation; [[manual]] is what the agent fills in.

The reviewed flow is two calls. GET /macros/{id}/prepare builds the draft and sends nothing, then POST /macros/{id}/run sends the text the agent approved and runs the steps. POST /macros/{id}/apply is the direct version, with no review, meant for macros without manual params and for automation.

Assignment rules

Routing is ordered and first match wins. Each rule filters on channel (match_channels) and, if you want, on origin (match_sources). It points at a destination: a team or a list of agents. The winner is the first rule, in priority order, whose filter matches and whose destination isn't empty.

Reading needs routing:read; writing, routing:write.

curl -X POST https://api.vitrinadev.com/api/v1/assignment-rules \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "WhatsApp → support team",
    "match_channels": ["whatsapp"],
    "team_id": "cccccccc-0000-4000-8000-000000000001"
  }'
{
  "data": {
    "id": "d5d5d5d5-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "name": "WhatsApp → support team",
    "priority": 0,
    "enabled": true,
    "match_sources": null,
    "match_channels": ["whatsapp"],
    "team_id": "cccccccc-0000-4000-8000-000000000001",
    "assignee_user_ids": null,
    "assignment_mode": "auto_round_robin",
    "is_portal_default": false,
    "created_at": "2026-09-22T13:00:00.000Z",
    "updated_at": "2026-09-22T13:00:00.000Z"
  }
}

A new rule always appends last; sending your own priority is refused. To reorder, call PUT /assignment-rules/order with every id in the new order. It applies all or nothing.

Removing a member with DELETE /memberships/{id} (Team) strips their id from every rule and every channel rotation. Assignment only deals to active members. If you keep your own copy of assignee_user_ids, it can go stale: read it again before you use it.

The full contracts live in the Macros and Assignment rules reference.

On this page