Docs

API and webhook

You pull watches and events with an API key. We push a signed POST when a threshold fires. Two separate surfaces — same account.

API

Public REST under /api/v1. You call us. Create a key in Integrations → API keys. Keys start with spk_.

Auth

The key sees every watch and event on the account. Watches belong to a project; the key does not.

Authorization: Bearer spk_live_...

Create a watch

POST /api/v1/watches

channel accepts a UC id, @handle, or YouTube URL. thresholdViews is 1–999,999,999. windowHours is 1–720 (30 days). projectId is optional — otherwise we use the current dashboard project.

POST /api/v1/watches
Authorization: Bearer spk_live_...
Content-Type: application/json

{
  "channel": "https://www.youtube.com/@handle",
  "thresholdViews": 3000,
  "windowHours": 1,
  "projectId": 1
}

Response 201:

{
  "watch": {
    "id": 12,
    "userId": 1,
    "projectId": 1,
    "channelId": 44,
    "youtubeChannelId": "UCxxxxxxxxxxxxxxxxxxxxxx",
    "channelTitle": "MrBeast",
    "channelThumbnailUrl": "https://yt3.googleusercontent.com/…",
    "triggerDefinitionId": 3,
    "thresholdViews": 3000,
    "windowHours": 1,
    "status": "active",
    "createdAt": "2026-09-02T00:18:11.000Z"
  }
}

409 if the unique-channel limit is reached ({ "code": "CHANNEL_LIMIT", "channelLimit" }). Extra watches on a channel you already track do not consume the limit. 400 for a bad channel or condition. 403 if the trial or subscription is not live.

List watches

GET /api/v1/watches

Every watch on the account, all projects, newest first.

GET /api/v1/watches
Authorization: Bearer spk_live_...

{
  "watches": [
    {
      "id": 12,
      "userId": 1,
      "projectId": 1,
      "channelId": 44,
      "youtubeChannelId": "UCxxxxxxxxxxxxxxxxxxxxxx",
      "channelTitle": "MrBeast",
      "channelThumbnailUrl": "https://yt3.googleusercontent.com/…",
      "triggerDefinitionId": 3,
      "thresholdViews": 3000,
      "windowHours": 1,
      "status": "active",
      "createdAt": "2026-09-02T00:18:11.000Z"
    }
  ]
}

Get a watch

GET /api/v1/watches/:id

Response { "watch": { ... } }. 404 if the id is not yours.

Delete a watch

DELETE /api/v1/watches/:id

Stops that condition. Past events stay. Response { "ok": true }.

List events

GET /api/v1/events?limit=50

Threshold hits, newest first. limit is 1–100, default 50. Same JSON we POST to a webhook. Events exist even when no endpoint is configured. Delivery status is not on this route — use the dashboard log.

GET /api/v1/events?limit=50
Authorization: Bearer spk_live_...

{
  "events": [
    {
      "id": 1842,
      "type": "video.threshold_reached",
      "created": "2026-09-02T00:18:11Z",
      "data": {
        "watchId": 12,
        "projectId": 1,
        "projectName": "Main",
        "channelId": "UCxxxxxxxxxxxxxxxxxxxxxx",
        "channelTitle": "MrBeast",
        "videoId": "dQw4w9WgXcQ",
        "videoTitle": "Why this hook is printing views",
        "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "publishedAt": "2026-09-01T23:18:00Z",
        "viewCount": 3280,
        "lastHourAdded": 3210,
        "threshold": 3000,
        "windowHours": 1
      }
    }
  ]
}

Example

curl -X POST /api/v1/watches \
  -H "Authorization: Bearer spk_live_…" \
  -H "Content-Type: application/json" \
  -d '{"channel":"@handle","thresholdViews":3000,"windowHours":1}'

Create an account