The API is under construction and opens first to teams in the early access program. These docs describe the v1 contract it is being built against.

Quickstart: send your first notification

In this guide you send a message, read the response and check whether it was delivered. The examples use email, but the request is the same for SMS and WhatsApp — only channel changes.

Before you start

You'll need:

  • A Notify API key, stored in the NOTIFY_API_KEY environment variable.
  • A template in your account. The examples use one called order_confirmation that expects the name and order_id variables.

Authentication

Every request carries your API key in the Authorization header as a Bearer token. The key identifies your account, so never send a customer ID in the body.

Keep the key out of browsers and mobile apps: call Notify from your backend.

Authorization: Bearer $NOTIFY_API_KEY

Send a message

Make a POST /v1/messages request with the channel, the recipient and the template key. If you pass a locale, Notify picks the template version in that language.

cURL
curl https://api.notify.com.mx/v1/messages \
  -H "Authorization: Bearer $NOTIFY_API_KEY" \
  -H "Idempotency-Key: order-1042-confirmation" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "email",
    "recipient": { "address": "ana@example.com", "locale": "es" },
    "template_key": "order_confirmation",
    "variables": { "name": "Ana", "order_id": "1042" }
  }'
Python
import os
import requests

response = requests.post(
    "https://api.notify.com.mx/v1/messages",
    headers={
        "Authorization": f"Bearer {os.environ['NOTIFY_API_KEY']}",
        "Idempotency-Key": "order-1042-confirmation",
    },
    json={
        "channel": "email",
        "recipient": {"address": "ana@example.com", "locale": "es"},
        "template_key": "order_confirmation",
        "variables": {"name": "Ana", "order_id": "1042"},
    },
    timeout=10,
)
response.raise_for_status()  # 202 Accepted
message = response.json()
print(message["id"], message["status"])
PHP
<?php
$ch = curl_init('https://api.notify.com.mx/v1/messages');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('NOTIFY_API_KEY'),
        'Idempotency-Key: order-1042-confirmation',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'channel' => 'email',
        'recipient' => ['address' => 'ana@example.com', 'locale' => 'es'],
        'template_key' => 'order_confirmation',
        'variables' => ['name' => 'Ana', 'order_id' => '1042'],
    ]),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 202
$message = json_decode($body, true);
echo $message['id'] . ' ' . $message['status'];
JavaScript (Node.js)
const response = await fetch('https://api.notify.com.mx/v1/messages', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NOTIFY_API_KEY}`,
    'Idempotency-Key': 'order-1042-confirmation',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    channel: 'email',
    recipient: { address: 'ana@example.com', locale: 'es' },
    template_key: 'order_confirmation',
    variables: { name: 'Ana', order_id: '1042' },
  }),
});

if (response.status !== 202) throw new Error(await response.text());
const message = await response.json();
console.log(message.id, message.status);

Reading the response: 202, not 200

Notify returns 202 Accepted as soon as the request is validated and queued. That means the message was accepted — not that it was delivered. Delivery happens in the background, with retries if a provider fails.

Keep the id from the response: you'll use it to check the real status.

HTTP/1.1 202 Accepted

{
  "id": "6f1c2a4e-9b7d-4c1e-8a35-2d0f5b9e7c11",
  "status": "accepted",
  "channel": "email",
  "template_key": "order_confirmation",
  "resolved_locale": "es",
  "created_at": "2026-10-05T17:42:08Z"
}

Check whether it arrived

GET /v1/messages/{id} returns the current status plus the history of attempts per provider.

cURL
curl https://api.notify.com.mx/v1/messages/6f1c2a4e-9b7d-4c1e-8a35-2d0f5b9e7c11 \
  -H "Authorization: Bearer $NOTIFY_API_KEY"
{
  "id": "6f1c2a4e-9b7d-4c1e-8a35-2d0f5b9e7c11",
  "status": "delivered",
  "channel": "email",
  "template_key": "order_confirmation",
  "resolved_locale": "es",
  "created_at": "2026-10-05T17:42:08Z",
  "delivered_at": "2026-10-05T17:42:11Z",
  "attempts": [
    {
      "attempt_number": 1,
      "provider": "ses",
      "status": "sent",
      "attempted_at": "2026-10-05T17:42:09Z"
    }
  ]
}

Message statuses

StatusWhat it means
acceptedAccepted and queued; not sent yet.
processingA worker is handing it to the provider.
sentThe provider accepted it. Delivery isn't confirmed yet.
deliveredThe provider confirmed delivery to the recipient.
failedAll retries were exhausted. Check attempts for the reason.
blockedNot sent because the recipient opted out of that channel.

Retry without duplicates

Networks fail. If you don't get a response, retry with the same Idempotency-Key header: Notify returns the original message and never sends twice.

Use a key that identifies the business event — e.g. order-1042-confirmation — not a random value per attempt.

Errors

Errors always include a stable code for your code to branch on and a readable message for your logs. A 422 means the request is well-formed but can't be processed — for example, a template variable is missing. On a 429, wait the number of seconds in the Retry-After header.

HTTP/1.1 422 Unprocessable Entity

{
  "code": "missing_required_variable",
  "message": "Template order_confirmation requires the order_id variable.",
  "details": { "variable": "order_id" }
}

Next steps

Head to the full reference to create multilingual templates, list messages and see every field in the API.

Go to the API reference