API Documentation

Learn how to send push notifications programmatically using the Chirpme API.

Overview

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/api

Authentication

All API requests must include your API key in the Authorization header using the Bearer token format.

Authorization: Bearer YOUR_API_KEY

Keep 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 Key Types

  • Account Keys - Can send to any channel in your account
  • Channel Keys - Restricted to a specific channel only
POST/api/send

Send a push notification to channel subscribers

Required Parameters

ParameterTypeDescription
channelIdstringThe unique identifier of the channel to send the notification to.
titlestringThe notification title. Keep it short and attention-grabbing (max 65 characters recommended).
bodystringThe notification body text. This is the main message content (max 240 characters recommended).

Optional Parameters

ParameterTypeDescription
urlstringA URL to open when the user taps the notification. Can be a deep link or web URL.
detailstringRich HTML content for the in-app detail view. Supports basic HTML tags for formatting.
imageUrlstringURL of an image to display with the notification. Should be HTTPS and publicly accessible.
scheduledAtstring (ISO 8601)Schedule the notification for future delivery. Use ISO 8601 format (e.g., '2025-01-15T10:00:00Z').
tostring[]Array of subscriber email addresses to send to. Only these subscribers will receive the notification. Requires Growth plan.
groupsstring[]Array of subscriber group IDs to send to. All members of the specified groups will receive the notification. Requires Growth plan.

iOS-Specific Parameters

ParameterTypeDescription
badgenumberThe badge number to display on the app icon. Set to 0 to clear the badge.
soundstringThe sound to play. Use 'default' for the default notification sound, or a custom sound file name.
categorystringiOS notification category identifier for custom actions.
threadIdstringThread identifier for grouping related notifications together.

Android-Specific Parameters

ParameterTypeDescription
channelNamestringAndroid notification channel name. Creates a new channel if it doesn't exist.
prioritystringNotification priority. Options: 'default', 'low', 'high', 'max'.
iconstringCustom notification icon identifier (Android legacy).
colorstringNotification accent color as hex (e.g., '#2dd4bf').
tagstringTag for replacing/updating existing notifications with the same tag.

Customization Parameters

ParameterTypeDescription
notificationIconstringOverride the channel icon. Can be a Material Symbol name or an image URL.
notificationIconTypestringType of notification icon. Options: 'material' (Material Symbol name) or 'url' (image URL).
suggestedSubTabstringSuggest a sub-tab name for organizing this notification in the mobile app.
suggestedSubTabColorstringColor for the suggested sub-tab as hex (e.g., '#3498db').

Targeting ParametersGrowth plan

Send to specific subscribers or groups instead of all channel subscribers. Omit both parameters to send to everyone.

ParameterTypeDescription
tostring[]Array of subscriber email addresses to send to. Only these subscribers will receive the notification.
groupsstring[]Array of subscriber group IDs to send to. All members of the specified groups will receive the notification.
GET/api/channels

List all channels in your account

Returns a list of all channels owned by the authenticated user. Requires an account-scoped API key.

Example Response

{
  "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.

POST/api/channels

Create a new notification channel

Required Parameters

ParameterTypeDescription
namestringThe channel name. Must be between 2 and 100 characters.
descriptionstringChannel description. Must be between 10 and 500 characters.

Optional Parameters

ParameterTypeDescription
codestringCustom channel code (3-20 characters, uppercase letters, numbers, and hyphens). Auto-generated if not provided.
passwordstringPassword to protect the channel. Subscribers will need this to join.
iconstringChannel icon. Can be a Material Symbol name or an image URL.
iconTypestringType of icon. Options: 'material' (default) or 'url'.
isPublicbooleanWhether the channel is discoverable in the mobile app. Default: false.
suggestedTabstringSuggested tab name for organizing this channel in mobile apps.
suggestedTabColorstringColor for the suggested tab as hex (e.g., '#2dd4bf').

Example Response

{
  "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.

GET/api/groups?channelId={channelId}Growth plan

List 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.

Example Response

{
  "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"
    }
  ]
}
POST/api/groupsGrowth plan

Create a new subscriber group

Parameters

ParameterTypeRequiredDescription
channelIdstringYesThe ID of the channel to create the group in.
namestringYesThe group name. Must be 100 characters or less.
memberEmailsstring[]YesArray of subscriber email addresses to add to the group.

Example Response (201)

{
  "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"
  }
}
PUT/api/groupsGrowth plan

Update a subscriber group

Update the name and/or members of an existing group. At least one of name or memberEmails must be provided.

Parameters

ParameterTypeRequiredDescription
channelIdstringYesThe ID of the channel the group belongs to.
groupIdstringYesThe ID of the group to update.
namestringNoNew name for the group.
memberEmailsstring[]NoUpdated array of subscriber email addresses. Replaces existing members.
DELETE/api/groups?channelId={channelId}&groupId={groupId}Growth plan

Delete a subscriber group

Permanently deletes a subscriber group. This does not unsubscribe the members from the channel.

Example Response

{
  "success": true
}

Response Format

Success Response (200)

{
  "success": true,
  "notification": {
    "id": "abc123xyz",
    "channelId": "your-channel-id",
    "status": "sent",
    "scheduledAt": null,
    "sentAt": "2025-01-07T10:30:00.000Z"
  }
}

Error Response

{
  "error": "Error message describing what went wrong"
}

Error Codes

CodeNameDescription
400Bad RequestMissing required fields (channelId, title, body).
401UnauthorizedMissing, invalid, or expired API key.
403ForbiddenAPI key doesn't have permission for the specified channel.
404Not FoundThe specified channel does not exist.
500Internal ErrorServer error. Please try again or contact support.

