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 case | Examples |
|---|---|
| Transactional notifications | Order updates, password resets, alerts |
| Marketing campaigns | Broadcast announcements to all users |
| Real-time alerts | System status, security notifications |
| Serverless functions | AWS Lambda, Vercel, Cloudflare Workers |
This API requires the Push Notifications extension to be enabled. See Push Notifications Extension for setup.
How it works
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
- Go to Dashboard → Extensions
- Find Push Notifications
- Click Enable and complete the setup wizard
- Configure your VAPID keys and allowed origins
Get your secret key
- Go to Dashboard → Settings → API Keys
- 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/pushHeaders
All requests require:
X-Secret-Key: Your organization secret keyContent-Type:application/json
Send notification
Send targeted push notifications to specific users or devices.
POST /v2/push/sendRequest 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:
| Option | Behavior |
|---|---|
target_all: true | Broadcast to all registered clients |
target_user_emails | Send to users by email address |
target_user_ids | Send to users by their user ID |
target_registration_ids | Send 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/broadcastSame 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/quotaResponse
{
"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/clientsQuery parameters
status- Filter by status:active,inactive,expired,unregistereduser_email- Filter by user emaillimit- 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_requestedQuery 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/serviceResponse
{
"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
| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED | 401 | Invalid or missing secret key |
FORBIDDEN | 403 | Secret key doesn't have permission |
INVALID_REQUEST | 400 | Malformed JSON or missing required fields |
NOT_FOUND | 404 | Client registration not found |
RATE_LIMITED | 429 | Too many requests |
QUOTA_EXCEEDED | 429 | Notification quota exceeded |
SERVICE_UNAVAILABLE | 503 | Push service temporarily unavailable |
Error response
{
"detail": "Notification quota exceeded for today"
}Rate limits
Rate limits depend on your plan:
| Plan | Hourly Limit | Daily Limit |
|---|---|---|
| Starter | 100 | 1,000 |
| Professional | 1,000 | 10,000 |
| Scale | 10,000 | 100,000 |
Async processing
For large notification batches (>100 recipients):
- Request returns immediately with
status: "queued" - Notifications are processed in the background
- Check delivery status via the clients endpoint
Force async mode for any request by setting async_mode: true in the request body.
Best practices
| Practice | Why |
|---|---|
| Use meaningful tags | Group related notifications to replace old ones |
| Set appropriate urgency | Use high only for critical alerts |
| Include action data | Pass URLs or IDs in the data field for client handling |
| Handle failures | Check failed_sends and invalid_registrations in responses |
| Monitor quota | Implement quota checks before large broadcasts |
| Clean up clients | Deregister clients that consistently fail |
Troubleshooting
Notifications not delivered
- Check client status is
activewithis_subscribed: true - Verify VAPID keys match between service and client
- Check notification quota hasn't been exceeded
- Verify allowed origins include client's origin
High failure rate
- Check for expired push subscriptions
- Verify payload size is within limits
- Review
invalid_registrationsin response - Client may have revoked notification permissions
Next steps
- Push notifications extension - Configure your PWA service
- API keys - Manage secret keys
- ACL rules - Control access patterns