API 20141201

Robert Kulagowski edited this page Feb 1, 2017 · 78 revisions

Preface

Any user with a valid Schedules Direct login may use the API. Developers may send email to grabber@schedulesdirect.org for assistance, but the Developers Corner should be your first stop.


NOTE: our contract with our upstream provider limits us to providing data for individual use only and exclusively to Open Source software; using an open source program as "middleware" and then pushing data into a commercial application violates the terms of service. Please see the subscriber agreement if you have questions. If you would like to use the data in a commercial, academic or governmental environment send an email to Kyle Brownell at Gracenote.


This page describes API version 20141201. Last update: 2016-07-11.

The server implements a RESTful interface.

There are multiple tools which can assist if you're implementing a REST client; two good ones are the Postman helper in Chrome and JSONlint at http://jsonlint.org

You can also use the mfdb-json PHP scripts at https://github.com/SchedulesDirect/mfdb-json as a starting point.

DateTime responses are in "Z" / UTC time. There are no Daylight Saving Time adjustments made in any DateTime values.

Design goals

From the outset, the design goals of the JSON API was to minimize the amount of data which needed to be sent from the server to the client. Throughout the API you will see that it makes liberal use of "modified" and MD5 hashes to allow a client to determine if it needs to perform an update on any particular piece of information. To reduce server-side processing Schedules Direct will not maintain a list of channels that you want sent to you; it's up to the client to request what they want when they make the request. (This makes the server architecture almost stateless and allows us to scale easily)

The API architecture allows your client to quickly determine things like:

  • Has the lineup mapping (the list of which content is on which channel) for a headend changed? If yes, then the modified date of the lineup will be updated. If your copy has a different modified date, then download the update. (It is still up to your client to determine whether the lineup should be applied automatically, whether you will run a diff of the existing vs. the new)
  • Has the schedule for a stationID changed since the last time you downloaded it? If yes, download a new one. Schedule updates happen multiple times per day, but not all schedules may have an update.
  • Have their been any updates to the programs in the schedule? The schedule for a stationID will tell you the programID that's in a timeslot, and the MD5 hash of the data for that program. But it doesn't automatically include the program data itself - that's a separate API call. Your application could compare the hash in the schedule with the hash of your local copy of the program data. If the MD5 hash in the schedule data is the same as what you already have from a previous download, then there's nothing to do. Or, the same program is played multiple times in a 2 week period over multiple stationIDs. It will still be the same program, with the same MD5 hash. Your application would only need to download it once as part of a batch request you send to the server for programIDs that you require. If it's different, then there may be new guest stars, or a late-breaking program update has occurred, so your client can include the programID in the batch request of new / updated programIDs.

Lineups and Headends

A headend may contain multiple lineups; a lineup is a specific mapping of channels and stationIDs. For example, for a "Cable" transport lineup, the headend may have three separate lineups: one for analog channels, which don't require a set-top-box, one for digital cable, which does require a set top box, and a QAM lineup, which is content which is available that is digital, but does not require a set-top-box.

Some examples:

  • You may have a lineup that doesn't require external hardware in order to tune. For a lineup that uses the transport type "Cable", this would be channels "2" through "125". DVB-C, -S and -T also fall into this category. In the data, these will have a device type of "DEFAULT".
  • You may have a digital lineup; one that requires an external set-top-box of some sort. For a cable lineup, most digital lineups are designated with an "X" as the device for historical reasons.
  • You may have a QAM lineup; cable TV content which is available with a QAM tuner. The device type would be "QAM".

Tasks your client must perform

A client process flow during initial configuration would be:

  • Using a web browser, configure an account at the Schedules Direct website. Accept the Terms of Service, etc.

Using a grabber client:

  • Set a useragent in the header of your request. The useragent will allow Schedules Direct and the developers to work together if there are bugs; please see http://forums.schedulesdirect.org/viewtopic.php?f=17&t=2597
  • Obtain the token for this session. If the token response indicates that the system is offline, you should disconnect. See Obtain a token for examples of success and failure.
  • Obtain the current status.
  • If the system status is "Offline" then disconnect; all further processing will be rejected at the server. A client should not attempt to reconnect for 1 hour.
  • Obtain the list of headends for the postal code.
  • Allow the user to select which lineup they want data for. Use the PUT function to add that lineup to their account at Schedules Direct. By default, a user may have 4 lineups in their account, but this can be modified by sending a request through the Schedules Direct ticket service or by sending an email to grabber@schedulesdirect.com
  • You may perform 6 "adds" in a 24 hour period. The status response will indicate the number of lineup changes remaining.
  • Download the lineup. This will provide the user the mapping of channels, callsigns and stationIDs.
  • Allow the user to select which stations they wish to receive data for - this is done at the client; the server does not maintain a list of stations for the user, only the lineup name.
  • Send a request for the schedules for those stationID's to the server. You may request the schedule data for all days for the stationID, or a subset. Use the "date" element in the request if you'd like to specify which days to get the schedule for. This can also be used to process data in batches if you have a memory or CPU-limited client.
  • Process the schedules; each stationID will typically contain at least 14 days of data. Some stationID's may have more than 14 days; some which are outside of North America may have as little as 7 days if the broadcaster doesn't provide daily updates to our upstream.
  • Determine which programID's need to be downloaded. During an initial download, the client will have an empty cache of programID's / MD5 hashes, so the client will need to download all relevant programID's.

NOTE: the server has been successfully tested with over 30,000 programID requests, but the response may overload the client. Therefore there is a hard-coded limit on the server; you may only request 5000 programIDs, schedules, or schedule MD5's per request. (But you may issue multiple requests if you need more than 5000 pieces of information from the server.) There is a 10-minute timeout on the server; if the response to your request can not be sent to you within 10 minutes, it will terminate at the 10 minute point. So, do not request 5000 programIDs if you are on a 33.6Kbps dial-up.

Once the client is in a steady state:

  • Obtain the token for this session. If the token response indicates that the system is offline, you should disconnect. See Obtain a token for examples of success and failure.
  • Obtain the current status.
  • If the system status is "Offline" then disconnect; all further processing will be rejected at the server. A client should not attempt to reconnect for 1 hour.
  • Check the status object and determine if any lineups on the server have newer "modified" dates than the one that is on the client. If yes, download the updated lineup.
  • If there are no changes to the lineups, send a request to the server for the MD5 hashes of the schedules that you are interested in. If the MD5 hash for the schedule is the same as you have locally cached from your last download, then the schedule on the server hasn't changed and your client should disconnect.
  • If the MD5 hash for the schedule is different, then download the schedules that have different hashes.
  • Parse the schedule, determine if the MD5 of the program for a particular timeslot has changed. If the programID for a timeslot is the same, but the MD5 has changed, this means that some sort of metadata for that program has been updated.
  • Request the "delta" programID's as determined through the MD5 values.

Requesting only stationID's and programID's that the user is interested in will minimize the time and data required in each download. Downloading only schedules and programs that are different than what you have already downloaded will minimize the download time and processing your client must perform.

Data updates occur seven days a week. At a minimum there will be two data refreshes per day. Use of the MD5 for the schedule will allow your client to determine if a particular stationID has an updated schedule. (Not all stationIDs may be refreshed in a particular time block if there are no server-side updates.)

Using Postman

The following examples give some pointers on how to use the Chrome POSTMan client to step through the tasks that your program must perform in order to use the service.

Obtain a token

This is the first thing your client must do; almost all commands require a token in the header.

A token is considered invalid if any of the following occurs

  • 24 hours elapse since the token was first granted
  • A new token is requested

POST https://json.schedulesdirect.org/20141201/token

with the body (click the "Raw" button) of the POST being:

{"username":"rkulagow@rocketmail.com", "password":"sha1hexpassword"}

The password field is the sha1_hex hash of the user's password, resulting in a 40-character string being passed to the server. The hash must be sent in lowercase.

Response:

The server will respond with one of the following:

{
    "code": 0,
    "message": "OK",
    "serverID": "AWS-SD-web.1",
    "datetime": "2016-08-23T13:55:25Z",
    "token": "f3fca79989cafe7dead71beefedc812b"
}

If the system is unavailable, you will receive:

{
    "response": "SERVICE_OFFLINE",
    "code": 3000,
    "serverID": "20141201.web.1",
    "message": "Server offline for maintenance.",
    "datetime": "2015-04-23T00:03:32Z",
    "token": "CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE"
}

If the service is offline you should disconnect and retry in 30 minutes.

If you receive a valid token, it must be passed to the server as part of the header for all requests.

In the following examples, where you see Token: Required you must send the token in the header. In POSTman, click "Headers". Set the Header field to "token" (no quotes, lowercase) and the Value field to the token that you retrieved.

Getting status

