# Managing Notification Templates

https://dev.wisecp.com/uk/managing-notification-templates

The five endpoints that list, add, read, edit and remove notification templates.

## Overview

A notification template lives in two places. Its **behaviour** sits in the settings file: whether it is on, who it reaches and by which channel. Its **text** sits in separate files per language: the subject, the e-mail body and the message.

That split reaches the endpoints. The listing gives the behaviour alone, and seeing the text wants one template read on its own.

Templates fall into groups and a group brings its own rules: attaching the invoice document means something in the invoice group and is ignored in the others.

## Reference

### Listing the Templates

get/api/v1/admin/notifications/templates

`Notifications/GetNotificationTemplates` admin

Returns every notification template under its group.

Response fields data[] — 3

groupstringThe group key.

namestringThe group's translated name.

templatesarray templates[]The templates in the group.

groupstringThe group it sits in.

keystringThe template key.

namestringIts translated name.

statusintWhether the template is on.

customboolWhether it was added by hand.

user_mailintWhether the client gets an e-mail.

admin_mailintWhether the staff get an e-mail.

user_smsintWhether the client gets a message.

admin_smsintWhether the staff get a message.

send_pdfintWhether the invoice document is attached. It comes empty outside the invoice group.

emailsstringExtra e-mail recipients.

phonesstringExtra phone recipients.

departmentsint[]The department ids tied to it.

variablesstringThe variables the template can use.

Errors 1

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/notifications/templates' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/notifications/templates', {
  headers: { Authorization: `Bearer ${apiKey}` },
});

const { data } = await res.json();
const flat = data.flatMap((g) => g.templates);
const off  = flat.filter((t) => ! t.status);
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/templates');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The list is GROUPED and carries NO content: the subject and body come on the detail endpoint.
$groups = Api::Notifications()->GetNotificationTemplates()['data'];
$flat   = array_merge(...array_column($groups, 'templates'));
```

### Adding a Template

post/api/v1/admin/notifications/templates

`Notifications/CreateNotificationTemplate` admin

Opens a new template under a group.

Body 2

groupstringreqThe group key.

keystringreqThe template key. A slash, dot or comma becomes a hyphen.

Response fields 201 — data — 14

dataobjectThe template made. Same shape as a template in the listing.

Errors 6

group_required422No group was given.

key_required422No key was given.

invalid_group422The group was sent as a list or an object instead of text.

invalid_key422The key was sent as a list or an object instead of text.

already_exists422A template with that group and key exists.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/notifications/templates' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"group":"account","key":"welcome-message"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/notifications/templates', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ group: 'account', key: 'welcome-message' }),
});

const { data } = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/templates');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['group' => 'account', 'key' => 'welcome-message']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// A new template is born EMPTY and the core never sends it by itself; you write the content and the trigger.
Api::Notifications()->CreateNotificationTemplate(['group' => 'account', 'key' => 'welcome-message']);
Api::Notifications()->UpdateNotificationTemplate([
    'group' => 'account', 'key' => 'welcome-message',
    'contents' => ['en' => ['subject' => 'Welcome', 'mail_content' => $html]],
]);
```

### Reading a Template

get/api/v1/admin/notifications/templates/{group}/{key}

`Notifications/GetNotificationTemplate` admin

Returns a template's settings and its text in every language.

Response fields data — 15

groupstringThe group it sits in.

keystringThe template key.

namestringIts translated name.

statusintWhether the template is on.

customboolWhether it was added by hand.

user_mailintWhether the client gets an e-mail.

admin_mailintWhether the staff get an e-mail.

user_smsintWhether the client gets a message.

admin_smsintWhether the staff get a message.

send_pdfintWhether the invoice document is attached. It comes empty outside the invoice group.

emailsstringExtra e-mail recipients.

phonesstringExtra phone recipients.

departmentsint[]The department ids tied to it.

variablesstringThe variables the template can use.

contentsobject contents.The text per language.

subjectstringThe e-mail subject.

mail_contentstringThe e-mail body.

sms_contentstringThe message text.

Errors 2

not_found404No such template.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/notifications/templates/invoice/invoice-created' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/notifications/templates/${group}/${key}`, {
  headers: { Authorization: `Bearer ${apiKey}` },
});

