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_).
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=50limit 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"
}
]
}| Field | Description |
|---|---|
id | Subscription identifier, used in the path of the other endpoints. |
url | The watched URL. |
frequency_minutes | Crawl cadence in minutes (see Frequency values). |
status | active or paused. |
change_count | Number of crawls so far that recorded a change. |
last_checked_at | Timestamp of the most recent crawl, or null if it hasn't been crawled yet. |
created_at | When 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 URL —
You are already watching this URL., orThis URL is already being watched in your organization.if a teammate watches it.
Get watch (with diffs)
GET /v1/url-watch/:id?limit=50Returns 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/:idReturns 204 with no content.
Frequency values
frequency_minutes accepts these values, subject to your plan's fastest interval — slower cadences
are always allowed:
| Minutes | Cadence | Minutes | Cadence | |
|---|---|---|---|---|
5 | Every 5 minutes | 720 | Every 12 hours | |
10 | Every 10 minutes | 1440 | Daily | |
30 | Every 30 minutes | 2880 | Every 2 days | |
60 | Hourly | 7200 | Every 5 days | |
180 | Every 3 hours | 10080 | Weekly | |
360 | Every 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
Quotas & limits
How checks are counted and the caps that drive the 422 responses above.
Creating watches
The same workflow from the dashboard.
Management keys
Create and rotate the fhm_ key these endpoints use.