Learn how to send push notifications programmatically using the Chirpme API.
The Chirpme API allows you to send push notifications to your channel subscribers programmatically. All API requests require authentication using an API key.
Base URL
https://chirpme.app/apiAll API requests must include your API key in the Authorization header using the Bearer token format.
Authorization: Bearer YOUR_API_KEYKeep your API key secure
Never expose your API key in client-side code or public repositories. Use environment variables or secure key management systems.
/api/sendSend a push notification to channel subscribers
| Parameter | Type | Description |
|---|---|---|
channelId | string | The unique identifier of the channel to send the notification to. |
title | string | The notification title. Keep it short and attention-grabbing (max 65 characters recommended). |
body | string | The notification body text. This is the main message content (max 240 characters recommended). |
| Parameter | Type | Description |
|---|---|---|
url | string | A URL to open when the user taps the notification. Can be a deep link or web URL. |
detail | string | Rich HTML content for the in-app detail view. Supports basic HTML tags for formatting. |
imageUrl | string | URL of an image to display with the notification. Should be HTTPS and publicly accessible. |
scheduledAt | string (ISO 8601) | Schedule the notification for future delivery. Use ISO 8601 format (e.g., '2025-01-15T10:00:00Z'). |
to | string[] | Array of subscriber email addresses to send to. Only these subscribers will receive the notification. Requires Growth plan. |
groups | string[] | Array of subscriber group IDs to send to. All members of the specified groups will receive the notification. Requires Growth plan. |
| Parameter | Type | Description |
|---|---|---|
badge | number | The badge number to display on the app icon. Set to 0 to clear the badge. |
sound | string | The sound to play. Use 'default' for the default notification sound, or a custom sound file name. |
category | string | iOS notification category identifier for custom actions. |
threadId | string | Thread identifier for grouping related notifications together. |
| Parameter | Type | Description |
|---|---|---|
channelName | string | Android notification channel name. Creates a new channel if it doesn't exist. |
priority | string | Notification priority. Options: 'default', 'low', 'high', 'max'. |
icon | string | Custom notification icon identifier (Android legacy). |
color | string | Notification accent color as hex (e.g., '#2dd4bf'). |
tag | string | Tag for replacing/updating existing notifications with the same tag. |
| Parameter | Type | Description |
|---|---|---|
notificationIcon | string | Override the channel icon. Can be a Material Symbol name or an image URL. |
notificationIconType | string | Type of notification icon. Options: 'material' (Material Symbol name) or 'url' (image URL). |
suggestedSubTab | string | Suggest a sub-tab name for organizing this notification in the mobile app. |
suggestedSubTabColor | string | Color for the suggested sub-tab as hex (e.g., '#3498db'). |
Send to specific subscribers or groups instead of all channel subscribers. Omit both parameters to send to everyone.
| Parameter | Type | Description |
|---|---|---|
to | string[] | Array of subscriber email addresses to send to. Only these subscribers will receive the notification. |
groups | string[] | Array of subscriber group IDs to send to. All members of the specified groups will receive the notification. |
/api/channelsList all channels in your account
Returns a list of all channels owned by the authenticated user. Requires an account-scoped API key.
{
"success": true,
"channels": [
{
"id": "abc123xyz",
"name": "Product Updates",
"description": "Get notified about new features",
"code": "PROD-2024",
"subscriberCount": 150,
"notificationCount": 42,
"isPasswordProtected": false,
"isPublic": false,
"createdAt": "2025-01-01T00:00:00.000Z"
}
]
}Note: Channel-scoped API keys cannot list channels. Use an account-scoped key.
/api/channelsCreate a new notification channel
| Parameter | Type | Description |
|---|---|---|
name | string | The channel name. Must be between 2 and 100 characters. |
description | string | Channel description. Must be between 10 and 500 characters. |
| Parameter | Type | Description |
|---|---|---|
code | string | Custom channel code (3-20 characters, uppercase letters, numbers, and hyphens). Auto-generated if not provided. |
password | string | Password to protect the channel. Subscribers will need this to join. |
icon | string | Channel icon. Can be a Material Symbol name or an image URL. |
iconType | string | Type of icon. Options: 'material' (default) or 'url'. |
isPublic | boolean | Whether the channel is discoverable in the mobile app. Default: false. |
suggestedTab | string | Suggested tab name for organizing this channel in mobile apps. |
suggestedTabColor | string | Color for the suggested tab as hex (e.g., '#2dd4bf'). |
{
"success": true,
"channel": {
"id": "abc123xyz",
"name": "Product Updates",
"description": "Get notified about new features",
"code": "PROD-2024",
"subscriberCount": 0,
"notificationCount": 0,
"isPasswordProtected": false,
"isPublic": false,
"createdAt": "2025-01-08T10:30:00.000Z"
}
}Note: Channel-scoped API keys cannot create channels. Use an account-scoped key.
/api/groups?channelId={channelId}Growth planList all subscriber groups for a channel
Returns all subscriber groups for the specified channel. Use group IDs with the to or groups parameter in /api/send for targeted notifications.
{
"success": true,
"groups": [
{
"id": "grp_abc123",
"name": "VIP Subscribers",
"memberEmails": ["user1@example.com", "user2@example.com"],
"createdAt": "2025-01-10T10:00:00.000Z",
"updatedAt": "2025-01-10T10:00:00.000Z"
}
]
}/api/groupsGrowth planCreate a new subscriber group
| Parameter | Type | Required | Description |
|---|---|---|---|
channelId | string | Yes | The ID of the channel to create the group in. |
name | string | Yes | The group name. Must be 100 characters or less. |
memberEmails | string[] | Yes | Array of subscriber email addresses to add to the group. |
{
"success": true,
"group": {
"id": "grp_abc123",
"name": "VIP Subscribers",
"memberEmails": ["user1@example.com", "user2@example.com"],
"createdAt": "2025-01-10T10:00:00.000Z",
"updatedAt": "2025-01-10T10:00:00.000Z"
}
}/api/groupsGrowth planUpdate a subscriber group
Update the name and/or members of an existing group. At least one of name or memberEmails must be provided.
| Parameter | Type | Required | Description |
|---|---|---|---|
channelId | string | Yes | The ID of the channel the group belongs to. |
groupId | string | Yes | The ID of the group to update. |
name | string | No | New name for the group. |
memberEmails | string[] | No | Updated array of subscriber email addresses. Replaces existing members. |
/api/groups?channelId={channelId}&groupId={groupId}Growth planDelete a subscriber group
Permanently deletes a subscriber group. This does not unsubscribe the members from the channel.
{
"success": true
}{
"success": true,
"notification": {
"id": "abc123xyz",
"channelId": "your-channel-id",
"status": "sent",
"scheduledAt": null,
"sentAt": "2025-01-07T10:30:00.000Z"
}
}{
"error": "Error message describing what went wrong"
}| Code | Name | Description |
|---|---|---|
| 400 | Bad Request | Missing required fields (channelId, title, body). |
| 401 | Unauthorized | Missing, invalid, or expired API key. |
| 403 | Forbidden | API key doesn't have permission for the specified channel. |
| 404 | Not Found | The specified channel does not exist. |
| 500 | Internal Error | Server error. Please try again or contact support. |
curl -X POST https://chirpme.app/api/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelId": "your-channel-id",
"title": "Hello World",
"body": "This is a test notification",
"url": "https://example.com",
"detail": "<p>Rich HTML content for detail view</p>",
"imageUrl": "https://example.com/image.png",
"scheduledAt": "2025-01-15T10:00:00Z",
"badge": 1,
"sound": "default",
"priority": "high",
"notificationIcon": "notifications",
"notificationIconType": "material",
"suggestedSubTab": "Updates",
"suggestedSubTabColor": "#2dd4bf",
"to": ["user1@example.com", "user2@example.com"],
"groups": ["group-id-1"]
}'const response = await fetch('https://chirpme.app/api/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
channelId: 'your-channel-id',
title: 'Hello World',
body: 'This is a test notification',
url: 'https://example.com',
detail: '<p>Rich HTML content for detail view</p>',
imageUrl: 'https://example.com/image.png',
scheduledAt: '2025-01-15T10:00:00Z',
// iOS options
badge: 1,
sound: 'default',
category: 'general',
threadId: 'thread-123',
// Android options
priority: 'high',
color: '#2dd4bf',
tag: 'notification-tag',
// Icon override
notificationIcon: 'notifications',
notificationIconType: 'material', // or 'url'
// Sub-tab suggestion
suggestedSubTab: 'Updates',
suggestedSubTabColor: '#2dd4bf',
// Targeting (Growth plan)
to: ['user1@example.com', 'user2@example.com'],
groups: ['group-id-1'],
}),
});
const data = await response.json();
console.log(data);import requests
response = requests.post(
'https://chirpme.app/api/send',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
json={
'channelId': 'your-channel-id',
'title': 'Hello World',
'body': 'This is a test notification',
'url': 'https://example.com',
'detail': '<p>Rich HTML content for detail view</p>',
'imageUrl': 'https://example.com/image.png',
'scheduledAt': '2025-01-15T10:00:00Z',
# iOS options
'badge': 1,
'sound': 'default',
'category': 'general',
'threadId': 'thread-123',
# Android options
'priority': 'high',
'color': '#2dd4bf',
'tag': 'notification-tag',
# Icon override
'notificationIcon': 'notifications',
'notificationIconType': 'material', # or 'url'
# Sub-tab suggestion
'suggestedSubTab': 'Updates',
'suggestedSubTabColor': '#2dd4bf',
# Targeting (Growth plan)
'to': ['user1@example.com', 'user2@example.com'],
'groups': ['group-id-1'],
}
)
data = response.json()
print(data)using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_KEY");
var payload = new {
channelId = "your-channel-id",
title = "Hello World",
body = "This is a test notification",
url = "https://example.com",
detail = "<p>Rich HTML content for detail view</p>",
imageUrl = "https://example.com/image.png",
scheduledAt = "2025-01-15T10:00:00Z",
// iOS options
badge = 1,
sound = "default",
category = "general",
threadId = "thread-123",
// Android options
priority = "high",
color = "#2dd4bf",
tag = "notification-tag",
// Icon override
notificationIcon = "notifications",
notificationIconType = "material", // or "url"
// Sub-tab suggestion
suggestedSubTab = "Updates",
suggestedSubTabColor = "#2dd4bf",
// Targeting (Growth plan)
to = new[] { "user1@example.com", "user2@example.com" },
groups = new[] { "group-id-1" }
};
var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://chirpme.app/api/send",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);curl -X POST https://chirpme.app/api/channels \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Product Updates",
"description": "Get notified about new features and product updates",
"code": "PROD-2024",
"icon": "notifications",
"iconType": "material",
"isPublic": false
}'const response = await fetch('https://chirpme.app/api/channels', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Product Updates',
description: 'Get notified about new features and product updates',
code: 'PROD-2024',
icon: 'notifications',
iconType: 'material',
isPublic: false,
}),
});
const data = await response.json();
console.log(data);import requests
response = requests.post(
'https://chirpme.app/api/channels',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
json={
'name': 'Product Updates',
'description': 'Get notified about new features and product updates',
'code': 'PROD-2024',
'icon': 'notifications',
'iconType': 'material',
'isPublic': False,
}
)
data = response.json()
print(data)using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_KEY");
var payload = new {
name = "Product Updates",
description = "Get notified about new features and product updates",
code = "PROD-2024",
icon = "notifications",
iconType = "material",
isPublic = false
};
var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://chirpme.app/api/channels",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);# List groups
curl -X GET "https://chirpme.app/api/groups?channelId=your-channel-id" \
-H "Authorization: Bearer YOUR_API_KEY"
# Create a group
curl -X POST https://chirpme.app/api/groups \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelId": "your-channel-id",
"name": "VIP Subscribers",
"memberEmails": ["user1@example.com", "user2@example.com"]
}'
# Update a group
curl -X PUT https://chirpme.app/api/groups \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelId": "your-channel-id",
"groupId": "group-id",
"name": "Premium Subscribers",
"memberEmails": ["user1@example.com", "user2@example.com", "user3@example.com"]
}'
# Delete a group
curl -X DELETE "https://chirpme.app/api/groups?channelId=your-channel-id&groupId=group-id" \
-H "Authorization: Bearer YOUR_API_KEY"// List groups
const groups = await fetch(
'https://chirpme.app/api/groups?channelId=your-channel-id',
{
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
}
);
console.log(await groups.json());
// Create a group
const newGroup = await fetch('https://chirpme.app/api/groups', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
channelId: 'your-channel-id',
name: 'VIP Subscribers',
memberEmails: ['user1@example.com', 'user2@example.com'],
}),
});
console.log(await newGroup.json());import requests
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
}
# List groups
groups = requests.get(
'https://chirpme.app/api/groups',
headers=headers,
params={'channelId': 'your-channel-id'}
)
print(groups.json())
# Create a group
new_group = requests.post(
'https://chirpme.app/api/groups',
headers=headers,
json={
'channelId': 'your-channel-id',
'name': 'VIP Subscribers',
'memberEmails': ['user1@example.com', 'user2@example.com'],
}
)
print(new_group.json())using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_KEY");
// List groups
var listResponse = await client.GetAsync(
"https://chirpme.app/api/groups?channelId=your-channel-id"
);
Console.WriteLine(await listResponse.Content.ReadAsStringAsync());
// Create a group
var payload = new {
channelId = "your-channel-id",
name = "VIP Subscribers",
memberEmails = new[] { "user1@example.com", "user2@example.com" }
};
var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json"
);
var createResponse = await client.PostAsync(
"https://chirpme.app/api/groups",
content
);
Console.WriteLine(await createResponse.Content.ReadAsStringAsync());Create real-time widgets on iOS Dynamic Island and Android devices. The lifecycle is: start an activity, update its fields over time, then end it when done. This feature is currently in beta.
percentage_barProgress bar
linear_stagesStep-by-step
deliveryDelivery tracking
countdownTimer
scoreboardLive scores
Each start and update consumes 1 notification credit. You can start from scratch by providing templateType and fields, or use a saved template by passing templateId.
/api/live-activitiesGrowth planStart a new live activity
| Parameter | Type | Required | Description |
|---|---|---|---|
channelId | string | Yes | The ID of the channel to start the live activity on. |
templateType | string | No | The widget layout type. One of: percentage_bar, linear_stages, delivery, countdown, scoreboard. Required unless templateId is provided. |
templateId | string | No | ID of a saved template. Template defaults are used for any fields not specified in the request. |
title | string | No | The live activity title displayed on the widget. Required unless templateId is provided. |
subtitle | string | No | Optional subtitle displayed below the title. |
accentColor | string | No | Accent color as hex string (e.g., '#2dd4bf'). |
channelIcon | string | No | Channel icon URL for this activity. |
tapUrl | string | No | URL to open when the user taps the live activity. |
fields | object | Yes | Key-value pairs of data fields for the widget. Keys depend on the templateType (all values must be strings). |
targetType | string | No | Targeting mode: 'all' (default), 'subscribers', or 'groups'. |
targetSubscribers | string[] | No | Array of subscriber email addresses when targetType is 'subscribers'. Requires Growth plan. |
targetGroups | string[] | No | Array of group IDs when targetType is 'groups'. Requires Growth plan. |
{
"success": true,
"liveActivity": {
"id": "abc123def456",
"deviceCount": 42,
"status": "active"
}
}/api/live-activitiesGrowth planUpdate a live activity
| Parameter | Type | Required | Description |
|---|---|---|---|
activityId | string | Yes | The ID of the live activity to update (returned from the start endpoint). |
channelId | string | Yes | The ID of the channel the live activity belongs to. |
fields | object | Yes | Key-value pairs to update. Merged with existing fields — only specified keys are overwritten. |
{
"success": true,
"deviceCount": 42
}/api/live-activities/:activityIdGrowth planEnd an active live activity
End an active live activity and dismiss widgets from all devices. Idempotent — returns success even if the activity is already ended or not found.
{
"success": true
}/api/live-activities?channelId={channelId}Growth planList active live activities for a channel
Returns all active live activities for the specified channel.
{
"success": true,
"liveActivities": [
{
"id": "abc123def456",
"templateType": "percentage_bar",
"status": "active",
"title": "Order Processing",
"deviceCount": 42,
"startedAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:05:00.000Z"
}
]
}# Start a live activity (all subscribers)
curl -X POST https://chirpme.app/api/live-activities \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelId": "your-channel-id",
"templateType": "percentage_bar",
"title": "Order Processing",
"fields": {
"percentage": "0",
"label": "Preparing your order..."
}
}'
# Start targeting specific subscribers (Growth plan)
curl -X POST https://chirpme.app/api/live-activities \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelId": "your-channel-id",
"templateType": "delivery",
"title": "Your Order",
"fields": { "status": "Picked up", "eta": "15 min" },
"targetType": "subscribers",
"targetSubscribers": ["user@example.com"]
}'
# Start targeting groups (Growth plan)
curl -X POST https://chirpme.app/api/live-activities \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelId": "your-channel-id",
"templateType": "scoreboard",
"title": "Live Match",
"fields": { "homeTeam": "Team A", "awayTeam": "Team B", "homeScore": "0", "awayScore": "0" },
"targetType": "groups",
"targetGroups": ["group-id-1"]
}'
# Update the live activity
curl -X PUT https://chirpme.app/api/live-activities \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"activityId": "ACTIVITY_ID",
"channelId": "your-channel-id",
"fields": {
"percentage": "75",
"label": "Almost ready!"
}
}'
# End the live activity
curl -X DELETE "https://chirpme.app/api/live-activities/ACTIVITY_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
# List active live activities
curl -X GET "https://chirpme.app/api/live-activities?channelId=your-channel-id" \
-H "Authorization: Bearer YOUR_API_KEY"// Start a live activity (all subscribers)
const start = await fetch('https://chirpme.app/api/live-activities', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
channelId: 'your-channel-id',
templateType: 'percentage_bar',
title: 'Order Processing',
fields: { percentage: '0', label: 'Preparing your order...' },
// Targeting (Growth plan) — omit for all subscribers
// targetType: 'subscribers',
// targetSubscribers: ['user@example.com'],
// targetType: 'groups',
// targetGroups: ['group-id-1'],
}),
});
const { liveActivity } = await start.json();
console.log('Activity ID:', liveActivity.id);
// Update the live activity
await fetch('https://chirpme.app/api/live-activities', {
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
activityId: liveActivity.id,
channelId: 'your-channel-id',
fields: { percentage: '75', label: 'Almost ready!' },
}),
});
// End the live activity
await fetch(`https://chirpme.app/api/live-activities/${liveActivity.id}`, {
method: 'DELETE',
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
});import requests
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
}
# Start a live activity (all subscribers)
start = requests.post(
'https://chirpme.app/api/live-activities',
headers=headers,
json={
'channelId': 'your-channel-id',
'templateType': 'percentage_bar',
'title': 'Order Processing',
'fields': {'percentage': '0', 'label': 'Preparing your order...'},
# Targeting (Growth plan) — omit for all subscribers
# 'targetType': 'subscribers',
# 'targetSubscribers': ['user@example.com'],
# 'targetType': 'groups',
# 'targetGroups': ['group-id-1'],
}
)
activity_id = start.json()['liveActivity']['id']
print('Activity ID:', activity_id)
# Update the live activity
requests.put(
'https://chirpme.app/api/live-activities',
headers=headers,
json={
'activityId': activity_id,
'channelId': 'your-channel-id',
'fields': {'percentage': '75', 'label': 'Almost ready!'},
}
)
# End the live activity
requests.delete(
f'https://chirpme.app/api/live-activities/{activity_id}',
headers=headers
)using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_KEY");
// Start a live activity (all subscribers)
var startPayload = new {
channelId = "your-channel-id",
templateType = "percentage_bar",
title = "Order Processing",
fields = new { percentage = "0", label = "Preparing your order..." },
// Targeting (Growth plan) — omit for all subscribers
// targetType = "subscribers",
// targetSubscribers = new[] { "user@example.com" },
// targetType = "groups",
// targetGroups = new[] { "group-id-1" }
};
var startContent = new StringContent(
JsonSerializer.Serialize(startPayload),
Encoding.UTF8,
"application/json"
);
var startResponse = await client.PostAsync(
"https://chirpme.app/api/live-activities",
startContent
);
var startResult = JsonSerializer.Deserialize<JsonElement>(
await startResponse.Content.ReadAsStringAsync()
);
var activityId = startResult.GetProperty("liveActivity").GetProperty("id").GetString();
// Update the live activity
var updatePayload = new {
activityId,
channelId = "your-channel-id",
fields = new { percentage = "75", label = "Almost ready!" }
};
var updateContent = new StringContent(
JsonSerializer.Serialize(updatePayload),
Encoding.UTF8,
"application/json"
);
await client.PutAsync("https://chirpme.app/api/live-activities", updateContent);
// End the live activity
await client.DeleteAsync($"https://chirpme.app/api/live-activities/{activityId}");Each template type accepts specific fields in the fields object. Pass these when starting or updating a live activity.
percentage_barProgress bar with percentage| Field | Type | Description |
|---|---|---|
percentage | string | Progress value 0–100 |
itemsComplete | string | Completed item count (e.g. "7") |
totalItems | string | Total item count (e.g. "100") |
status | string | Optional status label |
linear_stagesStep-by-step workflow| Field | Type | Description |
|---|---|---|
stages | string | JSON array of stage objects: [{"name":"Step 1"},{"name":"Step 2"}] |
currentStage | string | Zero-based index of the active stage (e.g. "0", "1") |
deliveryDelivery tracking with ETA| Field | Type | Description |
|---|---|---|
eta | string | Estimated arrival time (e.g. "3:45 PM") |
driverName | string | Driver or courier name |
distance | string | Distance remaining (e.g. "1.2 mi away") |
status | string | Current delivery status (e.g. "In Transit") |
stops | string | JSON array of stop objects: [{"name":"Picked Up"},{"name":"Delivered"}] |
currentStop | string | Zero-based index of the current stop |
countdownCountdown timer| Field | Type | Description |
|---|---|---|
endTimestamp | string | Unix epoch seconds for the target end time — enables a live countdown on device |
timeRemaining | string | Fallback display text (e.g. "2h 15m") when no endTimestamp |
percentage | string | Progress bar value 0–100 |
status | string | Optional status pill text (e.g. "Active") |
scoreboardLive sports scores| Field | Type | Description |
|---|---|---|
homeTeam | string | Home team name |
awayTeam | string | Away team name |
homeScore | string | Home team score |
awayScore | string | Away team score |
period | string | Current period (e.g. "Q1", "Half", "OT") |
All field values must be strings. The iOS widget decodes them as [String: String] — non-string values will cause silent decode failures.
The channelIcon parameter accepts an SF Symbol name or emoji. On iOS, the symbol renders natively; on Android, the emoji fallback is used. Below are commonly-used symbols organized by category.
truck.box.fillshippingbox.fillcar.fillbicycleairplanelocation.fillmappin.circle.fillfigure.walkfork.knifecup.and.saucer.filltakeoutbag.and.cup.and.straw.fillcart.fillbag.filltrophy.fillsoccerballbasketball.fillfootball.fillfigure.runflag.checkeredtimerclock.fillhourglassstopwatch.fillcheckmark.circle.fillbell.fillexclamationmark.triangle.fillmegaphone.fillflame.fillbolt.fillstar.fillheart.fillmusic.noteplay.fillticket.fillgamecontroller.filldollarsign.circle.fillcreditcard.fillchart.line.uptrend.xyaxisperson.fillbriefcase.fillYou can use any valid SF Symbol name — the list above shows common choices. You can also pass an emoji directly (e.g. 🚚).
Sign up to create your first channel and get an API key. Use our interactive API Explorer to test requests.