If you have any questions, encounter bugs, or just want to say hello, send us an email at dev@spotwatch.io.
The Spotwatch API is accessible via HTTPS through api.spotwatch.io
. You can pass arguments either as query strings or as JSON content with the content type application/json
. Successful requests return 200 OK
, while failed requests return either 400 Bad Request
or 403 Forbidden
with an error message in text/plain
.
Most requests require a valid API key. The API key can be provided either as a parameter or as a header field Authorization
with the type key
.
Using API key as a query parameter
$ curl -i 'https://api.spotwatch.io/get-ad
?ad_fields=categories
' -H '
Authorization: key
your-key'
Using API key in a JSON body
$ curl -i 'https://api.spotwatch.io/get-ad
' -d '
{"key":"your-key"
,"ad_fields":["categories"]}'
Error response example
HTTP/1.1 400 Bad Request
Content-Type: text/plain
Argument(s) missing. Expected [key, id], got [key, ad_fields], missing [id].
Success response example
HTTP/1.1 200 OK
Content-Type: application/json
{
"categories" : [ "telecommunication", "electronics", "mobile" ]
}
By default, timestamps are provided in ISO 8601 format in UTC. You can specify the desired time format for timestamps in your requests using the time_fmt
parameter.
Accepted values for time_fmt
are:
value | formatting | output example | |
---|---|---|---|
iso8601 |
YYYY-MM-DDTHH:MM:SSZ |
2022-03-31T06:07:07Z | *default |
unix |
integer |
1678454850 | |
plain |
YYYY-MM-DD HH:MM:SS |
2022-03-31 08:07:07 |
The plain
format returns a timestamp adjusted to the timezone set for your API key. By default, the timezone is Europe/Berlin
.
Set your timezone with
/set-timezone-for-api-key
Arguments
key |
string | your API key |
tz |
string | the timezone to set |
Example
/set-timezone-for-api-key
?key=your-key
&tz=Europe/London
Default timezone set to [Europe/London].
Requests with date arguments, usually indicated with a *_to / *_from
postfix, accept either ISO 8601, unix or a short day format
YYYY-MM-DD
.
Example
/get-ads
?key=your-key
&lastseen_from=2022-06-30
&lastseen_to=1656592050
Requests potentially returning huge datasets accept an optional page_lim
argument:
page_lim |
integer |
sets the limit for results per page
no limit / all on one page when -1
default 200
|
and return an additional page
object with fields:
index |
integer | current page index zero based |
prev |
string |
link to the previous page
null if first page
|
next |
string |
link to the next page
null if last page
|
results_total |
integer | total number of results (all pages combined) | pages_total |
integer | total number of pages |
Example
/get-broadcasts
?key=your-key
&time_fmt=unix
&page_lim=1000
Returns
{
"page": {
"index": 0,
"prev": null,
"next": "/hl0fserktnimhbcnfcmq",
"results_total": 424588,
"pages_total": 425
},
"results": [
...
]
}
The prev
and next
fields are links to the next / previous pages.
api.spotwatch.io/hl0fserktnimhbcnfcmq
retuns the next page
Get your key with
/get-api-key
Arguments
email |
string | your email |
pw |
string | your password |
Returns
Your API key as text/plain
.
Example
/get-api-key
?email=you@email.com
&pw=your-password
$ curl https://api.spotwatch.io/get-api-key
-d '
{"email":"you@email.com"
,"pw":"your-password"}'
Response
z8ragt1hfjsakilrfc4ehr3plfdt89b0
Get a single ad with
/get-ad
Arguments
key |
string | your API key |
id |
integer | the ad ID |
ad_fields |
string(s)comma-separated or json array | fields the ad object shall containdefault all |
broadcast_fields |
string(s)comma-separated or json array | fields the nested broadcast objects shall containdefault all except program
genre
subgenre
ad
|
time_fmt |
time format |
Returns
The ad with given ID as application/json
.
Example
/get-ad
?key=your-key
&id=3893859079416045
{
"id": 3893859079416045,
"created": "2022-03-31T06:07:07Z",
"lastseen": "2022-06-12T22:26:26Z",
"duration": 20,
"brand": "vodafone",
"description": "allnet flat",
"categories": [ "telecommunication" ],
"nbroadcasts": 1,
"broadcasts": [
{
"id": 39840,
"time": "2022-06-11T18:08:46Z",
"region": "de",
"channel": "vox",
"ad": 3893859079416045,
"block": 1259,
"blockindex": 3
}
],
"related": [ 2798804439039186 ],
"media": {
"video": {
"mp4": "/klwc7ilp41lgb8kiopye"
},
"image": {
"preview": "/9dgnbp81g6jndapeazyy",
"grid": "/pjbphmperbfaopf4qx8s"
}
}
}
Get multiple ads with
/get-ads
Arguments
key |
string | your API key |
ids |
integers(s)comma-separated or json array | filter by Ad-ID(s) |
category |
string(s)comma-separated or json array | filter by categories |
product |
string(s)comma-separated or json array | filter by product(s) |
event |
string(s)comma-separated or json array | filter by event(s) |
brand |
string(s)comma-separated or json array | filter by brand |
region |
string(s)comma-separated or json array | filter by region |
unidentified |
bool | include ads which are not identified default true
|
self_promo |
bool | include self promotional ads default true
|
created_from |
date | lower limit for creation date |
created_to |
date | upper limit for creation date |
lastseen_from |
date | lower limit for last seen date |
lastseen_to |
date | upper limit for last seen date |
time_seen_from |
date | only return ads broadcasted from time_seen_from |
time_seen_to |
date | only return ads broadcasted until time_seen_from |
duration_from |
integer | lower limit for ad durationin seconds |
duration_to |
integer | upper limit for ad durationin seconds |
ad_fields |
string(s)comma-separated or json array | fields the ad objects shall containdefault all |
broadcast_fields |
string(s)comma-separated or json array | fields the nested broadcast objects shall containdefault all except program
ad
|
keyword |
string(s)comma-separated or json array | only return ads which contain one of given keyword(s) |
time_fmt |
time format |
Returns
Page and array containing matched ads as application/json
.
Example
/get-ads
?key=your-key
&category=telecommunication
&ad_fields=id,lastseen,media
&time_fmt=unix
{
"page": { ... }
"results": [
{
"id": 6353806529225371,
"lastseen": 1656592050,
"media": {
"video": {
"mp4": "/klwc7ilp41lgb8kiopye"
},
"image": {
"preview": "/azfe4d2qwcmk0shik1gw",
"grid": "/pjbphmperbfaopf4qx8s"
}
}
},
...
]
}
Get a single broadcast with
/get-broadcast
Arguments
key |
string | your API key |
id |
integer | the broadcast ID |
broadcast_fields |
string(s)comma-separated or json array | fields the broadcast object shall containdefault all |
time_fmt |
time format |
Returns
The broadcast with given ID as application/json
.
Example
/get-broadcast
?key=your-key
&id=39840
{
"id": 39840,
"time": "2022-06-11T18:08:46Z",
"region": "de",
"channel": "vox",
"ad": 3893859079416045,
"block": 1259,
"blockindex": 3,
"program": "gute zeiten, schlechte zeiten",
"genre": "serien",
"subgenre": "daily soap"
}
Get multiple broadcasts with
/get-broadcasts
Arguments
key |
string | your API key |
channel |
string(s)comma-separated or json array | filter by channel |
region |
string(s)comma-separated or json array | filter by region |
ad_category |
string(s)comma-separated or json array | filter by ad category |
ad_brand |
string(s)comma-separated or json array | filter by ad brand |
time_from |
date | lower limit for broadcast date |
time_to |
date | upper limit for broadcast date |
ad_id |
integer(s)comma-separated or json array | only return broadcasts for given Ad-ID(s) |
broadcast_fields |
string(s)comma-separated or json array | fields the broadcast objects shall containdefault all |
time_fmt |
time format |
Returns
Page and array containing matched broadcasts as application/json
.
Example
/get-broadcasts
?key=your-key
&channel=rtl,dmax
&ad_brand=sony
&time_from=2022-06-09
&time_fmt=plain
&broadcast_fields=ad,time,region,channel
{
"page": { ... },
"results": [
{
"ad": 2371504209363725,
"time": "2022-05-06 18:40:10",
"region": "de",
"channel": "dmax",
},
...
]
}
Get all broadcasts for an ad with
/get-broadcasts-for-ad
Arguments
key |
string | your API key |
ad |
integer | the ad ID |
broadcast_fields |
string(s)comma-separated or json array | fields the broadcast objects shall containdefault all |
region |
string(s)comma-separated or json array | return broadcasts for specific region(s)default all |
fmt |
string | return format, csv or json default json |
csv_delimiter |
string | delimiter for the returned csvdefault , |
time_fmt |
time format |
Returns
An array containing all broadcast objects for given ad as
application/json
on fmt=json
text/csv
on fmt=csv
Example
/get-broadcasts-for-ad
?key=your-key
&ad=2798804439039186
&fmt=csv
&csv_delimiter=;
"id";"time";"region";"channel";"ad";"block";"blockindex"
"47501";"2022-06-09 01:00:00";"de";"rtl";"3392276504707697";"5922";"0"
...
Get a single broadcast block with
/get-block
Arguments
key |
string | your API key |
id |
integer | the block ID |
ad_fields |
string(s)comma-separated or json array | fields the nested ad objects shall containdefault id only |
broadcast_fields |
string(s)comma-separated or json array | fields the nested broadcast objects shall containdefault id only |
time_fmt |
time format |
Returns
The block with given ID as application/json
.
Example
/get-block
?key=your-key
&id=1259
&ad_fields=id,duration
{
"id": 1259,
"region": "de",
"channel": "rtl",
"start": "2022-06-09T01:00:00Z",
"finish": "2022-06-09T01:01:31Z",
"program": "two and a half men",
"genre": "serien",
"subgenre": "comedyserie",
"ads": [
{
"id": 3392276504707697,
"duration": 20
},
...
]
}
Get multiple broadcast blocks with
/get-blocks
Arguments
key |
string | your API key |
channel |
string(s)comma-separated or json array | filter by channel |
region |
string(s)comma-separated or json array | filter by region |
start_from |
date | lower limit for broadcast date |
start_to |
date | upper limit for broadcast date |
ad_fields |
string(s)comma-separated or json array | fields the nested ad objects shall containdefault id only |
broadcast_fields |
string(s)comma-separated or json array | fields the nested broadcast objects shall containdefault id only |
ad_id |
integer(s)comma-separated or json array | list only blocks which contain any of the specified ad ID(s) |
time_fmt |
time format |
Returns
Page and array containing matched block objects as application/json
.
Example
/get-blocks
?key=your-key
&start_from=2022-06-11
{
"page": { ... }
"results": [
{
"id" : 661,
"region": "de",
"channel" : "sat1",
"start" : "2022-06-11T01:00:00Z",
"finish" : "2022-06-11T01:01:31Z",
"program": "navy cis",
"genre": "serien",
"subgenre": "krimiserie"
"ads" : [
{
"id" : 767171625096234
},
...
]
}
]
}
Make multiple API requests in one go with
/batch
Arguments
key |
string | your API key |
requests |
json array | json objects with form: { "mapkey": "", "path": "", "args": {} } |
concurrent |
bool | allows concurrent processing of multiple requestsdefault false |
Returns
A map (mapkey -> result) of json objects with form:
{
"code": "", "reply": ""
}
Example
$ curl https://api.spotwatch.io/batch -H 'Authorization: key your-key' -d '{
"requests": [
{
"mapkey": "first",
"path": "/get-block",
"args": { "id": 810, "ad_fields": ["id", "brand"] }
},
{
"mapkey": "second",
"path": "/get-block",
"args": { "id": 14426, "ad_fields": ["id", "brand"] }
}
]
}'
Result
{
"first": {
"code": 200,
"reply": {
"id": 810,
"region": "de",
"channel": "viva",
"start": "2022-06-25T07:45:38Z",
"finish": "2022-06-25T07:46:18Z",
"ads": [
{ "id": 504038989557373, "brand": "goodgame.de" },
{ "id": 3996816512810860, "brand": "wimdu.de" }
]
}
},
"second": {
"code": 400,
"reply": "Block ID [14426] not found."
}
}
To avoid exposing sensible information in urls, mask requests with
/mask
Arguments
key |
string | your API key |
path |
string | request path |
args |
json | request arguments |
ttl |
integer |
time to live for returned link, in seconds
no limit when -1
default 7200 (2 hours)
|
ctl |
integer |
calls to live for returned link
no limit when -1
default -1
|
allow_args |
bool |
allows late binding for arguments
default false
|
Returns
Generated link in text/plain
.
Example
$ curl https://api.spotwatch.io/mask -d '{
"key": "your-key",
"allow_args": true,
"path": "/get-ad",
"args": {
"ad_fields": ["id", "brand", "description", "media"],
"time_fmt": "plain"
}
}'
/t1o0rc7lt1887qjnruje
The generated link can be called with arguments when allow_args
is set to true
:
/t1o0rc7lt1887qjnruje
?id=8763496104749285
Set a webhook for broadcast push messages with
/set-push-broadcast
Arguments
key |
string | your API key |
url |
string | push endpoint |
token |
string | your chosen token |
time_fmt |
time format | |
ad_fields |
string(s)comma-separated or json array | fields the nested ad object shall contain
default:
id
created
lastseen
duration
nbroadcasts
brand
description
categories
related
media
|
Push messages are sent over HTTP/HTTPS using the POST
method with a Content-Type
of application/json
. To verify a given endpoint, the server will send a ping message:
{ "ping": "random-string" }
The server expects the random string to be sent back as text/plain
.
When setting an endpoint, you can pass an optional argument called token
. This token can be any string of your choosing and will be included with every push message sent to the endpoint. You can use this token on your end to verify that the request comes from an authorized source.
Please note that only one endpoint can be set at any given time. Setting a new endpoint will overwrite the previous one.
To set an endpoint, use the following API call:
/set-push-broadcast
?key=your-key
&url=https://your-domain.net/your-webhook-endpoint
&token=your-chosen-token
To delete an endpoint, use the following API call:
/delete-push-broadcast
?key=your-key
The following is an exemplary implementation of setting up a webhook and receiving messages:
express = require("express")
axios = require("axios")
crypto = require("crypto")
bodyParser = require("body-parser")
spotwatchApiKey = "your-api-key"
webhookUrl = "https://your-domain.net/spotwatch-webhook"
randomToken = crypto.randomBytes(32).toString("hex")
setupBroadcastWebhook = () ->
apiRequestUrl = "https://api.spotwatch.io/set-push-broadcast"
# Pass your webhook URL along with the generated token
requestBody =
key: spotwatchApiKey
url: webhookUrl
token: randomToken
try
await axios.post(apiRequestUrl, requestBody)
console.log("Webhook set up successfully.")
catch error
console.log("Failed to set up webhook => #{error.response?.data}")
handleBroadcastMessage = (message) ->
# Process and handle the broadcast message
console.log(message)
app = express()
app.use(bodyParser.json())
# The endpoint which will be called to deliver broadcast messages
app.post "/spotwatch-webhook", (request, response) ->
body = request.body
token = body?.token
# This token should match your generated token
if token isnt randomToken
# Unauthorized access
response.status(403).end()
else if body.ping?
# Respond with the incoming ping in clear text
response.end(body.ping)
else
response.end()
# Handle incoming broadcast message
handleBroadcastMessage(body.message)
app.listen process.env.PORT, () ->
# Set up the webhook once the server is running
setupBroadcastWebhook()
{
"token": "your-chosen-token",
"push_type": "broadcast",
"message": {
"broadcast": {
"id": 895797,
"time": "2022-09-13T13:01:28Z",
"region": "de",
"channel": "sport1",
"ad": 1843718744355554,
"block": 110529,
"blockindex": 0,
"program": "american chopper"
"genre": "report",
"subgenre": "dokumentation"
},
"timings": {
"start": "2022-09-13T13:01:28Z",
"end": "2022-09-13T13:01:48Z",
"detected": "2022-09-13T13:01:30Z"
},
"ad": {
"id": 1843718744355554,
"brand": "alfa romeo",
...
}
}
}
You can also set up an internal message queue for broadcast messages. This can be accomplished by passing the special /message-queue
URL parameter to /set-push-broadcast
as shown below:
/set-push-broadcast
?key=your-key
&url=/message-queue
If /message-queue
is used as the endpoint, new broadcast messages will be queued in an internal queue. The maximum number of queued messages is 1000. If the messages in the queue exceed this maximum number, old messages will be replaced by new ones.
To access your message queue, call:
/get-message-queue
Arguments
key |
string | your API key |
num_messages
|
integer |
maximum number of messages to return
default -1 which means all messages
|
Returns
An array containing up to num_messages
or all messages, sorted from oldest to newest, in application/json
format.
All returned messages are considered delivered and will be removed from the internal queue.
Fetch all queued messages
/get-message-queue
?key=your-key
Fetch up to 100 queued messages
/get-message-queue
?key=your-key
&num_messages=100
{
"messages": [
{
"push_type": "broadcast"
"message": {
"broadcast": {
"id": 181132408,
"time": "2024-07-29T19:31:01Z",
"region": "de",
"channel": "tlc",
"ad": 8693926032257232,
"block": 1728925,
"blockindex": 13,
"program": "Dating ohne Grenzen: In 90 Tagen zum Altar"
"genre": "report",
"subgenre": "reality-soap"
},
"timings": {
"start": "2024-07-29T19:31:01Z",
"end": "2024-07-29T19:31:11Z",
"detected": "2024-07-29T19:31:04Z"
},
"ad": {
"id": 8693926032257232,
"brand": "emma",
"created": "2024-07-04T04:43:47Z",
"lastseen": "2024-07-29T19:31:01Z",
"duration": 10,
...
}
}
},
...
]
}
Get all available regions with
/get-all-regions
Arguments
key |
string | your API key |
Returns
A list of all available regions as application/json
.
Get all channels for which data is available, including historical data
/get-all-channels
Arguments
key |
string | your API key |
fmt |
string | return format, csv or json default json |
Returns
A map of all available channels mapped by region as application/json
or a list as text/csv
.
Get all currently tracked channels with
/get-tracked-channels
Arguments
key |
string | your API key |
fmt |
string | return format, csv or json default json |
Returns
A map of all available channels mapped by region as application/json
or a list as text/csv
.
Get all categories with
/get-all-categories
Arguments
key |
string | your API key |
Returns
A list of all categories as application/json
.
Get all brands with
/get-all-brands
Arguments
key |
string | your api key |
region |
string(s)comma-separated or json array | filter by region |
channel |
string(s)comma-separated or json array | filter by channel |
time_seen_from |
time format | return only brands seen from time_seen_from |
time_seen_to |
time format | return only brands seen until time_seen_to |
Returns
A list of all brands as application/json
.
Get all possible tv genres and subgenres with
/get-all-tv-genres
Arguments
key |
string | your API key |
Returns
A map of all possible genres and subgenres mapped by region as application/json
.
Field | Type | Description |
---|---|---|
id |
integer | ID of ad |
created |
time format | time when ad was generated |
lastseen |
time format | last time ad was seen |
duration |
integer | ad duration in seconds |
brand |
string | the advertised brand, empty string if no brand assigned |
description |
string | short description of advertised content, empty string if no description made |
regions |
array of strings | country code(s) of regions this ad is broadcasted in |
categories |
array of strings | categories of ad |
broadcasts |
array of broadcasts | all broadcasts of ad |
nbroadcasts |
integer | number of broadcasts |
self_promo |
bool | true or false if this ad is a broadcaster self promotion |
url |
string | visible url in ad, empty string if ad does not contain an url |
media |
media | video and images of ad |
related |
array of integers | IDs of ads this ad is looking similar to |
cross_region_ads |
map of string => integer | ads broadcasted in other regions which look exactly like this ad, ad IDs mapped by country code |
user_data |
string | custom user data |
Field | Type | Description | |
---|---|---|---|
image |
object | images of ad, null if ad has no images yet |
|
preview |
string | path to preview image | |
preview_xs |
string | path to smaller version of preview image | |
grid |
string | path to image from different ad snapshots arranged in a 3x3 grid | |
grid_xs |
string | path to smaller version of grid image | |
video | object | videos of ad, null if ad has no videos yet | |
mp4 | string | path to .mp4 version of video |
Field | Type | Description |
---|---|---|
id |
integer | ID of broadcast |
time |
time format | start time of broadcast |
ad |
integer | ID of broadcasted ad |
region |
string | region code of broadcast region |
channel |
string | name of broadcast channel |
block |
integer | ID of broadcast block |
blockindex |
integer | position of broadcast in broadcast block starting at 0 |
block_length |
integer | total number of broadcasts in broadcast block |
pic_in_pic |
bool | true or false if broadcast is special picture in picture format |
ad_brand |
string | brand of broadcasted ad |
ad_categories |
array of strings | categories of broadcasted ad |
ad_description |
string | description of broadcasted ad |
ad_duration |
integer | duration of broadcasted ad |
ad_nbroadcasts |
integer | total number of broadcasts of broadcasted ad |
program |
string | name of TV-program during broadcast, empty string if no program data available |
genre |
string | genre of TV-program, empty string if no program data available |
subgenre |
string | subgenre of TV-program, empty string if no program data available |
prev_program |
string | name of TV-program from previous block |
prev_genre |
string | genre of TV-program from previous block |
prev_subgenre |
string | subgenre of TV-program from previous block |
next_program |
string | name of TV-program from next block |
next_genre |
string | genre of TV-program from next block |
next_subgenre |
string | subgenre of TV-program from next block |
Field | Type | Description |
---|---|---|
id |
integer | ID of block |
start |
time format | start time of broadcast block |
finish |
time format | end time of broadcast block |
region |
string | region code of broadcast region |
channel |
string | name of broadcast channel |
ads |
array of ads | ads in this broadcast block, same order as they were broadcasted |
program |
string | name of TV-program during broadcast, empty string if no program data available |
genre |
string | genre of TV-program empty string if no program data available |
subgenre |
string | subgenre of TV-program empty string if no program data available |
prev_program |
string | name of TV-program from previous block |
prev_genre |
string | genre of TV-program from previous block |
prev_subgenre |
string | subgenre of TV-program from previous block |
next_program |
string | name of TV-program from next block |
next_genre |
string | genre of TV-program from next block |
next_subgenre |
string | subgenre of TV-program from next block |