Subscriptions / Watches
Status: ✅ Available | 🤖 Built for AI agents | 🔁 Poll-based
A subscription (a "watch") is a persistent, account-tied monitoring job. The API snapshots the watched commodities every interval_seconds and records an event each interval. Your agent then polls GET /v1/subscriptions/events with a cursor to catch up on what changed — events are polled, not pushed: there is no always-on connection or callback.
A watch is different from a price alert. A watch always emits an event every interval (a running log of snapshots + deltas); an alert only fires when a threshold is crossed.
Available on all tiers (Free included), with count and interval limits that scale by plan. The full feature set is advertised on Professional and Scale.
Authentication
All subscription endpoints require an API key. See the Authentication Guide.
Authorization: Token YOUR_API_KEY
# Bearer is also accepted:
Authorization: Bearer YOUR_API_KEY
Endpoints
| Method | Endpoint | Description | Counts against quota |
|---|---|---|---|
| GET | /v1/subscriptions | List your watches | Yes |
| POST | /v1/subscriptions | Create a watch | Yes |
| GET | /v1/subscriptions/:id | Get a single watch | Yes |
| PATCH | /v1/subscriptions/:id | Update a watch | Yes |
| DELETE | /v1/subscriptions/:id | Delete a watch | Yes |
| POST | /v1/subscriptions/:id/pause | Pause a watch | Yes |
| POST | /v1/subscriptions/:id/resume | Resume a watch | Yes |
| GET | /v1/subscriptions/events | Poll for new events (cursor) | No |
The event poll does not consume your monthly request quota and has its own generous rate limit (60 requests/minute per key), so agents can poll frequently without exhausting their request budget.
Plan gating
Watches are available on every tier; the concurrent-watch count and the minimum snapshot interval scale with the plan:
| Plan | Max active watches | Min interval |
|---|---|---|
| Free | 1 | 1 hour (3600s) |
| Developer | 3 | 30 min (1800s) |
| Starter | 10 | 15 min (900s) |
| Professional | 50 | 5 min (300s) |
| Scale | 1,000 | 1 min (60s) |
The number of codes per watch follows the same per-tier limit as the market brief (Free: 3 → Scale: 50). Webhook delivery (deliver_webhook) requires a plan entitled to webhooks.
List subscriptions
curl "https://api.oilpriceapi.com/v1/subscriptions" \
-H "Authorization: Token YOUR_API_KEY"
{
"status": "success",
"data": {
"subscriptions": [
{
"id": "8f1c2b3a-4d5e-6f70-8a9b-0c1d2e3f4a5b",
"name": "Crude desk hourly",
"codes": ["BRENT_CRUDE_USD", "WTI_USD"],
"interval_seconds": 3600,
"status": "active",
"deliver_webhook": false,
"source": "mcp",
"tool_name": "opa_create_price_subscription",
"last_evaluated_at": "2026-06-21T14:00:00Z",
"next_run_at": "2026-06-21T15:00:00Z",
"created_at": "2026-06-20T09:30:00Z"
}
]
}
}
Create a subscription
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
codes | array | Yes | Commodity codes to watch (e.g. ["BRENT_CRUDE_USD","WTI_USD"]). Shorthand aliases (WTI) are resolved. A single code string is also accepted and folded into codes. |
interval_seconds | integer | Yes | Snapshot interval. Must be at or above your plan's minimum (see Plan gating). |
name | string | No | Human-readable label (max 120 chars). |
deliver_webhook | boolean | No | Deliver events to your configured webhook endpoint. Requires a webhook-entitled plan. |
status | string | No | active (default) or paused. |
Attribution headers
When a watch is created programmatically by an agent, two optional headers stamp it for analytics (the OilPriceAPI MCP server sets these automatically):
| Header | Description |
|---|---|
X-OPA-Source | Origin of the watch: mcp, api, or dashboard (default api). |
X-OPA-Tool | The tool/integration name, e.g. opa_create_price_subscription. |
Example
curl -X POST "https://api.oilpriceapi.com/v1/subscriptions" \
-H "Authorization: Token YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "X-OPA-Source: mcp" \
-H "X-OPA-Tool: opa_create_price_subscription" \
-d '{
"name": "Crude desk hourly",
"codes": ["BRENT_CRUDE_USD", "WTI_USD"],
"interval_seconds": 3600
}'
{
"status": "success",
"data": {
"subscription": {
"id": "8f1c2b3a-4d5e-6f70-8a9b-0c1d2e3f4a5b",
"name": "Crude desk hourly",
"codes": ["BRENT_CRUDE_USD", "WTI_USD"],
"interval_seconds": 3600,
"status": "active",
"deliver_webhook": false,
"source": "mcp",
"tool_name": "opa_create_price_subscription",
"last_evaluated_at": null,
"next_run_at": "2026-06-21T15:00:00Z",
"created_at": "2026-06-21T14:30:00Z"
}
}
}
Update / pause / resume / delete
# Update interval or codes
curl -X PATCH "https://api.oilpriceapi.com/v1/subscriptions/SUBSCRIPTION_ID" \
-H "Authorization: Token YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "interval_seconds": 1800 }'
# Pause (stops emitting events; keeps the watch)
curl -X POST "https://api.oilpriceapi.com/v1/subscriptions/SUBSCRIPTION_ID/pause" \
-H "Authorization: Token YOUR_API_KEY"
# Resume
curl -X POST "https://api.oilpriceapi.com/v1/subscriptions/SUBSCRIPTION_ID/resume" \
-H "Authorization: Token YOUR_API_KEY"
# Delete (removes the watch and its event history) → 204 No Content
curl -X DELETE "https://api.oilpriceapi.com/v1/subscriptions/SUBSCRIPTION_ID" \
-H "Authorization: Token YOUR_API_KEY"
Poll events
A per-user cursor poll. Each event has a monotonic seq that is unique and stable per account. Pass the cursor from the previous response as since to get only newer events. This endpoint does not count against your request quota.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
since | integer | No | Return events with seq greater than this cursor. Default 0 (from the beginning). |
limit | integer | No | Max events to return (1–500, default 100). |
watch_id | string | No | Restrict to a single watch's events. |
Example
# First poll — from the beginning
curl "https://api.oilpriceapi.com/v1/subscriptions/events?since=0" \
-H "Authorization: Token YOUR_API_KEY"
# Subsequent polls — pass the cursor from the previous response
curl "https://api.oilpriceapi.com/v1/subscriptions/events?since=42" \
-H "Authorization: Token YOUR_API_KEY"
{
"status": "success",
"data": {
"cursor": 44,
"has_more": false,
"events": [
{
"id": "c1a2b3d4-...",
"seq": 43,
"watch_id": "8f1c2b3a-4d5e-6f70-8a9b-0c1d2e3f4a5b",
"observed_at": "2026-06-21T15:00:00Z",
"snapshot": {
"BRENT_CRUDE_USD": {
"price": 78.42,
"change_24h_pct": 1.23,
"currency": "USD",
"as_of": "2026-06-21T15:00:00Z"
},
"WTI_USD": {
"price": 74.1,
"change_24h_pct": 1.05,
"currency": "USD",
"as_of": "2026-06-21T15:00:00Z"
}
},
"deltas": {
"BRENT_CRUDE_USD": { "price_change": 0.31, "pct_change": 0.4 },
"WTI_USD": { "price_change": 0.18, "pct_change": 0.24 }
},
"source": "mcp",
"tool_name": "opa_create_price_subscription"
}
]
}
}
Event Fields
| Field | Type | Description |
|---|---|---|
cursor | integer | Highest seq returned; pass as since on the next poll |
has_more | boolean | true if more events are available beyond limit |
events[].seq | integer | Per-account monotonic sequence number |
events[].watch_id | string | The watch that produced the event |
events[].observed_at | string | ISO 8601 snapshot time (UTC) |
events[].snapshot | object | { code: { price, change_24h_pct, currency, as_of } } |
events[].deltas | object | Per-code change vs the prior snapshot (price_change, pct_change); empty on first observation |
Retention: events are retained for 14 days. Poll regularly and persist anything you need to keep beyond that window.
Errors
| Code | Status | Description |
|---|---|---|
WATCH_LIMIT | 422 | More active watches than your plan allows; response includes limit, current, and upgrade_url |
VALIDATION_ERROR | 422 | Invalid codes, interval below your plan floor, too many codes, or webhook delivery without entitlement |
NOT_FOUND | 404 | Watch id not found on your account |
INVALID_API_KEY | 401 | Missing or invalid API key |
RATE_LIMIT_EXCEEDED | 429 | Poll lane allows 60 requests/minute per key |
Related
- Agent Subscriptions with MCP - AI-agent recipe
- Get Market Brief - One-shot multi-commodity snapshot
- Price Alerts - Threshold-crossing notifications
- Webhooks - Push delivery and signature verification