Free key: real listings for yesterday, 500 calls a day, no card148 countriesGet yours in 30 seconds
tvguideapi

Last 30 days

API uptimefrom the monitorIncidentsfrom the monitor
All systems

Working normally

Checked every minute from outside our own servers.

Documentation/Reference

Webhooks

Be called when a followed channel, show or event changes or starts.

On the paid plans, register an https address and we call it when something you follow happens, instead of you asking every few minutes. An account has up to 10 webhooks; make them with Create a webhook.

The events

EventSent whenFollows
schedule.changedA slot on a followed channel was added, removed, moved or retitled, within about half an hour; up to 500 changes a call, the same rows as the change feedchannels or countries
show.startingA followed show starts within 15 minutes on a channelshows, and countries to narrow it
event.startingA followed team's or league's event starts within 15 minutes, with every channel showing itteams or leagues, and countries to narrow it
curl -X POST https://api.tvguideapi.com/v1/webhooks -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/tv", "events": ["event.starting"], "filter": {"teams": ["arsenal"], "countries": ["GB"]}}'

The answer carries the webhook's secret in full, once. Keep it: it signs every call we make to you.

What we send

A POST with a JSON body, the same for every event:

{
    "id": "evt_3f9c2a71b0d4e815",
    "type": "show.starting",
    "created": "2026-10-18T18:45:02Z",
    "data": {
        "show_id": "sh_7qk3m2xa",
        "listing": "ls_k2m9q4ta",
        "channel": "ch_9d4kq2ma",
        "channel_name": "BBC One",
        "country": "GB",
        "start": "2026-10-18T19:00:00Z",
        "title": "EastEnders"
    }
}

With three headers: X-TVG-Event (the event), X-TVG-Delivery (one id per delivery, the same on every try of it) and X-TVG-Signature.

Checking the signature

X-TVG-Signature is t=<unix time>,v1=<hex>, where v1 is an HMAC-SHA256 of the time, a full stop and the raw body, keyed with your secret. Compare it, and refuse a time more than five minutes old:

<?php
$body = file_get_contents('php://input');
preg_match('/t=(\d+),v1=([0-9a-f]+)/', $_SERVER['HTTP_X_TVG_SIGNATURE'] ?? '', $m);
$ok = $m && abs(time() - (int) $m[1]) < 300
    && hash_equals(hash_hmac('sha256', $m[1] . '.' . $body, 'whsec_YOUR_SECRET'), $m[2]);
http_response_code($ok ? 200 : 400);

Answering, and retries

Answer with any 2xx within 10 seconds; do the work after answering. Anything else is tried again, 8 times over about 3 days (after 1 minute, 5 minutes, 30 minutes, 2, 6, 12, 24 and 24 hours). A 4xx other than 408 or 429 means the call will never be accepted, so that delivery stops at once. After 20 failures in a row the webhook is turned off and we email you. Deliveries can arrive more than once and out of order: use X-TVG-Delivery or the event's id to keep one copy.

Testing and reading back

Test a webhook sends the newest real event of that webhook now, marked "test": true, and shows what your server answered. Get a webhook lists its last 50 calls with each answer.

Addresses we call

https only, on the public internet: an address that resolves to a private, loopback or link-local network is refused, when it is made and on every call.