GET https://json.schedulesdirect.org/20141201/status

Token: Required

Response:

{
    "account": {
        "expires": "2015-06-27T22:16:29Z",
        "messages": [],
        "maxLineups": 255
    },
    "lineups": [
        {
            "lineup": "USA-IL57303-X",
            "modified": "2015-04-11T21:30:27Z",
            "uri": "/20141201/lineups/USA-IL57303-X"
        },
        {
            "lineup": "USA-NY67791-X",
            "modified": "2015-04-17T02:45:44Z",
            "uri": "/20141201/lineups/USA-NY67791-X"
        },
        {
            "ID": "USA-WI61859-DEFAULT",
            "modified": "1970-01-01T00:00:00Z",
            "uri": "/20140530/lineups/USA-WI61859-DEFAULT",
            "isDeleted": true
        }
    ],
    "lastDataUpdate": "2015-04-17T03:36:24Z",
    "notifications": [],
    "systemStatus": [
        {
            "date": "2015-03-23T18:47:00Z",
            "status": "Online",
            "message": "Lineup responses updated. See http://forums.schedulesdirect.org/viewtopic.php?f=17&t=2645&p=8379 for details."
        }
    ],
    "serverID": "20141201.web.1",
    "datetime": "2016-08-23T13:57:34Z",
    "code": 0
}

NOTE: If a lineup has been marked as deleted at the headend, then your code may wish to notify the user.

Determine if the client is the correct version

Your client may make a request and query the server to determine if it is running the latest client.

GET https://json.schedulesdirect.org/20141201/version/{clientname}

Token: Not Required

For example:

GET https://json.schedulesdirect.org/20141201/version/mfdb-json

Response:

{
    "response": "OK",
    "code": 0,
    "client": "mfdb-json",
    "version": "0.11",
    "serverID": "20141201.t2.1",
    "datetime": "2014-09-22T19:11:38Z"
}

Your code could then compare the version in the response with an internal version and then prompt the user with what they'd like to do next.

Error Response:

{
    "response": "UNKNOWN_CLIENT",
    "code": 1005,
    "serverID": "20141201.t2.1",
    "message": "Did not recognize the submitted client.",
    "datetime": "2014-09-22T19:39:52Z"
}

NOTE:Developers, please contact grabber@schedulesdirect.org and provide the clientname string and the version that you'd like the server to reply with.

Obtain the list of available services

The services offered may change; querying the server will allow your client to make informed choices.

Token: Not Required

For example:

GET https://json.schedulesdirect.org/20141201/available

Response:

[
    {
        "type": "COUNTRIES",
        "description": "List of countries which are available.",
        "uri": "/20141201/available/countries"
    },
    {
        "type": "LANGUAGES",
        "description": "List of language digraphs and their language names.",
        "uri": "/20141201/available/languages"
    },
    {
        "type": "DVB-S",
        "description": "List of satellites which are available.",
        "uri": "/20141201/available/dvb-s"
    },
    {
        "type": "DVB-T",
        "description": "List of Freeview transmitters in a country. Country options: GBR",
        "uri": "/20141201/transmitters/{ISO 3166-1 alpha-3}"
    }
]

So for example, to see which countries there is data for, your client would:

GET https://json.schedulesdirect.org/20141201/available/countries

And would then parse the response. You are encouraged to not hardcode the list of countries in your application because the list may change.

