Macros
Saved replies with automated side-effects an agent applies in one click.
Download the full API pública projection: openapi.json.
Automate replies and assignment explains this resource in prose, with runnable examples.
| Method | Path | What it does |
|---|---|---|
GET | /macros | List macros |
POST | /macros | Create a macro |
DELETE | /macros/{id} | Delete a macro |
GET | /macros/{id} | Fetch one macro |
PUT | /macros/{id} | Update a macro |
GET | /macros/{id}/prepare | Resolve a macro for the composer |
GET /macros
List macros
Every macro in the workspace with its content, actions, params and usage counters. Unfiltered — active, visibility and available_for come back on each row for the caller to filter on, and inactive macros are included.
curl https://api.vitrinadev.com/api/v1/macros \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"id": "d3d3d3d3-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Cierre agradecido",
"description": "Agradece, etiqueta como resuelto y cambia el estado del ticket.",
"category": "cierre",
"content": "Gracias por escribirnos, [[nombre]]. Cualquier otra duda, aquí estamos.",
"shortcut": "cierre",
"actions": [
{
"id": "a1",
"type": "add_tag",
"value": [
"resuelto"
]
},
{
"id": "a2",
"type": "change_status",
"value": "resolved"
}
],
"params": [
{
"key": "nombre",
"label": "Nombre del cliente",
"input_type": "text"
}
],
"icon": "play",
"visibility": "public",
"available_for": "everyone",
"run_when": [
"manual"
],
"active": true,
"usage_count": 42,
"last_used_at": "2026-09-15T18:20:00.000Z",
"created_at": "2026-01-10T13:00:00.000Z",
"updated_at": "2026-09-10T13:00:00.000Z"
}
],
"meta": {
"total": 1
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /macros
Create a macro
Only name is required. An action-only macro is valid — one that just changes status and adds a label, with no content, is a normal thing to build.
actions is an untyped list: the step objects are stored as given and validated only when the macro RUNS. A typo in a step type creates cleanly and then reports unknown action type on every execution, so run a macro once after authoring it.
Each entry in params declares one [[manual]] placeholder, and its key must match the placeholder text in content for the composer to pair them up. Defaults: icon: "play", visibility: "public", available_for: "everyone", run_when: ["manual"], active: true. Answers 201.
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | yes | mín. 1, máx. 200 |
description | string | null | — | máx. 2000 |
category | string | null | — | máx. 100 |
content | string | — | máx. 8000, por defecto "" |
shortcut | string | null | — | máx. 50 |
actions | any[] | — | |
params | object[] | — | |
icon | string | — | máx. 60 |
visibility | public \ | private | — |
available_for | string | — | máx. 120 |
run_when | string[] | — | |
active | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/macros \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Cierre agradecido",
"content": "Gracias por escribirnos, [[nombre]]. Cualquier otra duda, aquí estamos.",
"actions": [
{
"id": "a1",
"type": "add_tag",
"value": [
"resuelto"
]
}
],
"params": [
{
"key": "nombre",
"label": "Nombre del cliente",
"input_type": "text"
}
]
}'Example response (201)
{
"data": {
"id": "d3d3d3d3-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Cierre agradecido",
"description": "Agradece, etiqueta como resuelto y cambia el estado del ticket.",
"category": "cierre",
"content": "Gracias por escribirnos, [[nombre]]. Cualquier otra duda, aquí estamos.",
"shortcut": "cierre",
"actions": [
{
"id": "a1",
"type": "add_tag",
"value": [
"resuelto"
]
},
{
"id": "a2",
"type": "change_status",
"value": "resolved"
}
],
"params": [
{
"key": "nombre",
"label": "Nombre del cliente",
"input_type": "text"
}
],
"icon": "play",
"visibility": "public",
"available_for": "everyone",
"run_when": [
"manual"
],
"active": true,
"usage_count": 42,
"last_used_at": "2026-09-15T18:20:00.000Z",
"created_at": "2026-01-10T13:00:00.000Z",
"updated_at": "2026-09-10T13:00:00.000Z"
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /macros/{id}
Delete a macro
Removes the macro. Everything it already did — messages sent, labels applied, status changes — stays; a macro is an action, not a relationship. Set active: false to retire one without losing its usage history.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
curl -X DELETE https://api.vitrinadev.com/api/v1/macros/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /macros/{id}
Fetch one macro
The macro as stored, including usage_count and last_used_at.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
curl https://api.vitrinadev.com/api/v1/macros/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"id": "d3d3d3d3-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Cierre agradecido",
"description": "Agradece, etiqueta como resuelto y cambia el estado del ticket.",
"category": "cierre",
"content": "Gracias por escribirnos, [[nombre]]. Cualquier otra duda, aquí estamos.",
"shortcut": "cierre",
"actions": [
{
"id": "a1",
"type": "add_tag",
"value": [
"resuelto"
]
},
{
"id": "a2",
"type": "change_status",
"value": "resolved"
}
],
"params": [
{
"key": "nombre",
"label": "Nombre del cliente",
"input_type": "text"
}
],
"icon": "play",
"visibility": "public",
"available_for": "everyone",
"run_when": [
"manual"
],
"active": true,
"usage_count": 42,
"last_used_at": "2026-09-15T18:20:00.000Z",
"created_at": "2026-01-10T13:00:00.000Z",
"updated_at": "2026-09-10T13:00:00.000Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /macros/{id}
Update a macro
A PUT that behaves as a PATCH; at least one field is required. actions and params are each replaced wholesale when sent, so a step list must be sent complete.
Editing takes effect immediately for anyone about to run it. The usage counters are not editable here.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | — | mín. 1, máx. 200 |
description | string | null | — | máx. 2000 |
category | string | null | — | máx. 100 |
content | string | — | máx. 8000, por defecto "" |
shortcut | string | null | — | máx. 50 |
actions | any[] | — | |
params | object[] | — | |
icon | string | — | máx. 60 |
visibility | public \ | private | — |
available_for | string | — | máx. 120 |
run_when | string[] | — | |
active | boolean | — |
curl -X PUT https://api.vitrinadev.com/api/v1/macros/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"active": false
}'Example response (200)
{
"data": {
"id": "d3d3d3d3-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Cierre agradecido",
"description": "Agradece, etiqueta como resuelto y cambia el estado del ticket.",
"category": "cierre",
"content": "Gracias por escribirnos, [[nombre]]. Cualquier otra duda, aquí estamos.",
"shortcut": "cierre",
"actions": [
{
"id": "a1",
"type": "add_tag",
"value": [
"resuelto"
]
},
{
"id": "a2",
"type": "change_status",
"value": "resolved"
}
],
"params": [
{
"key": "nombre",
"label": "Nombre del cliente",
"input_type": "text"
}
],
"icon": "play",
"visibility": "public",
"available_for": "everyone",
"run_when": [
"manual"
],
"active": false,
"usage_count": 42,
"last_used_at": "2026-09-15T18:20:00.000Z",
"created_at": "2026-01-10T13:00:00.000Z",
"updated_at": "2026-09-10T13:00:00.000Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /macros/{id}/prepare
Resolve a macro for the composer
Renders the macro against a live conversation WITHOUT sending or changing anything. Answers \{ macro, segments, manual_params, effects \}.
segments is the reply broken into resolved text and still-unfilled placeholders, so a composer can render the draft with gaps in place. manual_params is the [[manual]] params the agent must fill, with their input types and options. effects summarises the non-message actions so the agent can see what else pressing send will do.
The reply text is the macro’s FIRST send_message action, falling back to content. A macro with several send_message steps previews only the first here, though running it sends them all.
Read-only and side-effect free — unlike /apply, it does not touch usage_count.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes | |
conversation_id | query | string | yes | mín. 1 |
curl https://api.vitrinadev.com/api/v1/macros/<id>/prepare \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"macro": {
"id": "d3d3d3d3-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Cierre agradecido",
"description": "Agradece, etiqueta como resuelto y cambia el estado del ticket.",
"category": "cierre",
"content": "Gracias por escribirnos, [[nombre]]. Cualquier otra duda, aquí estamos.",
"shortcut": "cierre",
"actions": [
{
"id": "a1",
"type": "add_tag",
"value": [
"resuelto"
]
},
{
"id": "a2",
"type": "change_status",
"value": "resolved"
}
],
"params": [
{
"key": "nombre",
"label": "Nombre del cliente",
"input_type": "text"
}
],
"icon": "play",
"visibility": "public",
"available_for": "everyone",
"run_when": [
"manual"
],
"active": true,
"usage_count": 42,
"last_used_at": "2026-09-15T18:20:00.000Z",
"created_at": "2026-01-10T13:00:00.000Z",
"updated_at": "2026-09-10T13:00:00.000Z"
},
"segments": [
{
"text": "Gracias por escribirnos, ",
"resolved": true
},
{
"text": "[[nombre]]",
"resolved": false
}
],
"manual_params": [
{
"key": "nombre",
"label": "Nombre del cliente",
"input_type": "text"
}
],
"effects": [
"Etiqueta: resuelto",
"Cambia el estado a resolved"
]
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429