CloudSignal Docs
ExtensionsIntegration

Push notifications API

Send web push notifications to your PWA users via HTTP REST endpoints - ideal for serverless functions, webhooks, and backend services.

The Push Notifications API sends web push notifications to your PWA users from your backend services. Use it for:

Use caseExamples
Transactional notificationsOrder updates, password resets, alerts
Marketing campaignsBroadcast announcements to all users
Real-time alertsSystem status, security notifications
Serverless functionsAWS Lambda, Vercel, Cloudflare Workers

This API requires the Push Notifications extension to be enabled. See Push Notifications Extension for setup.

How it works

Push notifications API
Your Backend
CloudSignal
User's Browser
POST /v2/push/send
Web Push Protocol
200 OK

Your HTTP request triggers web push notifications to targeted PWA clients.

Authentication

All Push API endpoints use Secret Key authentication via the X-Secret-Key header.

Your secret key has full access to your organization. Never expose it in client-side code.

Find your secret key in Dashboard → Settings → API Keys.

Getting started

Enable push notifications extension

  1. Go to Dashboard → Extensions
  2. Find Push Notifications
  3. Click Enable and complete the setup wizard
  4. Configure your VAPID keys and allowed origins

Get your secret key

  1. Go to Dashboard → Settings → API Keys
  2. Copy your Secret Key (starts with sk_)

Send your first notification

curl -X POST https://api.cloudsignal.io/v2/push/send \
  -H "Content-Type: application/json" \
  -H "X-Secret-Key: sk_your_secret_key" \
  -d '{
    "title": "Hello!",
    "body": "This is your first push notification",
    "target_all": true
  }'

API reference

Base URL

https://api.cloudsignal.io/v2/push

Headers

All requests require:

  • X-Secret-Key: Your organization secret key
  • Content-Type: application/json

Send notification

Send targeted push notifications to specific users or devices.

POST /v2/push/send

Request body

{
  "title": "string",           // Required: Notification title (max 100 chars)
  "body": "string",            // Required: Notification body (max 255 chars)
  "icon": "string",            // Optional: Icon URL
  "badge": "string",           // Optional: Badge URL
  "image": "string",           // Optional: Large image URL
  "tag": "string",             // Optional: Tag for grouping notifications
  "data": {},                  // Optional: Custom data payload
  "urgency": "normal",         // Optional: very-low, low, normal, high
  "ttl": 86400,               // Optional: Time-to-live in seconds (max 28 days)
  
  // Targeting (use ONE of these)
  "target_all": false,                    // Send to all clients
  "target_user_emails": ["user@example.com"],  // Target by email
  "target_user_ids": ["uuid-..."],        // Target by user ID
  "target_registration_ids": ["uuid-..."] // Target specific devices
}

Targeting options

Choose one targeting method per request:

OptionBehavior
target_all: trueBroadcast to all registered clients
target_user_emailsSend to users by email address
target_user_idsSend to users by their user ID
target_registration_idsSend to specific device registrations

Response

Success (200)

{
  "request_id": "req_abc123",
  "total_targets": 150,
  "successful_sends": 148,
  "failed_sends": 2,
  "invalid_registrations": ["uuid-expired-device"],
  "message": "Notifications sent successfully",
  "status": "completed"
}

Async Processing (200)

For large batches (>100 recipients), notifications are queued:

{
  "request_id": "req_xyz789",
  "total_targets": 5000,
  "successful_sends": 0,
  "failed_sends": 0,
  "invalid_registrations": [],
  "message": "Notifications queued for processing",
  "status": "queued"
}

Broadcast notification

Convenience endpoint to send to all registered clients.

POST /v2/push/broadcast

Same request body as /send, but target_all is automatically set to true.

{
  "title": "System Update",
  "body": "We've released exciting new features!",
  "urgency": "normal"
}

Get notification quota

Check your notification quota usage.

GET /v2/push/quota

Response

{
  "organization_id": "org_abc123",
  "service_id": "svc_xyz789",
  "hourly_limit": 1000,
  "daily_limit": 10000,
  "hourly_remaining": 850,
  "daily_remaining": 9200,
  "reset_hourly_at": "2024-01-15T15:00:00Z",
  "reset_daily_at": "2024-01-16T00:00:00Z"
}

List clients

List registered push notification clients.

GET /v2/push/clients

Query parameters

  • status - Filter by status: active, inactive, expired, unregistered
  • user_email - Filter by user email
  • limit - Max results (default 100, max 1000)
  • offset - Pagination offset

Response