{
    "North America": [
        {
            "fullName": "United States",
            "shortName": "USA",
            "postalCodeExample": "12345",
            "postalCode": "/\\d{5}/"
        },
        {
            "fullName": "Canada",
            "shortName": "CAN",
            "postalCodeExample": "K1A0B1",
            "postalCode": "/[A-Z]{1}[\\d]{1}[A-Z]{1}[\\d]{1}[A-Z]{1}[\\d]{1}/gm"
        }
    ],
    "Europe": [
        {
            "fullName": "Austria",
            "shortName": "AUT",
            "postalCodeExample": "6886",
            "postalCode": "/\\d{4}/"
        },
<snip>
"Latin America": [
        {
            "fullName": "Argentina",
            "shortName": "ARG",
            "postalCodeExample": "A4190",
            "postalCode": "/[A-Z]\\d{4}/"
        },
        {
            "fullName": "Belize",
            "shortName": "BLZ",
            "postalCodeExample": "BZ",
            "postalCode": "/BZ/",
            "onePostalCode": true
        },
<snip>

The above example represents a typical response. For Belize, there is only one postal code available - "BZ", and that is what your client would send when performing the next step. The response also indicates an example of a postal code, and a suggested regexp if you would like to check your submission prior to sending it to the server.

Obtaining the list of transmitters rather than postal codes is an alternate means that your client may use, but is dependent on your user's knowing their transmitter.

GET https://json.schedulesdirect.org/20141201/transmitters/GBR

{
    "Aberdare": "GBR-0001213-DEFAULT",
    "Angus": "GBR-0001219-DEFAULT",
    "Beacon Hill": "GBR-0001324-DEFAULT",
    "Belmont": "GBR-0001339-DEFAULT",
    "Bilsdale": "GBR-0001228-DEFAULT",
    "Black Hill": "GBR-0001227-DEFAULT",
    "Blaenplwyf": "GBR-0001213-DEFAULT",
    "Bluebell Hill": "GBR-0001318-DEFAULT",
    "Bressay": "GBR-0001219-DEFAULT",
    "Brierley Hill": "GBR-0001335-DEFAULT",
<snip>

Obtain the list of headends in a postal code

GET https://json.schedulesdirect.org/20141201/headends?country=USA&postalcode=60030

Token: Required

The response will be an array of headends. Note that in CA00053 (and others) that there are multiple lineups in the headend.

Also, please see Automapping Lineups for a means to potentially automatically determine the appropriate lineup.

Response:

[
    {
        "headend": "CA00053",
        "transport": "Cable",
        "location": "Beverly Hills",
        "lineups": [
            {
                "name": "Time Warner Cable - Cable",
                "lineup": "USA-CA00053-DEFAULT",
                "uri": "/20141201/lineups/USA-CA00053-DEFAULT"
            },
            {
                "name": "Time Warner Cable - Digital",
                "lineup": "USA-CA00053-X",
                "uri": "/20141201/lineups/USA-CA00053-X"
            }
        ]
    },
    {
        "headend": "CA61222",
        "transport": "Cable",
        "location": "Beverly Hills",
        "lineups": [
            {
                "name": "Mulholland Estates - Cable",
                "lineup": "USA-CA61222-DEFAULT",
                "uri": "/20141201/lineups/USA-CA61222-DEFAULT"
            }
        ]
    },
    {
        "headend": "CA66511",
        "transport": "Cable",
        "location": "Los Angeles",
        "lineups": [
            {
                "name": "AT&T U-verse TV - Digital",
                "lineup": "USA-CA66511-X",
                "uri": "/20141201/lineups/USA-CA66511-X"
            }
        ]
    },
    {
        "headend": "CA67309",
        "transport": "Cable",
        "location": "Westchester",
        "lineups": [
            {
                "name": "Time Warner Cable Sherman Oaks - Cable",
                "lineup": "USA-CA67309-DEFAULT",
                "uri": "/20141201/lineups/USA-CA67309-DEFAULT"
            },
            {
                "name": "Time Warner Cable Sherman Oaks - Digital",
                "lineup": "USA-CA67309-X",
                "uri": "/20141201/lineups/USA-CA67309-X"
            }
        ]
    },
    {
        "headend": "CA67310",
        "transport": "Cable",
        "location": "Eagle Rock",
        "lineups": [
            {
                "name": "Time Warner Cable City of Los Angeles - Cable",
                "lineup": "USA-CA67310-DEFAULT",
                "uri": "/20141201/lineups/USA-CA67310-DEFAULT"
            },
            {
                "name": "Time Warner Cable City of Los Angeles - Digital",
                "lineup": "USA-CA67310-X",
                "uri": "/20141201/lineups/USA-CA67310-X"
            }
        ]
    },
    {
        "headend": "DISH803",
        "transport": "Satellite",
        "location": "Los Angeles",
        "lineups": [
            {
                "name": "DISH Los Angeles - Satellite",
                "lineup": "USA-DISH803-DEFAULT",
                "uri": "/20141201/lineups/USA-DISH803-DEFAULT"
            }
        ]
    },
    {
        "headend": "DITV803",
        "transport": "Satellite",
        "location": "Los Angeles",
        "lineups": [
            {
                "name": "DIRECTV Los Angeles - Satellite",
                "lineup": "USA-DITV803-DEFAULT",
                "uri": "/20141201/lineups/USA-DITV803-DEFAULT"
            }
        ]
    },
    {
        "headend": "90210",
        "transport": "Antenna",
        "location": "90210",
        "lineups": [
            {
                "name": "Antenna",
                "lineup": "USA-OTA-90210",
                "uri": "/20141201/lineups/USA-OTA-90210"
            }
        ]
    }
]

Add a lineup to a user's Schedules Direct account

Use the lineup field obtained from the GET /headends to add the lineup.

Token: Required

The command follows this format:

PUT /lineups/{COUNTRY}-{LINEUP}-{DEVICE}

So, to add IL57303:X in the United States:

PUT https://json.schedulesdirect.org/20141201/lineups/USA-IL57303-X

Response:

{
    "response": "OK",
    "code": 0,
    "serverID": "AWS-SD-web.1",
    "message": "Added lineup.",
    "changesRemaining": 254,
    "datetime": "2014-05-19T20:16:01Z"
}

Error response:

{
    "response": "INVALID_LINEUP",
    "code": 2105,
    "serverID": "20141201.t2.1",
    "message": "The lineup you submitted doesn't exist.",
    "datetime": "2014-09-20T03:34:25Z"
}

List the lineups a user has added to their account.

Token: Required

GET https://json.schedulesdirect.org/20141201/lineups

Response:

{
    "code": 0,
    "serverID": "20141201.web.1",
    "datetime": "2015-04-17T14:22:17Z",
    "lineups": [
        {
            "lineup": "GBR-0001317-DEFAULT",
            "name": "Freeview - Carlton - LWT (Southeast)",
            "transport": "DVB-T",
            "location": "London",
            "uri": "/20141201/lineups/GBR-0001317-DEFAULT"
        },
        {
            "lineup": "USA-IL57303-X",
            "name": "Comcast Waukegan/Lake Forest Area - Digital",
            "transport": "Cable",
            "location": "Lake Forest",
            "uri": "/20141201/lineups/USA-IL57303-X"
        },
        {
            "lineup": "USA-NY67791-X",
            "name": "Verizon Fios Queens - Digital",
            "transport": "Cable",
            "location": "Fresh Meadows",
            "uri": "/20141201/lineups/USA-NY67791-X"
        },
        {
            "lineup": "USA-OTA-60030",
            "name": "Local Over the Air Broadcast",
            "transport": "Antenna",
            "location": "60030",
            "uri": "/20141201/lineups/USA-OTA-60030"
        },
        {
            "lineup": "USA-WI61859-DEFAULT",
            "name": "DELETED LINEUP",
            "isDeleted": true
        }
    ]
}

NOTE: If a lineup has been marked as deleted at the server, both the status and the subscribed lineups will indicate "isDeleted" as TRUE. Your application should use this to notify the user that their lineup may no longer be valid.

Transport types your client should expect:

  • Antenna - North American ATSC and analog
  • Cable - Requires a set-top-box; typically used in North America
  • DVB-C
  • DVB-S - Freesat
  • DVB-T - Freeview
  • Satellite - Requires a set-top-box; typically used in North America

Delete a lineup from a user's account.

Token: Required

DELETE /lineups/{COUNTRY}-{LINEUP}-{DEVICE}

Example:

DELETE https://json.schedulesdirect.org/20141201/lineups/USA-IL57303-X

Response:

{
    "response": "OK",
    "code": 0,
    "serverID": "AWS-SD-web.1",
    "message": "Deleted lineup.",
    "changesRemaining": "254",
    "datetime": "2014-05-19T20:18:20Z"
}

StationID / channel mapping for a lineup

Token: Required

GET /lineups/{COUNTRY}-{LINEUP}-{DEVICE}

Example:

GET https://json.schedulesdirect.org/20141201/lineups/USA-OTA-90210

Response for an "Antenna" transport type; in this example this lineup is ATSC and contains the uhfVhf channel number and the atscMajor / Minor. A station still transmitting analog would have a uhfVhf, but no Major / Minor.

    "map": [
        {
            "stationID": "19567",
            "uhfVhf": 43,
            "atscMajor": 2,
            "atscMinor": 1
        },
        {
            "stationID": "88571",
            "uhfVhf": 43,
            "atscMajor": 2,
            "atscMinor": 2
        },
        {
            "stationID": "19568",
            "uhfVhf": 36,
            "atscMajor": 4,
            "atscMinor": 1
        },
etc.

Digital transports may contain additional information based on user scans submitted to Schedules Direct. If your application would like the extra data, in the header of the request add "verboseMap" and set it to true.

A non-Verbose map would look like:

{
    "map": [
        {
            "stationID": "24326",
            "channel": "001"
        },
        {
            "stationID": "17154",
            "channel": "002"
        }
    ]
}

A Verbose map would look like this:

{
    "map": [
        {
            "stationID": "24326",
            "channel": "001",
            "providerCallsign": "BBC ONE South",
            "logicalChannelNumber": "1",
            "matchType": "providerCallsign"
        },
        {
            "stationID": "17154",
            "channel": "002",
            "providerCallsign": "BBC TWO",
            "logicalChannelNumber": "2",
            "matchType": "providerCallsign"
        }
    ]
}

If your application requests a Verbose map and one is not available you will get the non-Verbose map.

A DVB transport will contain additional information (if available) regarding the transport, network and service IDs:

A lineup using DVB-T as a transport will contain:

    "map": [
        {
            "stationID": "30644",
            "frequencyHz": 490000000,
            "serviceID": 4164,
            "networkID": 9018,
            "transportID": 4164,
            "channel": "1"
        },
        {
            "stationID": "17154",
            "frequencyHz": 490000000,
            "serviceID": 4287,
            "networkID": 9018,
            "transportID": 4164,
            "channel": "2"
        }

A lineup using DVB-C transport will contain the symbolrate field:

"map": [
{
            "stationID": "76861",
            "frequencyHz": 247500000,
            "deliverySystem": "DVB-C",
            "modulationSystem": "QAM64",
            "symbolrate": 6875,
            "serviceID": 101,
            "networkID": 65024,
            "transportID": 2190,
            "channel": "1"
        },
        {
            "stationID": "87792",
            "frequencyHz": 594000000,
            "deliverySystem": "DVB-C",
            "modulationSystem": "QAM64",
            "symbolrate": 6875,
            "serviceID": 1200,
            "networkID": 65024,
            "transportID": 2000,
            "channel": "2"
        }

A DVB-S will contain satellite-specific tuning:

"map": [
        {
            "stationID": "30455",
            "frequencyHz": 10743000000,
            "polarization": "H",
            "deliverySystem": "DVB-S",
            "modulationSystem": "QPSK",
            "symbolrate": 22000,
            "fec": "5\/6",
            "serviceID": 9612,
            "networkID": 2,
            "transportID": 2043
        },
        {
            "stationID": "48857",
            "frequencyHz": 10743000000,
            "polarization": "H",
            "deliverySystem": "DVB-S",
            "modulationSystem": "QPSK",
            "symbolrate": 22000,
            "fec": "5\/6",
            "serviceID": 9614,
            "networkID": 2,
            "transportID": 2043
        }

In a lineup using DVB-S transport, the channel number is simply an integer with no particular significance. In a -C or -T, the channel number is typically the logical channel number as transmitted. If a DVB lineup does not contain the transport triplet then the Schedules Direct service does not have the information yet.

NOTE: Developers, if there's additional information required for tuning, send email to grabber@schedulesdirect.org so that it can be refined.

A "Satellite" or "Cable" lineup for the will have a map that appear like this:

    "map": [
        {
            "stationID": "74348",
            "channel": "001"
        },
        {
            "stationID": "11299",
            "channel": "002"
        }

The channels are presented as strings for future use; channel "numbers" may include hyphens in a future release.

QAM is handled slightly differently; because providers have multiple ways of presenting a QAM lineup, the map has additional information:

"map": [
        {
            "channel": "55.29",
            "virtualChannel": "55.29",
            "deliverySystem": "ATSC",
            "stationID": "80606",
            "channelMajor": 55,
            "channelMinor": 29,
            "providerCallsign": "FSPLUS",
            "matchType": "providerCallsign"
        },
        {
            "channel": "53.23",
            "virtualChannel": "53.23",
            "deliverySystem": "ATSC",
            "stationID": "10153",
            "channelMajor": 53,
            "channelMinor": 23,
            "providerCallsign": "truTV",
            "matchType": "providerCallsign"
        },

The providerCallsign and matchType fields are hints on how your application can map a raw scan to the data; the providerCallsign is often locally generated by the provider and doesn't match the callsign as defined in the stations array described below.

The other matchType you may see is "channel"; this is used when the providerCallsign is too ambiguous or not provided; you may see the channel as "76-104" for example.

The "channel" field may contain "_", "-" or "." as a separator; your application should normalize the data into whatever is appropriate locally.

After the "map" section comes the station information as an array of stationIDs:

    "stations": [
        {
            "stationID": "19567",
            "name": "KCBSDT (KCBS-DT)",
            "callsign": "KCBSDT",
            "affiliate": "CBS",
            "broadcastLanguage": [
                "en"
            ],
            "descriptionLanguage": [
                "en"
            ],
            "broadcaster": {
                "city": "Studio City",
                "state": "CA",
                "postalcode": "91604",
                "country": "United States"
            },
            "logo": {
                "URL": "https://s3.amazonaws.com/schedulesdirect/assets/stationLogos/s10098_h3_aa.png",
                "height": 270,
                "width": 360,
                "md5": "68713effdd9df195833a56"
            }
        },
        {
            "stationID": "88571",
            "name": "KCBSDT2 (KCBS-DT2)",
            "callsign": "KCBSDT2",
            "affiliate": "CBS",
            "broadcastLanguage": [
                "en"
            ],
            "descriptionLanguage": [
                "en"
            ],
            "broadcaster": {
                "city": "Studio City",
                "state": "CA",
                "postalcode": "91604",
                "country": "United States"
            },
            "logo": {
                "URL": "https://s3.amazonaws.com/schedulesdirect/assets/stationLogos/s10098_h3_aa.png",
                "height": 270,
                "width": 360,
                "md5": "68713effdd9df195833a56"
            }
        },
etc.

If a station is commercial-free, then that will be indicated in the data as the isCommercialFree attribute; the default is "FALSE" and is therefore not included to reduce the size of the data.

NOTE: if you are aware of a commercial-free station and it is not properly tagged in the data then send an email to grabber@schedulesdirect.org

{
            "stationID": "44023",
            "name": "KVCRDT (KVCR-DT)",
            "callsign": "KVCRDT",
            "affiliate": "PBS",
            "broadcastLanguage": "en",
            "descriptionLanguage": "es",
            "broadcaster": {
                "city": "San Bernardino",
                "state": "CA",
                "postalcode": "92401",
                "country": "United States"
            },
            "isCommercialFree": true,
            "logo": {
                "URL": "https://s3.amazonaws.com/schedulesdirect/assets/stationLogos/s11039_h3_aa.png",
                "height": 270,
                "width": 360,
                "md5": "b54e65c3384cc904c90124"
            }
        },

The final piece of information is metadata:

"metadata": {
        "lineup": "USA-OTA-90210",
        "modified": "2015-03-12T18:57:06Z",
        "transport": "Antenna"
    }

Metadata for a QAM lineup has the "modulation" field to differentiate it from a "Cable" lineup:

"metadata": {
        "lineup": "USA-IA14438-QAM",
        "modified": "2015-08-12T17:32:12Z",
        "transport": "Cable",
        "modulation": "QAM"
    }

NOTE: Your code must not assume that the "map" section is first in the data, or that the "metadata" is last.

Automapping a lineup

Automapping may be possible in some situations, but is user-driven. The automapping function accepts the "lineup.json" output from Silicon Dust's HDHomerun devices. It then runs a comparison against our database and returns potential lineup matches.

POST https://json.schedulesdirect.org/20141201/map/lineup/

Token: Required

The body of the request will be the output of:

GET http://ipAddressOfHDHR/lineup.json

If your grabber receives a 404, then the HDHomerun either doesn't support the call, (because it is too old), or the firmware isn't new enough.

If we have a match, the response will be something like:

{"USA-OTA-02116":100}

Indicating a 100% match. Matches above 90% are sent back as candidates.

If there are no match candidates, once your user has gone through the process of manually selecting a lineup by choosing their country, postal code and provider, you're encouraged to submit the lineup.json map with the now-known lineup to our database:

POST https://json.schedulesdirect.org/20141201/map/lineup/USA-OTA-02116

Token: Required

The body of the request will be the output of:

GET http://ipAddressOfHDHR/lineup.json

This may make it easier for the next user that's in the same area as the submitter, because now the database will have a match candidate for them.

Download program information

POST https://json.schedulesdirect.org/20141201/programs

Token: Required

The body of the request will have the programIDs you are requesting.

Your client must send an Accept-Encoding that has "deflate,gzip" in it, even though the response will be gzip'ed. This is due to an implementation bug in 20140530 which will be fixed in 20141201.

NOTE: No more than 5000 programIDs in a single request.

["EP000000060003", "EP000000510142"]

The response will look like:

[
{"programID":"EP000000060003","titles":[{"title120":"'Allo 'Allo!"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"A disguised British Intelligence officer is sent to help the airmen."}]},"originalAirDate":"1985-11-04","genres":["Sitcom"],"episodeTitle150":"The Poloceman Cometh","metadata":[{"Gracenote":{"season":2,"episode":3}}],"cast":[{"personId":"383774","nameId":"392649","name":"Gorden Kaye","role":"Actor","billingOrder":"01"},{"personId":"246840","nameId":"250387","name":"Carmen Silvera","role":"Actor","billingOrder":"02"},{"personId":"376955","nameId":"385830","name":"Rose Hill","role":"Actor","billingOrder":"03"},{"personId":"259773","nameId":"263340","name":"Vicki Michelle","role":"Actor","billingOrder":"04"},{"personId":"353113","nameId":"361987","name":"Kirsten Cooke","role":"Actor","billingOrder":"05"},{"personId":"77787","nameId":"77787","name":"Richard Marner","role":"Actor","billingOrder":"06"},{"personId":"230921","nameId":"234193","name":"Guy Siner","role":"Actor","billingOrder":"07"},{"personId":"374934","nameId":"383809","name":"Kim Hartman","role":"Actor","billingOrder":"08"},{"personId":"369151","nameId":"378026","name":"Richard Gibson","role":"Actor","billingOrder":"09"},{"personId":"343690","nameId":"352564","name":"Arthur Bostrom","role":"Actor","billingOrder":"10"},{"personId":"352557","nameId":"361431","name":"John D. Collins","role":"Actor","billingOrder":"11"},{"personId":"605275","nameId":"627734","name":"Nicholas Frankau","role":"Actor","billingOrder":"12"},{"personId":"373394","nameId":"382269","name":"Jack Haig","role":"Actor","billingOrder":"13"}],"crew":[{"personId":"354407","nameId":"363281","name":"David Croft","role":"Director","billingOrder":"01"},{"personId":"354407","nameId":"363281","name":"David Croft","role":"Writer","billingOrder":"02"},{"personId":"105145","nameId":"105145","name":"Jeremy Lloyd","role":"Writer","billingOrder":"03"}],"showType":"Series","hasImageArtwork":true,"md5":"Jo5NKxoo44xRvBCAq8QT2A"},
{"programID":"EP000000510142","titles":[{"title120":"A Different World"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"Whitley and Dwayne tell new students about their honeymoon in Los Angeles."}]},"originalAirDate":"1992-09-24","genres":["Sitcom"],"episodeTitle150":"Honeymoon in L.A.","metadata":[{"Gracenote":{"season":6,"episode":1}}],"cast":[{"personId":"700","nameId":"700","name":"Jasmine Guy","role":"Actor","billingOrder":"01"},{"personId":"729","nameId":"729","name":"Kadeem Hardison","role":"Actor","billingOrder":"02"},{"personId":"120","nameId":"120","name":"Darryl M. Bell","role":"Actor","billingOrder":"03"},{"personId":"1729","nameId":"1729","name":"Cree Summer","role":"Actor","billingOrder":"04"},{"personId":"217","nameId":"217","name":"Charnele Brown","role":"Actor","billingOrder":"05"},{"personId":"1811","nameId":"1811","name":"Glynn Turman","role":"Actor","billingOrder":"06"},{"personId":"1232","nameId":"1232","name":"Lou Myers","role":"Actor","billingOrder":"07"},{"personId":"1363","nameId":"1363","name":"Jada Pinkett","role":"Guest Star","billingOrder":"08"},{"personId":"222967","nameId":"225536","name":"Ajai Sanders","role":"Guest Star","billingOrder":"09"},{"personId":"181744","nameId":"183292","name":"Karen Malina White","role":"Guest Star","billingOrder":"10"},{"personId":"305017","nameId":"318897","name":"Patrick Y. Malone","role":"Guest Star","billingOrder":"11"},{"personId":"9841","nameId":"9841","name":"Bumper Robinson","role":"Guest Star","billingOrder":"12"},{"personId":"426422","nameId":"435297","name":"Sister Souljah","role":"Guest Star","billingOrder":"13"},{"personId":"25","nameId":"25","name":"Debbie Allen","role":"Guest Star","billingOrder":"14"},{"personId":"668","nameId":"668","name":"Gilbert Gottfried","role":"Guest Star","billingOrder":"15"}],"showType":"Series","hasImageArtwork":true,"md5":"P5kz0QmCeYxIA+yL0H4DWw"}
]

Taking the first response and feeding it into pro.jsonlint.com:

{
    "programID": "EP000000060003",
    "titles": [
        {
            "title120": "'Allo 'Allo!"
        }
    ],
    "eventDetails": {
        "subType": "Series"
    },
    "descriptions": {
        "description1000": [
            {
                "descriptionLanguage": "en",
                "description": "A disguised British Intelligence officer is sent to help the airmen."
            }
        ]
    },
    "originalAirDate": "1985-11-04",
    "genres": [
        "Sitcom"
    ],
    "episodeTitle150": "The Poloceman Cometh",
    "metadata": [
        {
            "Gracenote": {
                "season": 2,
                "episode": 3
            }
        }
    ],
    "cast": [
        {
            "personId": "383774",
            "nameId": "392649",
            "name": "Gorden Kaye",
            "role": "Actor",
            "billingOrder": "01"
        },
        {
            "personId": "246840",
            "nameId": "250387",
            "name": "Carmen Silvera",
            "role": "Actor",
            "billingOrder": "02"
        },
        {
            "personId": "376955",
            "nameId": "385830",
            "name": "Rose Hill",
            "role": "Actor",
            "billingOrder": "03"
        },
        {
            "personId": "259773",
            "nameId": "263340",
            "name": "Vicki Michelle",
            "role": "Actor",
            "billingOrder": "04"
        },
        {
            "personId": "353113",
            "nameId": "361987",
            "name": "Kirsten Cooke",
            "role": "Actor",
            "billingOrder": "05"
        },
        {
            "personId": "77787",
            "nameId": "77787",
            "name": "Richard Marner",
            "role": "Actor",
            "billingOrder": "06"
        },
        {
            "personId": "230921",
            "nameId": "234193",
            "name": "Guy Siner",
            "role": "Actor",
            "billingOrder": "07"
        },
        {
            "personId": "374934",
            "nameId": "383809",
            "name": "Kim Hartman",
            "role": "Actor",
            "billingOrder": "08"
        },
        {
            "personId": "369151",
            "nameId": "378026",
            "name": "Richard Gibson",
            "role": "Actor",
            "billingOrder": "09"
        },
        {
            "personId": "343690",
            "nameId": "352564",
            "name": "Arthur Bostrom",
            "role": "Actor",
            "billingOrder": "10"
        },
        {
            "personId": "352557",
            "nameId": "361431",
            "name": "John D. Collins",
            "role": "Actor",
            "billingOrder": "11"
        },
        {
            "personId": "605275",
            "nameId": "627734",
            "name": "Nicholas Frankau",
            "role": "Actor",
            "billingOrder": "12"
        },
        {
            "personId": "373394",
            "nameId": "382269",
            "name": "Jack Haig",
            "role": "Actor",
            "billingOrder": "13"
        }
    ],
    "crew": [
        {
            "personId": "354407",
            "nameId": "363281",
            "name": "David Croft",
            "role": "Director",
            "billingOrder": "01"
        },
        {
            "personId": "354407",
            "nameId": "363281",
            "name": "David Croft",
            "role": "Writer",
            "billingOrder": "02"
        },
        {
            "personId": "105145",
            "nameId": "105145",
            "name": "Jeremy Lloyd",
            "role": "Writer",
            "billingOrder": "03"
        }
    ],
    "showType": "Series",
    "hasImageArtwork": true,
    "md5": "Jo5NKxoo44xRvBCAq8QT2A"
}

There are two potential error conditions your code may receive as a response; one is temporary and one is permanent. In the following instance the same programID was requested:

    {
        "programID": "EP000000060003",
        "code": 6001,
        "message": "The programID you requested has been queued for generation but is not yet ready for download. Retry."
    }

In this case the programID you requested is valid, but isn't available at the server at the moment and is being generated. Code 6001 indicates a soft failure.

A code 6000 error indicates a permanent failure; if the programID was found in the schedule and you receive a code 6000 error when trying to retrieve it then send email to grabber@schedulesdirect.org.

Your client should maintain a cached copy of the program data; if the MD5 for a programID differs then your client will know that it should re-download the program data.

See Program Response for details on the fields.

See Retrieving Images for information on how your client can retrieve images.

Downloading a generic description of a program

You may want to obtain the generic description of a program; this is only available for "EP" types.

POST https://json.schedulesdirect.org/20141201/metadata/description/

Token: Required

The body of the request must contain the programIDs:

["EP000000060011","EP000186930001"]

Will return:

{
    "SH000000060000": {
        "code": 0,
        "description100": "A cafe owner attempts to repatriate
escapees during World War II.",
        "description1000": "A French cafe owner tries to ride out
World War II. Caught between the Gestapo and the Resistance and forced
into working with both, René also struggles to hide evidence of his
affairs with the waitresses from his wife, who, though she can't carry
a tune, frequently performs as a singer in the cafe."
    },
    "SH000186930000": {
        "code": 0,
        "description100": "Homer and Marge Simpson raise Bart, Lisa
and baby Maggie.",
        "description1000": "This long-running animated comedy focuses
on the eponymous family in the town of Springfield in an unnamed U.S.
state. The head of the Simpson family, Homer, is not a typical family
man. A nuclear-plant employee, he does his best to lead his family but
often finds that they are leading him. The family includes loving,
blue-haired matriarch Marge, troublemaking son Bart, overachieving
daughter Lisa and baby Maggie. Other Springfield residents include the
family's religious neighbor, Ned Flanders, family physician Dr.
Hibbert, Moe the bartender and police chief Clancy Wiggum."
    }
}

The "code" in each response has the following meaning:

  • 0 - no error.
  • 6000 - Invalid programID, don't try again.
  • 6001 - ProgramID is valid but wasn't available on the server. Try again in a few minutes.

You may have up to 500 programIDs in the request.

Your code should send unique requests; sending the same programID multiple times, or incrementing the programID by one episode will always return the same generic description.

Download the schedules for stationIDs

POST https://json.schedulesdirect.org/20141201/schedules

Token: Required

The body of the request must contain stationID elements. If the "date" element isn't included, you will be sent the schedule for "today" through the last day of schedule data on the server.

NOTE: If your code is going to request specific dates, then it should first make the call to Download the MD5 and lastModified for stationIDs This will let your code know what the MD5 is for a schedule for each day that we have data on the server, and will also give you the valid range of dates. If your code is caching the MD5 for each stationID / day combination, it will know whether it has to re-download a schedule.

NOTE: No more than 5000 stationIDs in a single request.

NOTE: The dates are not a range; you must include each date individually.

[
    {
        "stationID": "20454",
        "date": [
            "2015-03-13",
            "2015-03-17"
        ]
    },
    {
        "stationID": "10021",
        "date": [
            "2015-03-12",
            "2015-03-13"
        ]
    }
]

The response will be an array of elements. Each stationID / date combination will contain a metadata element that provides an MD5 value which should be stored so that your code can determine if the schedule for a stationID / date combination needs to be refreshed.

[
    {
        "stationID": "20454",
        "programs": [
            {
                "programID": "SH005371070000",
                "airDateTime": "2015-03-03T00:00:00Z",
                "duration": 1800,
                "md5": "Sy8HEMBPcuiAx3FBukUhKQ",
                "new": true,
                "audioProperties": [
                    "stereo",
                    "cc"
                ],
                "videoProperties": [
                    "hdtv"
                ]
            },
            {
                "programID": "EP000014577244",
                "airDateTime": "2015-03-03T00:30:00Z",
                "duration": 1800,
                "md5": "25DNXVXO192JI7Y9vSW9lQ",
                "new": true,
                "audioProperties": [
                    "stereo",
                    "cc"
                ],
                "videoProperties": [
                    "hdtv"
                ]
            },
(etc for the remaining schedules for this stationID / date combination.)
{
                "programID": "EP014145320829",
                "airDateTime": "2015-03-03T23:30:00Z",
                "duration": 1800,
                "md5": "A6RCPnx4SjKN3oaZtXxNfw",
                "new": true,
                "audioProperties": [
                    "stereo",
                    "cc"
                ],
                "videoProperties": [
                    "hdtv"
                ]
            }
        ],
        "metadata": {
            "modified": "2015-03-02T15:56:02Z",
            "md5": "UtL+hq0sqtCTZVFrGHZ5sg",
            "startDate": "2015-03-03"
        }
    },
    {
        "stationID": "20454",
        "programs": [
            {
                "programID": "SH005371070000",
                "airDateTime": "2015-03-04T00:00:00Z",
                "duration": 1800,
                "md5": "Sy8HEMBPcuiAx3FBukUhKQ",
                "new": true,
                "audioProperties": [
                    "stereo",
                    "cc"
                ],
                "videoProperties": [
                    "hdtv"
                ]
            },
(more schedule elements)
            {
                "programID": "EP014145320830",
                "airDateTime": "2015-03-04T23:30:00Z",
                "duration": 1800,
                "md5": "LdPQVqsQJWTcX1b5k2VPGQ",
                "new": true,
                "audioProperties": [
                    "stereo",
                    "cc"
                ],
                "videoProperties": [
                    "hdtv"
                ]
            }
        ],
        "metadata": {
            "modified": "2015-03-02T15:56:02Z",
            "md5": "ZZPts55w9WUP1rMRvKsGDw",
            "startDate": "2015-03-04"
        }
    },
    {
        "stationID": "10021",
        "programs": [
            {
                "programID": "EP018632100004",
                "airDateTime": "2015-03-03T01:56:00Z",
                "duration": 3840,
                "md5": "J+AOJ/ofAQdp12Bh3U+C+A",
                "audioProperties": [
                    "cc"
                ],
                "ratings": [
                    {
                        "body": "USA Parental Rating",
                        "code": "TV14"
                    }
                ]
            },

Schedule fields

Your program must be able to process UTF-8 characters.

stationID - max 12 characters. Mandatory. This is a string, and your code must not treat it as an integer. Provides information to the grabber regarding the stationID that this schedule is for.

Note: Australian and New Zealand stationIDs will start with "AU" or "NZ".


programs - an array of program data. Mandatory. Must contain at least one element.

Each element of the programs array will contain:

programID - 14 characters. Mandatory. What programID will the data be for.

airDateTime - 20 characters. Mandatory. "2014-10-03T00:00:00Z". This will always be in "Z" time; your grabber must make any adjustments to localtime if it does not natively work in "Z" time internally.

duration - integer. Mandatory. Duration of the program in seconds.

md5 - 22 characters. Mandatory. The MD5 hash value of the JSON data on the server for the programID. If your application has cached the JSON for the program, but the cached MD5 isn't the same as what is in the schedule, that should trigger your grabber to refresh the JSON for the programID because it's changed.

The following program elements are booleans and are optional. If a boolean is not in the schedule, then assume "FALSE". If a boolean is in the schedule, do not assume "TRUE".

  • new - is this showing new?
  • cableInTheClassroom
  • catchup - typically only found outside of North America
  • continued - typically only found outside of North America
  • educational
  • joinedInProgress
  • leftInProgress
  • premiere - Should only be found in Miniseries and Movie program types.
  • programBreak - Program stops and will restart later (frequently followed by a continued). Typically only found outside of North America.
  • repeat - An encore presentation. Repeat should only be found on a second telecast of sporting events.
  • signed - Program has an on-screen person providing sign-language translation.
  • subjectToBlackout
  • timeApproximate
  • free - the program is on a channel which typically has a cost, such as pay-per-view, but in this instance is free.

The following are optional, but can be used to indicate additional information.

  • liveTapeDelay - is this showing Live, or Tape Delayed?. Possible values: "Live", "Tape", "Delay".
  • isPremiereOrFinale - Values are: "Season Premiere", "Season Finale", "Series Premiere", "Series Finale", "Premiere", "Finale"
  • ratings - an array of ratings values.
    • body: what classification body is providing the rating?
    • code: what rating was assigned?

Example:

"ratings": [
                {
                    "body": "USA Parental Rating",
                    "code": "TVPG"
                }
            ]

Programs may be rated by various bodies, so your code should iterate through the bodies and use the one appropriate for your locale.

NOTE: In the next version of the API, the ratings element will be removed from the schedule entity; there is a "contentRating" field associated with the program which should be used instead.

  • multipart - indicates whether the program is one of a series.
"multipart": {
                "partNumber": 1,
                "totalParts": 3
            }

audioProperties - optional. An array of audio properties.

  • Atmos - Dolby Atmos
  • cc - Closed Captioned
  • DD
  • DD 5.1
  • Dolby
  • dubbed
  • dvs - Descriptive Video Service
  • SAP - Secondary Audio Program
  • stereo
  • subtitled
  • surround

videoProperties - optional. An array of video properties.

  • 3d - is this showing in 3d
  • enhanced - Enhanced is better video quality than Standard Definition, but not true High Definition. (720p / 1080i)
  • hdtv - the content is in High Definition
  • letterbox
  • sdtv
  • uhdtv - the content is in "UHDTV"; this is provider-dependent and does not imply any particular resolution or encoding

The following metadata is associated with the schedule (it is not inside the programs array)

  • modified - 20 characters. Mandatory. Follows strftime() format; "Y-m-d\TH:i:s\Z" The timestamp for the creation time of this schedule on the server.
  • md5 - 22 characters. Mandatory. What is the MD5 for this schedule (stationID and programs elements) - metadata is not included in the MD5 calculation.
  • startDate - the start date of the JSON schedule. Mandatory. strftime() "Y-m-d" format.
  • code - optional. Indicates if there were errors with the station. It is possible that your client has requested a stationID which has been deleted upstream, but that your client still believes is "live" because it hasn't updated the lineup.

Errors

You may receive the following as a response element:

[
    {
        "stationID": "10489",
        "serverID": "20141201.web.1",
        "code": 2201,
        "response": "STATIONID_DELETED",
        "programs": [],
        "metadata": {
            "code": 2201,
            "modified": "1970-01-01",
            "md5": "CAFEDEADBEEFCAFEDEADBE",
            "isDeleted": true
        }
    }
]

This occurs if the lineup has not yet been updated to reflect that a stationID has been deleted, so requesting data for the stationID will result in an error. This may also occur if the lineup has been updated on the server side, but the client hasn't downloaded an updated lineup map.

{
    "response": "SCHEDULE_QUEUED",
    "code": 7100,
    "serverID": "20141201.1",
    "message": "The schedule you requested has been queued for generation but is not yet ready for download. Retry.",
    "datetime": "2014-12-04T20:38:15Z",
    "stationID": "50475",
    "retryTime": "2014-12-04T20:48:15Z"
}

The server creates schedules just-in-time based on user requests and channels which are active. If you receive the above response, your code should honor the "retryTime" parameter and wait at least this long before retrying to download the schedule. This will give the backend system enough time to generate the schedule for you.

[
    {
        "stationID": "92371",
        "serverID": "20141201.web.1",
        "code": 7020,
        "response": "SCHEDULE_RANGE_EXCEEDED",
        "minDate": "2015-06-21",
        "maxDate": "2015-07-12",
        "requestedDate": "2015-07-20",
        "message": "Date requested (2015-07-20) not within 2015-06-21 -> 2015-07-12 for stationID 92371."
    }
]

Error 7020 occurs when the requested date is out of range of what's on the server. If your code uses the MD5 function as decribed in the next section it will know what the min / max dates are prior to requesting the schedule.

Download the MD5 and lastModified for stationIDs

POST https://json.schedulesdirect.org/20141201/schedules/md5

Token: Required

The body of the request will have the stationIDs that you are requesting, with an optional "date" element to request specific dates for this stationID. If you do not include a "date" element the server will send the MD5 for "today" through the furthest date we have information for.

This function is useful to determine whether a particular stationID has an updated schedule; schedules are typically updated 4 times per day, 7 days per week. If a schedule has been updated, the MD5 and lastModified for that stationID for that date will be updated. Using this function, your client can determine (through use of a local cache) if it needs to download a new schedule.

NOTE: No more than 5000 stationIDs in a single request.

NOTE: The dates are not a range; you must include each date individually.

[
    {
        "stationID": "10021"
    },
    {
        "stationID": "31590",
        "date": [
            "2015-03-12",
            "2015-03-17"
        ]
    }
]

Days more than one day in the past (referencing to midnight, Zulu time) are invalid.

The response will look like this:

{
    "10021": {
        "2015-03-02": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "90OhzuWDRZ/3pDA8kiD/3Q"
        },
        "2015-03-03": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "SpVOfFY4a8gQrrZjOqyK8g"
        },
        "2015-03-04": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "M28yUIqJyWKYK678cXf0yg"
        },
        "2015-03-05": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "va+LAHqHRthUCIvHyYWvmQ"
        },
        "2015-03-06": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "Vh+/n50xOs9beZwYttNmkg"
        },
        "2015-03-07": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "Zkwk4WR/OdZRJW7VxFmpIg"
        },
        "2015-03-08": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "E71/Hhn7g9hjm9C62ZRu/w"
        },
        "2015-03-09": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:58Z",
            "md5": "57bRSvsGzlcOABs6L4+rJg"
        },
        "2015-03-10": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "fSxdu0nSh9sjxSIeaxke9Q"
        },
        "2015-03-11": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "7RIUvb4lOYnH+sLR2AbZNw"
        },
        "2015-03-12": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "GtQa6tTyXbV766VIjtbPig"
        },
        "2015-03-13": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "loNYYtTiRSEGV4Go9MdwGQ"
        },
        "2015-03-14": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "60eiM0FxIIWHuEHIVrPTcQ"
        },
        "2015-03-15": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "scsW02JiUimh2c9tFJxcZA"
        },
        "2015-03-16": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "IW54d8U3T3NoP2qVXRqlNg"
        },
        "2015-03-17": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "oBn5rCpJHnL+VZ4IAzc1XQ"
        },
        "2015-03-18": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "E3Rg8FDt0U8skbUEtwFh2A"
        },
        "2015-03-19": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "K8oSxRaIgeNLc8SZetzwpQ"
        },
        "2015-03-20": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "CcK6uEz2WCkpLQnMP0Wl0w"
        },
        "2015-03-21": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "tmEF/TxAjJ1maNBx93nitA"
        },
        "2015-03-22": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "jShohWNfMZDiDp8DmrlroQ"
        },
        "2015-03-23": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:54:59Z",
            "md5": "sFF9EE8hJYDzSgUZA0tycQ"
        }
    },
    "31590": {
        "2015-03-02": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:56:17Z",
            "md5": "cuq9QUJZRygLx21821qlUw"
        },
        "2015-03-03": {
            "code": 0,
            "message": "OK",
            "lastModified": "2015-03-02T15:56:17Z",
            "md5": "ZDPKmNdzvnCF5EzY855cLQ"
        }
    }
}

