Send customer notifications

Send order confirmations, payment receipts, shipping updates, and reminders to your customers by SMS or email. Chime tracks delivery status and lets you retry safely with idempotency keys. This guide shows you how to notify customers immediately or schedule messages for future delivery.


How it works

Notifications work in two phases: create the Chime with your message content and recipient details, then query delivery status when you need confirmation. Messages send immediately or at a scheduled time. Chime routes SMS to phone numbers and email to email addresses. Every Chime tracks its transmission lifecycle—initialized, sent, delivered, or failed—so you can determine whether a transmission has started and whether delivery was confirmed.

For email recipients, include a top-level email object with subject, text, and from.address, and omit full_message. Commerce validates the sender, rejects header injection, scans links and HTML, and only sends sanitized content that passes the safety policy.

{
  "recipient": {
    "type": "email",
    "email": {
      "address": "[email protected]"
    }
  },
  "email": {
    "subject": "Your receipt is ready",
    "text": "Your receipt is ready. View it at https://yourstore.example/receipts/or_7821.",
    "from": {
      "address": "[email protected]"
    }
  }
}

Step 1: Send a notification immediately

Send a notification right away when order status changes, payment completes, or any event requires immediate customer awareness. Call Send Chime with one of two recipient shapes: use type plus the matching phone.number or email.address for an inline contact, or use transport plus customer_id for a saved customer. Never combine transport with inline contact details.

Send notification

POST
/chimes/send
curl https://api.zebo.dev/chimes/send \
  -H "Authorization: Bearer $COMMERCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": {
      "type": "phone",
      "phone": {
        "number": "+233544998605"
      },
      "name": "Gloria Kesewaa"
    },
    "full_message": "Your order #OR-7821 has been confirmed. Total: GHS 200.00. Expected delivery: Dec 18-20. Track here: https://pages.zebo.dev/invoices/track/OR-7821",
    "sender": "YourStore",
    "purpose": "notification",
    "request_meta": {
      "idempotency_key": "notify_order_OR-7821_confirmed"
    },
    "custom_data": {
      "order_id": "OR-7821",
      "event": "order_confirmed",
      "customer_id": "cu_gloria_k"
    }
  }'

The Chime API responds immediately with a Chime ID and initial transmission status. Actual delivery happens asynchronously—SMS typically delivers within seconds, email within a minute.

Using idempotency keys

Pass request_meta.idempotency_key or the Idempotency-Key header to prevent duplicate notifications during retries. If your server crashes after sending but before recording the send, retry with the same key—Chime returns the original notification instead of sending again. This protects customers from receiving confusing duplicate messages for payment confirmations, order updates, and other critical events.

Attaching metadata

Use custom_data to link notifications back to your internal records. Store order IDs, customer IDs, event types, or any context you need for analytics and debugging. Query Chimes later to retrieve this metadata for reconciliation or support investigations.


Step 2: Check delivery status

Verify notification delivery by calling Lookup Chime with the Chime ID. The response includes transmission status, delivery timestamps, and all metadata from creation.

Check delivery

POST
/chimes/lookup
curl https://api.zebo.dev/chimes/lookup \
  -H "Authorization: Bearer $COMMERCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chime_id": "WkPvqTrqGsopu07wfC7ttoWqmfwt48ZW7BGvYU"
  }'

Status values indicate message progress: initialized means a transmission exists but has not been sent, sent means the message was handed off but delivery is not confirmed, delivered means delivery was confirmed, and failed means the transmission could not complete.


Schedule notifications for future delivery

Schedule Chimes when you need notifications delivered at specific future times—subscription renewal reminders, appointment confirmations, or time-based marketing campaigns. Call Schedule Chime with the message, send_after, and recipient objects. Inline recipients use type plus a matching phone or email object; saved customers use transport plus customer_id.

Schedule notification

POST
/chimes/schedule
curl https://api.zebo.dev/chimes/schedule \
  -H "Authorization: Bearer $COMMERCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": [
      { "type": "phone", "phone": { "number": "+233544998605" } },
      { "type": "phone", "phone": { "number": "+233501234567" } }
    ],
    "full_message": "Reminder: Your subscription renews in 3 days on Dec 18. Update payment details at https://pages.zebo.dev/invoices/billing or contact support.",
    "send_after": "2025-12-15T09:00:00Z",
    "sender_id": "YourBrand",
    "purpose": "reminder"
  }'

Scheduled Chimes deliver at or shortly after the specified time. Commerce resolves every saved customer and validates every inline phone number or email address before accepting the schedule. A malformed or unresolved recipient rejects the request; later transmission failures remain isolated to the affected recipient.


Crafting effective notifications

Front-load critical information

Put order numbers, amounts, dates, or urgency first. "Order #OR-7821 shipped. Arrives Dec 18-20" beats "We're excited to inform you that your recent order has been shipped and should arrive soon."

Include actionable links

Always provide next steps: order tracking URLs, payment confirmation pages, or support contact forms. Make URLs meaningful—checkout.zebo.dev/track/OR-7821 tells customers where they're going before they click.

Keep SMS under 160 characters

SMS charges per 160-character segment. Long messages split across multiple texts and confuse recipients. If you need more space, use email instead or shorten the message and link to details.

Use idempotency for critical messages

Payment confirmations, order receipts, and account alerts demand idempotency. Pass a unique key through request_meta.idempotency_key or the Idempotency-Key header constructed from the event—notify_payment_${payment_id}_confirmed—to prevent duplicate notifications during retries.


Next steps

  • Chime API Reference — Complete endpoint documentation and response formats
  • Product: Chime — Deep dive into Chime features and use cases
  • OTP API — Send verification codes for authentication flows
  • Orders — Trigger notifications from order events

Was this page helpful?