const { data } = await res.json();
const missing = langs.filter((l) => ! data.contents[l]?.subject);
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/templates/' . $group . '/' . $key);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The variables you may use are written here; another one written into a template goes out as TEXT.
$t = Api::Notifications()->GetNotificationTemplate(['group' => $g, 'key' => $k])['data'];
$allowed = $t['variables'];
```

### Updating a Template

patch/api/v1/admin/notifications/templates/{group}/{key}

`Notifications/UpdateNotificationTemplate` admin

Writes the settings and text you send and leaves the rest alone.

Body 10

statusintWhether the template is on.

user_mailintWhether the client gets an e-mail.

admin_mailintWhether the staff get an e-mail.

user_smsintWhether the client gets a message.

admin_smsintWhether the staff get a message.

send_pdfintWhether the invoice document is attached. It is ignored outside the invoice group.

emailsstringExtra e-mail recipients, separated by commas or new lines.

phonesstringExtra phone recipients, separated by commas or new lines.

departmentsint[]The department ids. The list replaces rather than adds.

contentsobject contents.The text per language.

subjectstringThe e-mail subject.

mail_contentstringThe e-mail body.

sms_contentstringThe message text.

Response fields data — 15

dataobjectThe template as it now stands. Same shape as the read endpoint.

Errors 13

not_found404No such template.

invalid_emails422The e-mail recipients were sent as a list or an object instead of text.

invalid_phones422The phone recipients were sent as a list or an object instead of text.

invalid_status422The on and off switch was sent as a list or an object.

invalid_user_mail422The client e-mail switch was sent as a list or an object.

invalid_admin_mail422The staff e-mail switch was sent as a list or an object.

invalid_user_sms422The client message switch was sent as a list or an object.

invalid_admin_sms422The staff message switch was sent as a list or an object.

invalid_send_pdf422The invoice document switch was sent as a list or an object.

invalid_departments422A department in the list is a list or an object instead of an id.

invalid_contents422The text is not grouped by language, or one of its parts is not text.

config_write_failed422The settings file could not be written.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PATCH 'https://panel.example.com/api/v1/admin/notifications/templates/invoice/invoice-created' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"status":1,"user_mail":1,"departments":[1,2]}'
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/notifications/templates/${group}/${key}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    status: 1,
    contents: { en: { subject: 'Your invoice', mail_content: html } },
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/templates/' . $group . '/' . $key);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['status' => 1]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The department list REPLACES what was there; read it first to add one.
$t = Api::Notifications()->GetNotificationTemplate(['group' => $g, 'key' => $k])['data'];
$t['departments'][] = $newDid;

Api::Notifications()->UpdateNotificationTemplate([
    'group' => $g, 'key' => $k, 'departments' => $t['departments'],
]);
```

### Removing a Template

delete/api/v1/admin/notifications/templates/{group}/{key}

`Notifications/DeleteNotificationTemplate` admin

Removes a template and its text in every language.

Response fields data — 3

deletedboolWhether the delete ran.

groupstringThe group key.

keystringThe key of the template removed.

Errors 2

not_found404No such template.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X DELETE 'https://panel.example.com/api/v1/admin/notifications/templates/account/welcome-message' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/notifications/templates/${group}/${key}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/templates/' . $group . '/' . $key);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// Removing one of the CORE's own templates silences that event entirely; turning the state off is enough.
Api::Notifications()->UpdateNotificationTemplate(['group' => $g, 'key' => $k, 'status' => 0]);
```

## Pitfalls

> **The department list replaces what was there**
> 
> The department list you send on an update **replaces** the one there. Sending only the department you meant to add takes the others out and they stop getting the notification. Read it first and merge the list.

> **An unknown variable goes out as text**
> 
> The variables a template may use are written on its own record. Writing one that is not in that list **raises no error**; the notification goes out and the client sees the raw braces. Read the list allowed before writing the text.

> **A new template is never sent by itself**
> 
> A template added by hand is a record and nothing more: **no event** in the core fires it. A module or a hook has to call it for anything to go out. Turning the template on produces no message on its own.

> **Two templates have their state tied to the sign-up setting**
> 
> The on and off state of the e-mail and phone verification templates moves together with the **sign-up verification setting**. Closing the template closes the verification step in the sign-up flow as well. Changing it as though it were a display setting drops verification for new members.

> **The document attachment falls away quietly outside its group**
> 
> The setting that attaches the invoice document works in the invoice group alone. Sending it on another group's template **raises no error**: the value is ignored and comes back empty on the read. That is not the save failing.

> **A wrong type stops the whole update**
> 
> A list or an object sent where text or 0 and 1 are expected is **refused** with 422. Nothing in that request is saved, not even the fields that were right. Fix the field named in the error and send the request again.

## Related Articles

- [Notification Layout](https://dev.wisecp.com/en/notification-layout)
- [Staff Departments](https://dev.wisecp.com/en/staff-departments)
- [Language Packages](https://dev.wisecp.com/en/language-packages)