(etc for all stationIDs requested)

Delete a system message

DELETE /messages/{messageID}

Deletes non-system status messages from the status response.

Downloading "in progress" for sporting events.

Schedules Direct can provide information about sporting events which may be used by an application to extend the recording of a program which is running long due to a tie score or delay, or to stop a recording which the user has configured with a fixed over-run time.

As of 2015-11-28, we provide responses for: NFL, NHL, NBA and MLB.

NOTE: a sporting event which runs late will not cause a schedule re-generation, because we won't know if the broadcaster is going to shift the starting time for subsequent programs, or just "joined in progress".

NOTE: the "isComplete" flag indicates that the event is over; broadcasters may choose to have post-game analysis, so your client must take that into consideration.

The URL accepts a single programID that you're interested in.

GET https://json.schedulesdirect.org/20141201/metadata/stillRunning/{programID}

Token: Required

If you are requesting a valid program, but are the first client to request this programID, the response will be:

{
    "response": "PROGRAMID_QUEUED",
    "code": 6001,
    "serverID": "20141201.web.2",
    "message": "The programID you requested has been queued for generation but is not yet ready for download. Retry.",
    "datetime": "2015-11-27T03:21:02Z",
    "programID": "SP003190180000"
}

Your client should wait 30 seconds before retrying.

