# Sending Notifications

https://dev.wisecp.com/es/sending-notifications

The five endpoints that send a client a template, an e-mail or an SMS, and read the result back.

## Overview

These endpoints send a message to a client and read back what was sent. There are three ways to send: a stored template, a free e-mail and a free SMS.

Every send is **synchronous**. The response comes after the dispatch attempt finishes; nothing is queued. A slow provider slows your request down with it.

## Reference

### Previewing the Recipients

get/api/v1/admin/clients/{id}/notifications/recipients

`Clients/GetClientNotificationRecipients` admin sends nothing

Returns who a template would reach, without sending anything.

Query parameters 2

templatestringThe template id, in `group/name` form.

channelstring`email` or `sms`. Give it and you get only that channel's recipients.

Response fields data — 2

mailobject[]The e-mail recipients. Each element carries `email` and `name`.

smsobject[]The SMS recipients. An empty array when the client has no phone.

Errors 3

not_found404No such client.

template_invalid422`template` is not in `group/name` form.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -G 'https://panel.example.com/api/v1/admin/clients/42/notifications/recipients' \
  -H "Authorization: Bearer $API_KEY" \
  -d template=user/welcome
```

```javascript
const url = new URL('https://panel.example.com/api/v1/admin/clients/42/notifications/recipients');
url.searchParams.set('template', 'user/welcome');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
```

```php
$url = 'https://panel.example.com/api/v1/admin/clients/42/notifications/recipients?' . http_build_query(['template' => 'user/welcome']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

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

```php
// Check for recipients first: a template with none comes back as a 500.
$preview = Api::Clients()->GetClientNotificationRecipients([
    'id'       => 42,
    'template' => 'user/welcome',
], ['channel' => 'email']);

if (!($preview['data']['mail'] ?? [])) {
    return;
}
```

Response 200

```json
{
  "data": {
    "mail": [
      { "email": "john@example.com", "name": "John Doe" }
    ],
    "sms": []
  }
}
```

### Sending a Template

post/api/v1/admin/clients/{id}/notifications/template

`Clients/SendClientTemplate` admin synchronous

Sends a stored notification template to the client.

Body 2

templatestringrequiredThe template id, in `group/name` form. Both halves have to be filled: `user/welcome`.

channelstring`email` or `sms`. Defaults to `email`.

Response fields data — 3

sentboolAlways `true`. A failure comes back as an error, not as a value in this field.

channelstringThe channel that was used.

templatestringId of the template that was sent.

Errors 4

not_found404No such client.

template_invalid422`template` is not in `group/name` form.

send_failed500The dispatch failed.

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/clients/42/notifications/template' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"template":"user/welcome","channel":"email"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/notifications/template', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ template: 'user/welcome', channel: 'email' }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/notifications/template');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'template' => 'user/welcome',
        'channel'  => 'email',
    ]),
]);

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

```php
$response = Api::Clients()->SendClientTemplate([
    'id'       => 42,
    'template' => 'user/welcome',
    'channel'  => 'email',
]);
```

### Sending a Custom E-mail

post/api/v1/admin/clients/{id}/notifications/email

`Clients/SendClientEmail` admin synchronous

Sends an e-mail with a free subject and body, without going through a template.

Body 3

subjectstringrequiredThe subject line.

messagestringrequiredThe body.

copy_to_adminboolCopies the sending admin. Off by default.

Response fields data — 1

sentboolAlways `true`.

Errors 5

not_found404No such client.

subject_required422`subject` was empty.

message_required422`message` was empty.

send_failed500The dispatch failed **or there was no valid recipient**.

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/clients/42/notifications/email' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"subject":"An update about your account","message":"Hello, your request has been processed.","copy_to_admin":true}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/notifications/email', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    subject: 'An update about your account',
    message: 'Hello, your request has been processed.',
    copy_to_admin: true,
  }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/notifications/email');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'subject'       => 'An update about your account',
        'message'       => 'Hello, your request has been processed.',
        'copy_to_admin' => true,
    ]),
]);

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

```php
$response = Api::Clients()->SendClientEmail([
    'id'      => 42,
    'subject' => 'An update about your account',
    'message' => 'Hello, your request has been processed.',
]);

// 'send_failed' covers both a failed dispatch and no recipient at all.
$failed = ($response['error']['code'] ?? '') === 'send_failed';
```

### Sending a Custom SMS

post/api/v1/admin/clients/{id}/notifications/sms

`Clients/SendClientSms` admin synchronous

Sends the client an SMS with free content.

Body 1

messagestringrequiredThe message body.

Response fields data — 1

sentboolAlways `true`.

Errors 4

not_found404No such client.

message_required422`message` was empty.

send_failed500The dispatch failed or there was no valid recipient.

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/clients/42/notifications/sms' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"message":"Hello, your request has been processed."}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/notifications/sms', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ message: 'Hello, your request has been processed.' }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/notifications/sms');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['message' => 'Hello, your request has been processed.']),
]);

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

```php
$response = Api::Clients()->SendClientSms([
    'id'      => 42,
    'message' => 'Hello, your request has been processed.',
]);
```

### Reading a Sent Message

get/api/v1/admin/clients/messages/preview

`Clients/GetMessagePreview` admin decrypted

Returns the content of an e-mail or SMS that was sent earlier.

Query parameters 2

typestringrequired`email` ya da `sms`.

idintrequiredThe log record id. Not the client id, the record's own id.

Response fields data — 2

typestringThe record type.

contentstringThe decrypted message content.

Errors 2

invalid_request422`type` or `id` is missing or invalid.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -G 'https://panel.example.com/api/v1/admin/clients/messages/preview' \
  -H "Authorization: Bearer $API_KEY" \
  -d type=email \
  -d id=901
```

```javascript
const url = new URL('https://panel.example.com/api/v1/admin/clients/messages/preview');
url.searchParams.set('type', 'email');
url.searchParams.set('id', '901');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
```

```php
$url = 'https://panel.example.com/api/v1/admin/clients/messages/preview?' . http_build_query(['type' => 'email', 'id' => 901]);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

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

```php
$response = Api::Clients()->GetMessagePreview([], [
    'type' => 'email',
    'id'   => 901,
]);

$content = $response['data']['content'];
```

## Pitfalls

> **The sent field is always true**
> 
> The `sent` field in the response is a constant, not an outcome. A failure arrives as an error body, not as this field turning `false`. Branch on the error code, not on the field.

> **A send with no recipient returns a 500**
> 
> If the client has no e-mail or phone the error is `send_failed`. That is not a server fault, it is the absence of a recipient. To tell them apart, call the preview endpoint first and skip the send when the list comes back empty.

> **The request waits for the dispatch**
> 
> Nothing is queued. If you are writing a batch job you pay the provider's response time for every client, so set your timeout accordingly.

## Related Articles

- [Client Endpoints](https://dev.wisecp.com/en/client-endpoints)
- [Account State and Bulk Actions](https://dev.wisecp.com/en/account-state-and-bulk-actions)