{
  "clients": [
    {
      "registration_id": "reg_abc123",
      "organization_id": "org_xyz",
      "service_id": "svc_123",
      "status": "active",
      "is_active": true,
      "is_online": false,
      "is_installed": true,
      "is_subscribed": true,
      "user_email": "user@example.com",
      "last_active": "2024-01-15T10:30:00Z",
      "notification_count": 42,
      "device_info": {
        "browser_name": "Chrome",
        "browser_version": "120",
        "os_name": "Windows",
        "device_type": "desktop"
      },
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "total": 150,
  "limit": 100,
  "offset": 0
}

Get client status

Get details for a specific client registration.

GET /v2/push/clients/{registration_id}

Returns the same client object structure as the list endpoint.


Deregister client

Remove a client from push notifications.

DELETE /v2/push/clients/{registration_id}?reason=user_requested

Query parameters

  • reason - Optional reason for deregistration

Response

{
  "success": true,
  "registration_id": "reg_abc123",
  "message": "Client deregistered successfully"
}

Get service info

Get your PWA service configuration and statistics.

GET /v2/push/service

Response

{
  "service_id": "svc_abc123",
  "organization_id": "org_xyz",
  "service_identifier": "my-app",
  "service_name": "My Application",
  "vapid_public_key": "BKxxx...",
  "contact_email": "admin@example.com",
  "notifications_enabled": true,
  "is_active": true,
  "hourly_notification_limit": 1000,
  "daily_notification_limit": 10000,
  "active_registrations": 1500,
  "push_subscribers": 1200
}

Code examples

// Node.js / Edge Functions
async function sendPushNotification(options) {
  const response = await fetch('https://api.cloudsignal.io/v2/push/send', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Secret-Key': process.env.CLOUDSIGNAL_SECRET_KEY
    },
    body: JSON.stringify({
      title: options.title,
      body: options.body,
      target_user_emails: options.emails,
      data: options.data
    })
  });

  if (!response.ok) {
    throw new Error(`Push failed: ${response.status}`);
  }

  return response.json();
}

// Send to specific users
await sendPushNotification({
  title: 'Order Shipped!',
  body: 'Your order #12345 is on its way',
  emails: ['customer@example.com'],
  data: { orderId: '12345', trackingUrl: 'https://...' }
});
import os
import requests

def send_push_notification(
    title: str,
    body: str,
    emails: list[str] = None,
    broadcast: bool = False
):
    payload = {
        'title': title,
        'body': body,
    }
    
    if broadcast:
        payload['target_all'] = True
    elif emails:
        payload['target_user_emails'] = emails
    
    response = requests.post(
        'https://api.cloudsignal.io/v2/push/send',
        headers={
            'Content-Type': 'application/json',
            'X-Secret-Key': os.environ['CLOUDSIGNAL_SECRET_KEY']
        },
        json=payload
    )
    response.raise_for_status()
    return response.json()

# Send to all users
send_push_notification(
    title='New Feature!',
    body='Check out our latest update',
    broadcast=True
)
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
    "os"
)

type PushRequest struct {
    Title           string   `json:"title"`
    Body            string   `json:"body"`
    TargetAll       bool     `json:"target_all,omitempty"`
    TargetUserEmails []string `json:"target_user_emails,omitempty"`
}

func sendPushNotification(req PushRequest) error {
    body, _ := json.Marshal(req)

    r, _ := http.NewRequest("POST",
        "https://api.cloudsignal.io/v2/push/send",
        bytes.NewBuffer(body))
    
    r.Header.Set("Content-Type", "application/json")
    r.Header.Set("X-Secret-Key", os.Getenv("CLOUDSIGNAL_SECRET_KEY"))

    resp, err := http.DefaultClient.Do(r)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    
    return nil
}
# Send to specific users
curl -X POST https://api.cloudsignal.io/v2/push/send \
  -H "Content-Type: application/json" \
  -H "X-Secret-Key: $CLOUDSIGNAL_SECRET_KEY" \
  -d '{
    "title": "Password Reset",
    "body": "Click to reset your password",
    "target_user_emails": ["user@example.com"],
    "urgency": "high"
  }'

# Broadcast to all
curl -X POST https://api.cloudsignal.io/v2/push/broadcast \
  -H "Content-Type: application/json" \
  -H "X-Secret-Key: $CLOUDSIGNAL_SECRET_KEY" \
  -d '{
    "title": "Maintenance Notice",
    "body": "System maintenance at 2 AM UTC"
  }'

# Check quota
curl https://api.cloudsignal.io/v2/push/quota \
  -H "X-Secret-Key: $CLOUDSIGNAL_SECRET_KEY"

Error handling

Error codes

CodeHTTP StatusDescription
UNAUTHORIZED401Invalid or missing secret key
FORBIDDEN403Secret key doesn't have permission
INVALID_REQUEST400Malformed JSON or missing required fields
NOT_FOUND404Client registration not found
RATE_LIMITED429Too many requests
QUOTA_EXCEEDED429Notification quota exceeded
SERVICE_UNAVAILABLE503Push service temporarily unavailable

Error response

{
  "detail": "Notification quota exceeded for today"
}

Rate limits

Rate limits depend on your plan:

PlanHourly LimitDaily Limit
Starter1001,000
Professional1,00010,000
Scale10,000100,000

Async processing

For large notification batches (>100 recipients):

  1. Request returns immediately with status: "queued"
  2. Notifications are processed in the background
  3. Check delivery status via the clients endpoint

Force async mode for any request by setting async_mode: true in the request body.

Best practices

PracticeWhy
Use meaningful tagsGroup related notifications to replace old ones
Set appropriate urgencyUse high only for critical alerts
Include action dataPass URLs or IDs in the data field for client handling
Handle failuresCheck failed_sends and invalid_registrations in responses
Monitor quotaImplement quota checks before large broadcasts
Clean up clientsDeregister clients that consistently fail

Troubleshooting

Notifications not delivered

  1. Check client status is active with is_subscribed: true
  2. Verify VAPID keys match between service and client
  3. Check notification quota hasn't been exceeded
  4. Verify allowed origins include client's origin

High failure rate

  1. Check for expired push subscriptions
  2. Verify payload size is within limits
  3. Review invalid_registrations in response
  4. Client may have revoked notification permissions

Next steps

On this page