Response Templates API
The Response Templates API manages canned responses (text snippets) that agents insert in the ticket composer. Templates are multilingual (de/en/fr/es/it) and have a scope (PERSONAL / AGENT_GROUP / ORGANIZATION) that drives visibility and management rights. Mount: /api/response-templates.
🔐 Auth: Logged-in users only — API keys get 403, since personal templates are bound to a user. The rights required for a change depend on the template's scope (PERSONAL → manageOwn and owner, shared → manageShared). See RBAC →.
Endpoints
| Method | Endpoint | Description | Permission |
|---|---|---|---|
GET | /api/response-templates | Picker list (visible + active); query search/category → { data } | use |
GET | /api/response-templates/manage | Management list → { data } | manageOwn ‖ manageShared |
POST | /api/response-templates | Create (201) | per scope |
PATCH | /api/response-templates/:id | Update | per scope |
PATCH | /api/response-templates/:id/active | Activate/deactivate { isActive } → 204 | per scope |
DELETE | /api/response-templates/:id | Soft-delete → 204 | per scope |
GET / returns templates insertable in the composer (visible by scope, only isActive). GET /manage returns manageable templates: manageShared sees all shared (ORGANIZATION + AGENT_GROUP) plus own PERSONAL; manageOwn-only sees just own PERSONAL. For changes, per scope: PERSONAL requires manageOwn AND ownership, ORGANIZATION/AGENT_GROUP require manageShared.
Response Shape
Both lists return the templates under data — without page numbers, because the set stays small per user and is delivered in full. The picker list sorts by category, then name; the management list puts the scope first. POST and PATCH :id return the object bare, the two remaining mutations answer 204 with no body.
{
"data": [
{
"id": "clx-tpl-ack",
"name": "Acknowledgement",
"category": "General",
"scope": "ORGANIZATION",
"ownerId": null,
"agentGroupId": null,
"isActive": true,
"translations": {
"de": { "body": "Vielen Dank für Ihre Anfrage. Wir kümmern uns darum." },
"en": { "body": "Thank you for your request. We are on it." }
},
"agentGroup": null
}
]
}
ownerId is set only for PERSONAL — that is how the picker recognises your own templates. For scope AGENT_GROUP, agentGroup carries the target group with id, name and isArchived; templates of archived groups stay visible in management (with a note) and disappear from the picker.
Scopes
| Scope | Visible to | Required field |
|---|---|---|
PERSONAL | owner only | ownerId (set by the server: the logged-in user) |
AGENT_GROUP | active members of the AgentGroup | agentGroupId |
ORGANIZATION | all agents with responseTemplates.use | — |
Create Template
POST /api/response-templates
{
"name": "Acknowledgement",
"category": "General",
"scope": "ORGANIZATION",
"isActive": true,
"translations": {
"de": { "body": "Vielen Dank für Ihre Anfrage. Wir kümmern uns darum." },
"en": { "body": "Thank you for your request. We are on it." }
}
}
// scope AGENT_GROUP — agentGroupId required:{
"name": "Network Standard Reply",
"scope": "AGENT_GROUP",
"agentGroupId": "clx-group-network",
"translations": { "de": { "body": "Bitte starten Sie zunächst Ihren Router neu …" } }
}
Fields: name (1–120), category? (max 60, empty string → null), scope (default PERSONAL), agentGroupId (required only for AGENT_GROUP, forbidden otherwise), translations (record of de/en/fr/es/it → { body 1–5000 }, at least 1 language), isActive (default true). ownerId is always set by the server (the logged-in user). The body is validated strictly: an unknown field is a 400 — so a typo in a field name surfaces immediately instead of being silently ignored. The same applies to the query of GET / (only search, max 200 characters, and category).
Update Template
PATCH /api/response-templates/:id
{ "name": "Acknowledgement (short)", "translations": { "de": { "body": "…" } } }
⚠️ scope cannot be changed on update, because that would change the template's owner and visibility. A GROUP↔ORG move = delete + recreate. An agentGroupId change within AGENT_GROUP is allowed. A PATCH with empty translations is rejected (at least 1 language).
Use in the Ticket Composer
Templates are inserted into the ticket reply composer via the picker (GET /). Since the per-language body limit equals the ticket message limit (5000 chars), the picker checks the combined length (existing text + template) on insert; if it is too long, nothing is inserted and a notice is shown instead of truncating.
🎫 Ticket messages and reply flow: Tickets API →.
Error codes
| Status | errorCode | Meaning |
|---|---|---|
400 | AGENT_GROUP_NOT_ACTIVE | Target group missing, inactive or archived (details names agentGroupId) |
400 | RESPONSE_TEMPLATE_SCOPE_MISMATCH | agentGroupId on a template whose scope has no group |
403 | FORBIDDEN | Right for the scope missing; also for API key calls |
404 | RESPONSE_TEMPLATE_NOT_FOUND | Template does not exist or is not visible to the caller |
410 | RESPONSE_TEMPLATE_DELETED | Visible template has been deleted |
🔒 A personal template belonging to someone else answers every change with 404, not 403: a 403 would confirm that the template exists. Personal templates therefore stay invisible even to managers holding manageShared.
Permissions (responseTemplates)
| Permission | Description |
|---|---|
responseTemplates.use | Use the picker (read + insert visible templates) |
responseTemplates.manageOwn | Create/edit/delete own PERSONAL templates |
responseTemplates.manageShared | Manage ORGANIZATION + AGENT_GROUP templates |
Composer inserts templates into ticket replies
Signatures (separate from text snippets)
AgentGroups for scope AGENT_GROUP
responseTemplates.* rights