Code Examples

cURL

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"]
  }'

Node.js

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);

Python

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)

C#

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);

Channel API Examples

cURL

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
  }'

Node.js

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);

Python

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)

C#

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);

Groups API Examples

cURL

# 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"

Node.js

// 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());

Python

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())

C#

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());

Live Activities API

Growth planBeta

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.

Template Types

percentage_bar

Progress bar

linear_stages

Step-by-step

delivery

Delivery tracking

countdown

Timer

scoreboard

Live 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.

POST/api/live-activitiesGrowth plan

Start a new live activity

Parameters

ParameterTypeRequiredDescription
channelIdstringYesThe ID of the channel to start the live activity on.
templateTypestringNoThe widget layout type. One of: percentage_bar, linear_stages, delivery, countdown, scoreboard. Required unless templateId is provided.
templateIdstringNoID of a saved template. Template defaults are used for any fields not specified in the request.
titlestringNoThe live activity title displayed on the widget. Required unless templateId is provided.
subtitlestringNoOptional subtitle displayed below the title.
accentColorstringNoAccent color as hex string (e.g., '#2dd4bf').
channelIconstringNoChannel icon URL for this activity.
tapUrlstringNoURL to open when the user taps the live activity.
fieldsobjectYesKey-value pairs of data fields for the widget. Keys depend on the templateType (all values must be strings).
targetTypestringNoTargeting mode: 'all' (default), 'subscribers', or 'groups'.
targetSubscribersstring[]NoArray of subscriber email addresses when targetType is 'subscribers'. Requires Growth plan.
targetGroupsstring[]NoArray of group IDs when targetType is 'groups'. Requires Growth plan.

Example Response

{
  "success": true,
  "liveActivity": {
    "id": "abc123def456",
    "deviceCount": 42,
    "status": "active"
  }
}
PUT/api/live-activitiesGrowth plan

Update a live activity

Parameters

ParameterTypeRequiredDescription
activityIdstringYesThe ID of the live activity to update (returned from the start endpoint).
channelIdstringYesThe ID of the channel the live activity belongs to.
fieldsobjectYesKey-value pairs to update. Merged with existing fields — only specified keys are overwritten.

Example Response

{
  "success": true,
  "deviceCount": 42
}
DELETE/api/live-activities/:activityIdGrowth plan

End 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.

Example Response

{
  "success": true
}
GET/api/live-activities?channelId={channelId}Growth plan

List active live activities for a channel

Returns all active live activities for the specified channel.

Example Response

{
  "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"
    }
  ]
}

Live Activities API Examples

cURL

# 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"

Node.js

// 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' },
});

Python

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
)

C#

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}");

Template Fields Reference

Each template type accepts specific fields in the fields object. Pass these when starting or updating a live activity.

percentage_barProgress bar with percentage
FieldTypeDescription
percentagestringProgress value 0–100
itemsCompletestringCompleted item count (e.g. "7")
totalItemsstringTotal item count (e.g. "100")
statusstringOptional status label
linear_stagesStep-by-step workflow
FieldTypeDescription
stagesstringJSON array of stage objects: [{"name":"Step 1"},{"name":"Step 2"}]
currentStagestringZero-based index of the active stage (e.g. "0", "1")
deliveryDelivery tracking with ETA
FieldTypeDescription
etastringEstimated arrival time (e.g. "3:45 PM")
driverNamestringDriver or courier name
distancestringDistance remaining (e.g. "1.2 mi away")
statusstringCurrent delivery status (e.g. "In Transit")
stopsstringJSON array of stop objects: [{"name":"Picked Up"},{"name":"Delivered"}]
currentStopstringZero-based index of the current stop
countdownCountdown timer
FieldTypeDescription
endTimestampstringUnix epoch seconds for the target end time — enables a live countdown on device
timeRemainingstringFallback display text (e.g. "2h 15m") when no endTimestamp
percentagestringProgress bar value 0–100
statusstringOptional status pill text (e.g. "Active")
scoreboardLive sports scores
FieldTypeDescription
homeTeamstringHome team name
awayTeamstringAway team name
homeScorestringHome team score
awayScorestringAway team score
periodstringCurrent 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.

Channel Icon Reference (SF Symbols)

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.

Delivery & Transport

🚚truck.box.fill
📦shippingbox.fill
🚗car.fill
🚲bicycle
✈️airplane
📍location.fill
📍mappin.circle.fill
🚶figure.walk

Food & Drink

🍽️fork.knife
cup.and.saucer.fill
🥤takeoutbag.and.cup.and.straw.fill
🛒cart.fill
🛍️bag.fill

Sports & Fitness

🏆trophy.fill
soccerball
🏀basketball.fill
🏈football.fill
🏃figure.run
🏁flag.checkered

Time & Progress

⏱️timer
🕐clock.fill
hourglass
⏱️stopwatch.fill
checkmark.circle.fill

Alerts & Status

🔔bell.fill
⚠️exclamationmark.triangle.fill
📢megaphone.fill
🔥flame.fill
bolt.fill
star.fill
❤️heart.fill

Media & Entertainment

🎵music.note
▶️play.fill
🎫ticket.fill
🎮gamecontroller.fill

Business & Finance

💲dollarsign.circle.fill
💳creditcard.fill
📈chart.line.uptrend.xyaxis
👤person.fill
💼briefcase.fill

You can use any valid SF Symbol name — the list above shows common choices. You can also pass an emoji directly (e.g. 🚚).

Ready to get started?

Sign up to create your first channel and get an API key. Use our interactive API Explorer to test requests.