Firehose
API reference

URL Watch endpoints

List, create, update, and delete URL Watch subscriptions and read their crawl diffs over HTTP, authenticated with an organization management key (fhm_).

View as Markdown

These endpoints create and manage URL Watch subscriptions and read their diffs. Like the tap endpoints, they require a management key (fhm_). Base URL: https://api.firehose.com.

A management key acts as the user who created it. These endpoints only see and modify that user's own watches within the organization — a watch owned by another member returns 404.

URL Watch must be available on your plan. It's unavailable on the API only plan, where any create call is rejected with 422.

List watches

GET /v1/url-watch?limit=50

limit is optional, from 1 to your plan's maximum watched URLs (the default). Returns your watches, newest first.

{
  "data": [
    {
      "id": "uuid",
      "url": "https://example.com/pricing",
      "frequency_minutes": 360,
      "status": "active",
      "change_count": 4,
      "last_checked_at": "2026-06-08T09:00:00+00:00",
      "created_at": "2026-06-01T00:00:00+00:00"
    }
  ]
}
FieldDescription
idSubscription identifier, used in the path of the other endpoints.
urlThe watched URL.
frequency_minutesCrawl cadence in minutes (see Frequency values).
statusactive or paused.
change_countNumber of crawls so far that recorded a change.
last_checked_atTimestamp of the most recent crawl, or null if it hasn't been crawled yet.
created_atWhen the watch was created.

Create watch

POST /v1/url-watch
Content-Type: application/json
 
{ "url": "https://example.com/pricing", "frequency_minutes": 360 }

Both fields are required. url must be a valid URL (max 2048 characters) and frequency_minutes must be one of the allowed values for your plan. Returns 201 with the new subscription; the first crawl is queued immediately.

Common 422 responses:

  • Invalid frequency — not an allowed value, or faster than your plan permits.
  • Watched-URL limit reached — already at your plan's maximum watched URLs.
  • Monthly checks exhausted — this month's check quota is used up.
  • Duplicate URLYou are already watching this URL., or This URL is already being watched in your organization. if a teammate watches it.

Get watch (with diffs)

GET /v1/url-watch/:id?limit=50

Returns the subscription plus its crawl history, newest first. limit is optional, from 1 to 100 (default 50).

{
  "data": {
    "id": "uuid",
    "url": "https://example.com/pricing",
    "frequency_minutes": 360,
    "status": "active",
    "change_count": 4,
    "last_checked_at": "2026-06-08T09:00:00+00:00",
    "created_at": "2026-06-01T00:00:00+00:00"
  },
  "diffs": [
    {
      "diff": { "hunks": [[{ "del": ["$19/mo"], "ins": ["$24/mo"] }]] },
      "has_changes": true,
      "created_at": "2026-06-08T09:00:00+00:00"
    },
    {
      "diff": null,
      "has_changes": false,
      "created_at": "2026-06-08T03:00:00+00:00"
    }
  ]
}

Each entry is one crawl. When the page changed, has_changes is true and diff holds the change (see Diff shape). A crawl that found no change — or that errored — has has_changes: false and diff: null; the error detail itself isn't returned over the API.

Update watch

PUT /v1/url-watch/:id
Content-Type: application/json
 
{ "frequency_minutes": 720, "status": "paused" }

Both fields are optional. frequency_minutes must be an allowed value; status is active or paused. Resuming a paused watch (status: "active") while your monthly checks are exhausted returns 422. Returns the updated subscription.

Delete watch

DELETE /v1/url-watch/:id

Returns 204 with no content.

Frequency values

frequency_minutes accepts these values, subject to your plan's fastest interval — slower cadences are always allowed:

MinutesCadenceMinutesCadence
5Every 5 minutes720Every 12 hours
10Every 10 minutes1440Daily
30Every 30 minutes2880Every 2 days
60Hourly7200Every 5 days
180Every 3 hours10080Weekly
360Every 6 hours

The fastest interval allowed is 3 hours on Free, 10 minutes on Starter, and 5 minutes on Advanced and Business. See Quotas & limits.

Diff shape

diff is the stored diff, decoded as JSON. The current format groups the change into hunks — a list of hunks, each a list of blocks with optional ctx (unchanged context), del (removed), and ins (added) line arrays:

{
  "hunks": [
    [
      { "ctx": ["Pricing"] },
      { "del": ["$19/mo"], "ins": ["$24/mo"] }
    ]
  ]
}

Older entries may use a flat chunks array instead — { "chunks": [{ "typ": "ins", "text": "..." }] }, where typ is ins or del. This is the same diff rendered in the dashboard; see Diffs & crawl history.

See Errors & limits for status codes shared across the API.

Next steps