API Reference
Complete reference for the HowlAlert Cloudflare Worker API endpoints.
Base URL
The API is served by a Cloudflare Worker. Your base URL will follow this pattern:
https://howlalert-api.<your-account>.workers.dev
Authentication
All protected endpoints require an Apple Identity Token passed as a Bearer token:
Authorization: Bearer <apple_identity_token>
In the development environment, the token is not cryptographically verified — any value is accepted and mapped to a synthetic user ID.
In production, the worker verifies the JWT against Apple's public keys (RSASSA-PKCS1-v1_5 / SHA-256), validates the issuer, audience (com.mrdemonwolf.howlalert), and expiration.
Requests to protected endpoints without a valid token receive a 401 Unauthorized response.
Endpoints Overview
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /status | No | Health check |
POST | /register | Yes | Register device for push notifications |
DELETE | /register | Yes | Deregister a device |
DELETE | /device/:token | Yes | Unregister device by token param |
POST | /event | Yes | Submit a usage event |
GET | /preferences | Yes | Fetch user thresholds |
POST | /preferences | Yes | Update user thresholds |
GET | /history | Yes | Event history (paginated) |
GET | /device | Yes | List registered devices |
DELETE | /account | Yes | Delete all user data |
GET /status
Health check endpoint. No authentication required.
Response
{
"status": "ok",
"version": "0.1.0",
"environment": "production"
}
POST /register
Register a device for push notifications.
Request Body
{
"device_token": "string",
"platform": "ios" | "watchos",
"sandbox": false
}
| Field | Type | Required | Description |
|---|---|---|---|
device_token | string | Yes | APNs device token |
platform | "ios" | "watchos" | Yes | Device platform |
sandbox | boolean | No | Use APNs sandbox environment |
Response
{
"success": true,
"message": "Device registered"
}
Example
curl -X POST https://howlalert-api.example.workers.dev/register \
-H "Authorization: Bearer $APPLE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device_token": "abc123...",
"platform": "ios",
"sandbox": false
}'
DELETE /register
Deregister a device by providing the device token in the request body.
Request Body
{
"deviceToken": "string"
}
Response
{
"message": "Device deregistered"
}
DELETE /device/:token
Unregister a device by passing the device token as a URL parameter.
Response
{
"success": true
}
POST /event
Submit a usage event. This is the primary data-ingestion endpoint.
Request Body (UsageEventPayload)
{
"sessionId": "string",
"timestamp": "string",
"model": "string",
"inputTokens": 0,
"outputTokens": 0,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"costUSD": 0.0
}
| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | Claude Code session identifier |
timestamp | string | Yes | ISO 8601 timestamp |
model | string | Yes | Model name (e.g., claude-sonnet-4-20250514) |
inputTokens | number | Yes | Input token count |
outputTokens | number | Yes | Output token count |
cacheReadTokens | number | Yes | Cache read token count |
cacheWriteTokens | number | Yes | Cache write token count |
costUSD | number | Yes | Cost in USD for this event |
Response
{
"success": true,
"summary": {
"totalCost": 4.32
}
}
Example
curl -X POST https://howlalert-api.example.workers.dev/event \
-H "Authorization: Bearer $APPLE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "sess_abc123",
"timestamp": "2026-03-17T12:00:00Z",
"model": "claude-sonnet-4-20250514",
"inputTokens": 1500,
"outputTokens": 800,
"cacheReadTokens": 200,
"cacheWriteTokens": 100,
"costUSD": 0.12
}'
GET /preferences
Fetch the current user's threshold preferences.
Response
{
"preferences": {
"userId": "string",
"thresholds": [
{
"id": "string",
"type": "daily_cost",
"value": 5.0,
"isEnabled": true
}
],
"updatedAt": "2026-03-17T12:00:00Z"
}
}
Returns { "preferences": null } if no preferences have been configured.
Types
UserPreferences
| Field | Type | Description |
|---|---|---|
userId | string | User identifier |
thresholds | ThresholdConfig[] | Array of threshold configurations |
updatedAt | string | ISO 8601 timestamp of last update |
ThresholdConfig
| Field | Type | Description |
|---|---|---|
id | string | Unique threshold identifier |
type | "daily_cost" | "token_count" | "session_count" | Threshold type |
value | number | Threshold value |
isEnabled | boolean | Whether this threshold is active |
POST /preferences
Update the current user's threshold preferences.
Request Body
{
"thresholds": [
{
"id": "string",
"type": "daily_cost",
"value": 10.0,
"isEnabled": true
}
]
}
Response
{
"success": true,
"preferences": {
"userId": "string",
"thresholds": [
{
"id": "string",
"type": "daily_cost",
"value": 10.0,
"isEnabled": true
}
],
"updatedAt": "2026-03-17T12:00:00Z"
}
}
Example
curl -X POST https://howlalert-api.example.workers.dev/preferences \
-H "Authorization: Bearer $APPLE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"thresholds": [
{
"id": "thresh_1",
"type": "daily_cost",
"value": 10.0,
"isEnabled": true
},
{
"id": "thresh_2",
"type": "token_count",
"value": 500000,
"isEnabled": false
}
]
}'
GET /history
Retrieve paginated event history for the authenticated user.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Maximum number of events to return |
offset | number | 0 | Number of events to skip |
Response
{
"events": [
{
"id": "string",
"userId": "string",
"sessionId": "string",
"timestamp": "string",
"model": "string",
"inputTokens": 1500,
"outputTokens": 800,
"cacheReadTokens": 200,
"cacheWriteTokens": 100,
"costUSD": 0.12,
"createdAt": "string"
}
],
"limit": 50,
"offset": 0
}
GET /device
List all registered devices for the authenticated user.
Response
{
"devices": [
{
"deviceToken": "string",
"platform": "ios",
"userId": "string",
"registeredAt": "string",
"sandbox": false
}
]
}
DELETE /account
Delete all data associated with the authenticated user, including devices and event history.
Response
{
"success": true,
"devicesRemoved": 2,
"eventsRemoved": 143
}
Threshold Alerting
When a usage event is submitted via POST /event, the worker performs the following steps:
- Inserts the event into the D1 database.
- Fetches the daily cost summary for the current day.
- Loads user preferences from KV (
prefs:{userId}). - Compares the daily cost against the configured threshold (defaults to $5.00 if no preferences are set).
- If the threshold is exceeded, sends an APNs push notification to every registered device for that user.
This check runs on every event submission, so users are alerted as soon as their spending crosses the configured limit.
Error Responses
All endpoints return standard JSON error responses.
401 Unauthorized — Missing or invalid authentication token.
{
"error": "Unauthorized"
}
400 Bad Request — Missing required fields or invalid request body.
{
"error": "Missing required field: device_token"
}