For a program which is still in progress, "isComplete" will be "false":

{
    "code": 0,
    "message": "OK",
    "programID": "SP003190180000",
    "response": "OK",
    "isComplete": false,
    "serverID": "Test1",
    "datetime": "2015-11-27T02:48:40Z",
    "result": {
        "homeTeam": {
            "name": "Green Bay",
            "score": "10"
        },
        "awayTeam": {
            "name": "Chicago",
            "score": "7"
        }
    }
}

For a program which is over, "isComplete" will be "true":

{
    "code": 0,
    "message": "OK",
    "programID": "SP003190160000",
    "response": "OK",
    "isComplete": true,
    "serverID": "Test1",
    "datetime": "2015-11-27T01:39:28Z",
    "result": {
        "homeTeam": {
            "name": "Detroit",
            "score": "45"
        },
        "awayTeam": {
            "name": "Philadelphia",
            "score": "14"
        }
    }
}

If you request a program which is valid, but is still in the future, you will get:

{
    "response": "FUTURE_PROGRAM",
    "code": 6002,
    "serverID": "20141201.web.2",
    "message": "The programID you requested has not occurred yet, so isComplete status is unknown.",
    "datetime": "2015-11-27T03:08:57Z",
    "programID": "SP003264810000",
    "eventStartDateTime": "2015-11-29T20:00Z"
}

If you request an invalid program, or a sport which we do not track, you will receive:

{
    "response": "INVALID_PROGRAMID",
    "code": 6000,
    "serverID": "20141201.web.2",
    "message": "Could not find requested programID.",
    "datetime": "2015-11-27T03:13:30Z"
}

Download graphics, channel logos, banners

Images, fanart, logos, etc will have a URI in the JSON response. If the URI is complete, it will point to Amazon S3, in which case your application should pull the image directly from Amazon. If the URI is incomplete (no http:// for example), then send the request to Schedules Direct. Your application will then receive a 303 redirect.

There is a number of metadata elements which are available to the client.

If the program contains a boolean called "hasImageArtwork" and it is TRUE, this means that this particular program has artwork available, such as DVD coverart, stills from the program, title cards, etc.

{
    "programID": "EP003851900001",
    "titles": [
        {
            "title120": "Gilmore Girls"
        }
    ],
    "descriptions": {
        "description100": [
            {
                "descriptionLanguage": "en",
                "description": "A woman (Lauren Graham) endeavors to raise a daughter (Alexis Bledel) on her own."
            }
        ],
        "description1000": [
            {
                "descriptionLanguage": "en",
                "description": "Lorelai must ask her estranged parents for financial help when her daughter, Rory, is accepted into a prestigious prep school."
            }
        ]
    },
    "originalAirDate": "2000-10-05",
    "genres": [
        "Drama",
        "Comedy"
    ],
    "episodeTitle150": "Pilot",
    "metadata": [
        {
            "Gracenote": {
                "season": 1,
                "episode": 1
            }
        }
    ],
    "contentRating": [
        {
            "body": "Departamento de Justiça, Classificação, Títulos e Qualificação",
            "code": "L"
        },
        {
            "body": "USA Parental Rating",
            "code": "TVPG"
        }
    ],
    "cast": [
        {
            "billingOrder": "01",
            "role": "Actor",
            "nameId": "68293",
            "personId": "68293",
            "name": "Lauren Graham"
        },
        {
            "billingOrder": "02",
            "role": "Actor",
            "nameId": "183495",
            "personId": "181941",
            "name": "Alexis Bledel"
        },
<snip>
        {
            "billingOrder": "09",
            "role": "Actor",
            "nameId": "39938",
            "personId": "39938",
            "name": "Liz Torres"
        }
    ],
    "crew": [
        {
            "billingOrder": "01",
            "role": "Executive Producer",
            "nameId": "191244",
            "personId": "189517",
            "name": "Amy Sherman-Palladino"
        },
        {
            "billingOrder": "02",
            "role": "Executive Producer",
            "nameId": "253033",
            "personId": "249480",
            "name": "Gavin Polone"
        },
        {
            "billingOrder": "03",
            "role": "Director",
            "nameId": "78100",
            "personId": "78100",
            "name": "Lesli Linka Glatter"
        },
        {
            "billingOrder": "04",
            "role": "Writer",
            "nameId": "191244",
            "personId": "189517",
            "name": "Amy Sherman-Palladino"
        }
    ],
    "showType": "Series",
    "hasImageArtwork": true,
    "md5": "hVdDQ1wTUCel5CY6BhLKqw"
}

Retrieving JSON index based on programID

The available image artwork index is retrieved by using the following URL:

POST https://json.schedulesdirect.org/20141201/metadata/programs/

Token: Not Required

The body of the message should contain the leftmost 10 characters of the programID:

["SH00712240", "EP00385190"]

Which will return an index of what content is available:

[
    {
        "programID": "SH00712240",
        "data": [
            {
                "width": "135",
                "height": "180",
                "uri": "assets/p282288_b_v2_aa.jpg",
                "size": "Sm",
                "aspect": "3x4",
                "category": "Banner-L3",
                "text": "yes",
                "primary": "true",
                "tier": "Series"
            },
            {
                "width": "720",
                "height": "540",
                "uri": "assets/p282288_b_h6_aa.jpg",
                "size": "Lg",
                "aspect": "4x3",
                "category": "Banner-L3",
                "text": "yes",
                "primary": "true",
                "tier": "Series"
            },
            {
                "width": "960",
                "height": "1440",
                "uri": "assets/p282288_b_v8_aa.jpg",
                "size": "Ms",
                "aspect": "2x3",
                "category": "Banner-L3",
                "text": "yes",
                "primary": "true",
                "tier": "Series"
            },
<snip>
            {
                "width": "180",
                "height": "135",
                "uri": "assets/p282288_b_h5_aa.jpg",
                "size": "Sm",
                "aspect": "4x3",
                "category": "Banner-L3",
                "text": "yes",
                "primary": "true",
                "tier": "Series"
            }
        ]
    },
    {
        "programID": "EP00385190",
        "data": [
            {
                "width": "540",
                "height": "720",
                "caption": {
                    "content": "Alexis Bledel as Rory Gilmore",
                    "lang": "en"
                },
                "uri": "assets/p184655_n183495_cc_v4_aa.jpg",
                "size": "Lg",
                "aspect": "3x4",
                "category": "Cast in Character",
                "text": "no",
                "primary": "true",
                "tier": "Series"
            },
<etc>

You may batch up to 500 elements in each request.

Retrieving JSON index based on rootId

The returned JSON may contain a "rootId". If it does, you may obtain information using:

https://json.schedulesdirect.org/20141201/metadata/programs/{rootId}

GET https://json.schedulesdirect.org/20141201/metadata/programs/33125

Token: Not Required

Which returns:

[
    {
        "uri": "movies/AllPhotos/35605/35605_aa.jpg",
        "height": "432",
        "width": "288",
        "primary": "true",
        "category": "Poster Art",
        "caption": {
            "content": "Poster Art",
            "lang": "en"
        }
    },
    {
        "uri": "movies/AllPhotos/35605/35605_aa_t.jpg",
        "height": "108",
        "width": "72",
        "primary": "true",
        "category": "Poster Art",
        "caption": {
            "content": "Poster Art",
            "lang": "en"
        }
    },
    {
        "uri": "assets/35605_ab.jpg",
        "height": "288",
        "width": "432",
        "category": "Scene Still",
        "caption": {
            "content": "Billy Bob Thornton and Tony Cox in Terry Zwigoff's BAD SANTA.",
            "lang": "en"
        }
    },
        <snip>

Retrieving an image

To retrieve a particular image, use the URI from the JSON index.

https://json.schedulesdirect.org/20141201/image/{uri}

So:

GET https://json.schedulesdirect.org/20141201/image/assets/p184655_b_h3_aa.jpg

This will send your client a 303 redirect which it must follow in order to retrieve the actual image:

https://s3.amazonaws.com/schedulesdirect/assets/p184655_b_h3_aa.jpg

NOTE: If the URI is already "complete" and contains the S3 URL, then your client should access S3 directly. Notice the difference in the uri in the following example:

{
        "width": "360",
        "height": "270",
        "uri": "assets/p10779614_l_h3_aa.jpg",
        "size": "Md",
        "aspect": "4x3",
        "category": "Logo",
        "text": "no",
        "primary": "true",
        "tier": "Series"
    },
    {
        "width": "180",
        "height": "135",
        "uri": "https://s3.amazonaws.com/schedulesdirect/assets/p10779614_l_h5_aa.jpg",
        "size": "Sm",
        "aspect": "4x3",
        "category": "Logo",
        "text": "no",
        "primary": "true",
        "tier": "Series"
    },

Retrieving images for a particular celebrity

The program object also contains nameId and personId elements in the cast and crew section. The actor Lauren Graham has a nameId of 68293, so

GET https://json.schedulesdirect.org/20141201/metadata/celebrity/68293

Token: Not Required

Returns

[
    {
        "uri": "assets/35605_aq.jpg",
        "height": "288",
        "width": "432",
        "category": "Scene Still",
        "caption": {
            "content": "Billy Bob Thornton and Lauren Graham in Terry Zwigoff's BAD SANTA.",
            "lang": "en"
        },
        "rootId": "33125",
        "title": "Bad Santa"
    },

        <snip>

    }

Your grabber may use the same /image/ call with the URI to retrieve that image:

https://json.schedulesdirect.org/20141201/image/{uri}

https://json.schedulesdirect.org/20141201/image/assets/35605_aq.jpg

Field meanings

There are various fields in the JSON response.

  • Banner – source-provided image, usually shows cast ensemble with source-provided text
  • Banner-L1 - same as Banner
  • Banner-L2 - source-provided image with plain text
  • Banner-L3 - stock photo image with plain text
  • Banner-LO - banner with Logo Only
  • Banner-LOT - banner with Logo Only + Text indicating season number
  • Iconic - representative series/season/episode image, no text
  • Staple - the staple image is intended to cover programs which do not have a unique banner image.
  • Cast Ensemble - cast ensemble, no text
  • Cast in Character - individual cast member, no text
  • Logo - official logo for program, sports organization, sports conference, or TV station
  • Box Art - DVD box art, for movies only
  • Poster Art – theatrical movie poster, standard sizes
  • Scene Still – movie photos, legacy sizes
  • Photo - same as Scene Still
  • Photo-headshot - celebrity image

Error Codes

The system may respond to a request and send back an error code.

Response Internal Code Error
0 OK OK
1001 INVALID_JSON Unable to decode JSON
1002 DEFLATE_REQUIRED Did not receive Accept-Encoding: deflate in request.
1004 TOKEN_MISSING Token required but not provided in request header.
2000 UNSUPPORTED_COMMAND Unsupported command
2001 REQUIRED_ACTION_MISSING Request is missing an action to take.
2002 REQUIRED_REQUEST_MISSING Did not receive request.
2004 REQUIRED_PARAMETER_MISSING:COUNTRY In order to search for lineups, you must supply a 3-letter country parameter.
2005 REQUIRED_PARAMETER_MISSING:POSTALCODE In order to search for lineups, you must supply a postal code parameter.
2006 REQUIRED_PARAMETER_MISSING:MSGID In order to delete a message you must supply the messageID.
2050 INVALID_PARAMETER:COUNTRY The COUNTRY parameter must be ISO-3166-1 alpha 3. See http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
2051 INVALID_PARAMETER:POSTALCODE The POSTALCODE parameter must be valid for the country you are searching. Post message to http://forums.schedulesdirect.org/viewforum.php?f=6 if you are having issues.
2052 INVALID_PARAMETER:FETCHTYPE You didn't provide a fetchtype I know how to handle.
2100 DUPLICATE_LINEUP Lineup already in account.
2101 LINEUP_NOT_FOUND Lineup not in account. Add lineup to account before requesting mapping.
2102 UNKNOWN_LINEUP Invalid lineup requested. Check your COUNTRY / POSTALCODE combination for validity.
2103 INVALID_LINEUP_DELETE Delete of lineup not in account.
2104 LINEUP_WRONG_FORMAT Lineup must be formatted COUNTRY-LINEUP-DEVICE or COUNTRY-OTA-POSTALCODE
2105 INVALID_LINEUP The lineup you submitted doesn't exist.
2106 LINEUP_DELETED The lineup you requested has been deleted from the server.
2107 LINEUP_QUEUED The lineup is being generated on the server. Please retry.
2108 INVALID_COUNTRY The country you requested is either mis-typed or does not have valid data.
2200 STATIONID_NOT_FOUND The stationID you requested is not in any of your lineups.
3000 SERVICE_OFFLINE Server offline for maintenance.
4001 ACCOUNT_EXPIRED Account expired.
4002 INVALID_HASH Password hash must be lowercase 40 character sha1_hex of password.
4003 INVALID_USER Invalid username or password.
4004 ACCOUNT_LOCKOUT Too many login failures. Locked for 15 minutes.
4005 ACCOUNT_DISABLED Account has been disabled. Please contact Schedules Direct support: admin@schedulesdirect.org for more information.
4006 TOKEN_EXPIRED Token has expired. Request new token.
4100 MAX_LINEUP_CHANGES_REACHED Exceeded maximum number of lineup changes for today.
4101 MAX_LINEUPS Exceeded number of lineups for this account.
4102 NO_LINEUPS No lineups have been added to this account.
5000 IMAGE_NOT_FOUND Could not find requested image. Post message to http://forums.schedulesdirect.org/viewforum.php?f=6 if you are having issues.
6000 INVALID_PROGRAMID Could not find requested programID. Permanent failure.
6001 PROGRAMID_QUEUED ProgramID should exist at the server, but doesn't. The server will regenerate the JSON for the program, so your application should retry.
7000 SCHEDULE_NOT_FOUND The schedule you requested should be available. Post message to http://forums.schedulesdirect.org/viewforum.php?f=6
7010 INVALID_SCHEDULE_REQUEST The server can't determine whether your schedule is valid or not. Open a support ticket.
7020 SCHEDULE_RANGE_EXCEEDED The date that you've requested is outside of the range of the data for that stationID.
7030 SCHEDULE_NOT_IN_LINEUP You have requested a schedule which is not in any of your configured lineups.
7100 SCHEDULE_QUEUED The schedule you requested has been queued for generation but is not yet ready for download. Retry.
9999 HCF Unknown error. Open support ticket.