API 20131021
This API has been deprecated. Please see https://github.com/SchedulesDirect/JSON-Service/wiki
for the current version.
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.
This page describes API version 20131021.
In this document, references to "baseurl" mean "https://json.schedulesdirect.org/20131021/"
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.
A headend may contain multiple lineups, and a lineup is a specific mapping of channels and stationIDs.
You may have an analog lineup, meaning the channels that you can tune using an analog tuner. In a cable lineup, this would be channels "2" through "125". In the data, these are typically called "DEFAULT".
You may have a digital lineup; one that requires an external set-top-box. 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".
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.
This is the first thing your client must do; almost all commands require a token in the header.
POST https://json.schedulesdirect.org/20131021/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",
"token": "f3fca79989cafe7dead71beefedc812b"
}
TODO: include error responses.
The "token" 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.
GET https://json.schedulesdirect.org/20131021/status
Token: Required
Response:
{
"account": {
"expires": "2014-06-28T05:16:29Z",
"messages": [],
"maxLineups": 16,
"nextSuggestedConnectTime": "2014-05-20T16:32:12Z"
},
"lineups": [
{
"ID": "USA-OTA-60030",
"modified": "2014-05-17T15:47:42Z",
"uri": "/20131021/lineups/USA-OTA-60030"
},
{
"ID": "USA-OTA-60654",
"modified": "2014-05-15T17:41:11Z",
"uri": "/20131021/lineups/USA-OTA-60654"
},
{
"ID": "USA-PA37765-QAM",
"modified": "2014-05-06T14:50:02Z",
"uri": "/20131021/lineups/USA-PA37765-QAM"
}
],
"lastDataUpdate": "2014-05-19T14:44:34Z",
"notifications": [],
"systemStatus": [
{
"date": "2012-12-17T16:24:47Z",
"status": "Online",
"details": "All servers running normally."
}
],
"serverID": "AWS-SD-web.1",
"code": 0
}
###Obtain the list of headends in a postal code
GET https://json.schedulesdirect.org/20131021/headends?country=USA&postalcode=60030
Token: Required
Response:
{
"60030": {
"type": "Over-the-Air",
"location": "60030",
"lineups": [
{
"name": "Antenna",
"uri": "/20131021/lineups/USA-OTA-60030"
}
]
},
"4DTV": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "4DTV",
"uri": "/20131021/lineups/USA-4DTV-DEFAULT"
}
]
},
"AFN": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "AFN Satellite",
"uri": "/20131021/lineups/USA-AFN-DEFAULT"
}
]
},
"C-BAND": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "C-Band",
"uri": "/20131021/lineup/USA-C-BAND-DEFAULT"
}
]
},
"DISH602": {
"type": "Satellite",
"location": "Chicago",
"lineups": [
{
"name": "DISH Chicago",
"uri": "/20131021/lineups/USA-DISH602-DEFAULT"
}
]
},
"DITV": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "DIRECTV",
"uri": "/20131021/lineups/USA-DITV-DEFAULT"
}
]
},
"DITV602": {
"type": "Satellite",
"location": "Chicago",
"lineups": [
{
"name": "DIRECTV Chicago",
"uri": "/20131021/lineups/USA-DITV602-DEFAULT"
}
]
},
"ECHOST": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "DISH Network",
"uri": "/20131021/lineups/USA-ECHOST-DEFAULT"
}
]
},
"GLOBCST": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "Globecast World TV",
"uri": "/20131021/lineups/USA-GLOBCST-DEFAULT"
}
]
},
"GLRYSTR": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "GLRYSTR",
"uri": "/20131021/lineups/USA-GLRYSTR-DEFAULT"
}
]
},
"IL57303": {
"type": "Cable",
"location": "Lake Forest",
"lineups": [
{
"name": "Comcast Waukegan/Lake Forest Area - Digital",
"uri": "/20131021/lineups/USA-IL57303-X"
}
]
},
"IL61078": {
"type": "Cable",
"location": "Grayslake",
"lineups": [
{
"name": "Saddlebrook Farms - Cable",
"uri": "/20131021/lineups/USA-IL61078-DEFAULT"
}
]
},
"IL63063": {
"type": "Cable",
"location": "Mchenry",
"lineups": [
{
"name": "Comcast McHenry & Fox Areas - Digital",
"uri": "/20131021/lineups/USA-IL63063-X"
}
]
},
"IL63463": {
"type": "Cable",
"location": "Carpentersville",
"lineups": [
{
"name": "Comcast Algonquin/Elgin Areas - Digital",
"uri": "/20131021/lineups/USA-IL63463-X"
}
]
},
"IL67050": {
"type": "Cable",
"location": "Chicago",
"lineups": [
{
"name": "AT&T U-verse TV - Digital",
"uri": "/20131021/lineups/USA-IL67050-X"
}
]
},
"RELAYTV": {
"type": "Satellite",
"location": "USA",
"lineups": [
{
"name": "RELAYTV",
"uri": "/20131021/lineups/USA-RELAYTV-DEFAULT"
}
]
}
}
Add a lineup to a user's account. Use the lineup names obtained from the GET /headends that are appropriate for your postal code.
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/20131021/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"
}
###List the lineups a user has added to their account.
Token: Required
GET https://json.schedulesdirect.org/20131021/lineups
Response:
{
"serverID": "AWS-SD-web.1",
"datetime": "2014-05-19T20:14:23Z",
"lineups": [
{
"name": "Local",
"type": "Antenna",
"location": "60030",
"uri": "/20131021/lineups/USA-OTA-60030"
},
{
"name": "Local",
"type": "Antenna",
"location": "60654",
"uri": "/20131021/lineups/USA-OTA-60654"
},
{
"name": "Local",
"type": "QAM",
"location": "60654",
"uri": "/20131021/lineups/USA-PA37765-QAM"
}
]
}
Token: Required
DELETE /lineups/{COUNTRY}-{LINEUP}-{DEVICE}
Example:
DELETE https://json.schedulesdirect.org/20131021/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"
}
Token: Required
GET /lineups/{COUNTRY}-{LINEUP}-{DEVICE}
Example:
GET https://json.schedulesdirect.org/20131021/lineups/USA-IL57303-X
Response:
{
"map": [
{
"stationID": "74348",
"channel": "001"
},
{
"stationID": "11299",
"channel": "002"
},
{
"stationID": "12475",
"channel": "003"
},
{
"stationID": "11848",
"channel": "004"
},
{
"stationID": "11670",
"channel": "005"
},
{
"stationID": "11461",
"channel": "006"
},
{
"stationID": "11653",
"channel": "007"
},
etc.
POST https://json.schedulesdirect.org/20131021/programs
Token: Required
The body of the request will have the programIDs you are requesting.
{"request":["SH015157750000", "EP000042172058"]}
The response will look like:
{"programID":"SH015157750000","titles":{"title120":"Help in Daily Living"},"eventDetails":{"subType":"Series"},"originalAirDate":"2012-01-01","genres":["Religious"],"showType":"Series","md5":"d7CrQrtdSALdksAr9YDaHQ"}
{"programID":"EP000042172058","titles":{"title120":"The Bold and the Beautiful"},"eventDetails":{"subType":"Series"},"originalAirDate":"2014-05-28","genres":["Soap"],"images":[{"uri":"https:\/\/s3.amazonaws.com\/schedulesdirect-API20131021\/assets\/p183907_b_v5_ac.jpg","dimension":"w=240px|h=360px","md5":"2a46b9984f91bc5531136c"}],"cast":[{"personId":"33184","nameId":"33184","name":"John McCook","role":"Actor","billingOrder":"01"},{"personId":"60861","nameId":"60861","name":"Susan Flannery","role":"Actor","billingOrder":"02"},{"personId":"56539","nameId":"56539","name":"Ronn Moss","role":"Actor","billingOrder":"03"},{"personId":"35962","nameId":"35962","name":"Katherine Kelly Lang","role":"Actor","billingOrder":"04"},{"personId":"1859","nameId":"1859","name":"Jack Wagner","role":"Actor","billingOrder":"05"},{"personId":"314870","nameId":"322751","name":"Texas Battle","role":"Actor","billingOrder":"06"},{"personId":"258308","nameId":"261872","name":"Brandon Beemer","role":"Actor","billingOrder":"07"},{"personId":"199845","nameId":"683742","name":"Sarah Joy Brown","role":"Actor","billingOrder":"08"},{"personId":"314743","nameId":"322612","name":"Scott Clifton","role":"Actor","billingOrder":"09"},{"personId":"581436","nameId":"606454","name":"Zack Conroy","role":"Actor","billingOrder":"10"},{"personId":"86347","nameId":"86347","name":"Don Diamont","role":"Actor","billingOrder":"11"},{"personId":"38997","nameId":"38997","name":"Lesley-Anne Down","role":"Actor","billingOrder":"12"},{"personId":"467","nameId":"467","name":"Patrick Duffy","role":"Actor","billingOrder":"13"},{"personId":"201420","nameId":"203327","name":"Adrienne Frantz","role":"Actor","billingOrder":"14"},{"personId":"207731","nameId":"209765","name":"Jennifer Gareis","role":"Actor","billingOrder":"15"},{"personId":"154046","nameId":"158401","name":"Rick Hearst","role":"Actor","billingOrder":"16"},{"personId":"209275","nameId":"211473","name":"Ashley Jones","role":"Actor","billingOrder":"17"},{"personId":"219518","nameId":"221932","name":"Kyle Lowder","role":"Actor","billingOrder":"18"},{"personId":"520723","nameId":"539170","name":"Jacqueline MacInnes Wood","role":"Actor","billingOrder":"19"},{"personId":"513765","nameId":"529540","name":"Kimberly Matula","role":"Actor","billingOrder":"20"},{"personId":"78173","nameId":"78173","name":"Alley Mills","role":"Actor","billingOrder":"21"},{"personId":"26015","nameId":"26015","name":"Heather Tom","role":"Actor","billingOrder":"22"},{"personId":"67534","nameId":"67534","name":"Hunter Tylo","role":"Actor","billingOrder":"23"},{"personId":"160503","nameId":"161114","name":"Courtnee Draper","role":"Actor","billingOrder":"24"},{"personId":"158217","nameId":"158546","name":"Schae Harrison","role":"Actor","billingOrder":"25"},{"personId":"657589","nameId":"683757","name":"Adam Gregory","role":"Actor","billingOrder":"26"},{"personId":"605072","nameId":"627584","name":"Kristolyn Lloyd","role":"Actor","billingOrder":"27"},{"personId":"1106","nameId":"1106","name":"A Martinez","role":"Actor","billingOrder":"28"},{"personId":"67625","nameId":"67625","name":"Andrea Evans","role":"Actor","billingOrder":"29"},{"personId":"152236","nameId":"152366","name":"Sean Whalen","role":"Actor","billingOrder":"30"},{"personId":"521001","nameId":"539609","name":"Lawrence Saint-Victor","role":"Actor","billingOrder":"31"},{"personId":"67555","nameId":"67555","name":"Thorsten Kaye","role":"Actor","billingOrder":"32"}],"crew":[{"personId":"264987","nameId":"268563","name":"Bradley Bell","role":"Producer","billingOrder":"01"}],"showType":"Series","md5":"bOt\/jJr0iAJSQY8WTyy4FA"}
Each line is a separate JSON object. Taking the first response and feeding it into jsonlint.com:
{
"programID": "SH015157750000",
"titles": {
"title120": "Help in Daily Living"
},
"eventDetails": {
"subType": "Series"
},
"originalAirDate": "2012-01-01",
"genres": [
"Religious"
],
"showType": "Series",
"md5": "d7CrQrtdSALdksAr9YDaHQ"
}
###Download the schedules for stationIDs
POST https://json.schedulesdirect.org/20131021/schedules
Token: Required
The body of the request will have the stationIDs that you are requesting schedules for.
{"request":[10002, 20454]}
Will return something which looks like this:
{"stationID":"10002","programs":[{"programID":"SH003712850000","md5":"LiAma3Y25JBWkrJvbNDvTg","airDateTime":"2014-05-02T00:00:00Z","duration":3600},{"programID":"SH006701200000","md5":"WI1BR8w4nPmXOVwe\/qK2xA","airDateTime":"2014-05-02T01:00:00Z","duration":7200,"liveTapeDelay":"Live","new":true},{"programID":"SH012546070000","md5":"vQ7tHUkfCvzyLY2OoG6rrQ","airDateTime":"2014-05-02T03:00:00Z","duration":3600},{"programID":"SH006701200000","md5":"WI1BR8w4nPmXOVwe\/qK2xA","airDateTime":"2014-05-02T04:00:00Z","duration":3600},{"programID":"SH017588780000","md5":"98wfRh+5cV741AFgFZlm6A","airDateTime":"2014-05-02T05:00:00Z","duration":3600},{"programID":"SH006701200000","md5":"WI1BR8w4nPmXOVwe\/qK2xA","airDateTime":"2014-05-02T06:00:00Z","duration":7200,"liveTapeDelay":"Live","new":true},{"programID":"SH005532720000","md5":"O2f14xmm2a9FB6VWvO7q8w","airDateTime":"2014-05-
02T08:00:00Z","duration":3600}
{"programID":"SH000006800000","md5":"XFG2oYyaxHLeGFnIYADtNA","airDateTime":"2014-05-04T00:00:00Z","duration":1800,"audioProperties":["cc","stereo"]}}
{"stationID":"20454","programs":[{"programID":"EP009311820166","md5":"dA+SfzzL0H7wwiw9ZIux1w","airDateTime":"2014-05-02T00:00:00Z","duration":1860,"contentRating":[{"body":"USA Parental Rating","code":"TVPG"}],"contentAdvisory":{"USA Parental Rating":["Language","Dialog"]},"syndication":{"source":"CBS","type":"Broadcast Network"},"new":true,"audioProperties":["cc","stereo","DD 5.1"],"videoProperties":["hdtv"]},{"programID":"EP017398410024","md5":"DWgiUeVMH10G1Uj+Pukj\/A","airDateTime":"2014-05-02T00:31:00Z","duration":1800,"contentRating":[{"body":"USA Parental Rating","code":"TVPG"}],"contentAdvisory":{"USA Parental Rating":["Language","Dialog"]},"syndication":{"source":"CBS","type":"Broadcast Network"},"new":true,"audioProperties":["cc","stereo","DD 5.1"],"videoProperties":["hdtv"]}
(etc)
"programs" is an array of many elements; parsing the JSON will allow your program to
- Check whether it needs to download the program details because it has never downloaded this program before (you don't already have a copy of the programID in your local cache)
- The md5 of the program has changed, so it should be re-downloaded to get updated information.
###Delete a system message
DELETE /messages/{messageID} Deletes non-system status messages from the status response.
###Download graphics, channel logos, banners
GET /assets/{uri}
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.
#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:
- Obtain the token for this session.
- 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 headends they want data for. Use the PUT function to add that headend to their account at Schedules Direct. By default, a user may have 4 headends 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 lineups for the headends. This will provide the user the mapping of channels, callsigns and station IDs.
- 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.
- Process the schedules; each schedule for each station id will contain at least 12 days of data.
- Determine which program id's need to be downloaded. During an initial download, the client will have an empty cache of program id's / MD5 hashes, so the client will need to download all relevant program id's.
NOTE: the server has been successfully tested with over 30,000 program ID requests, but the response may overload the client. You are strongly encouraged to chunk your requests to prevent your client from running out of memory. In addition, there is a 10 minute timeout on the server side. Requesting 30,000 program IDs over a 33.6Kbps modem will result in a failed download. You must ensure that the number of programs requested can be serviced within 10 minutes.
Once the client is in a steady state:
- Obtain a token.
- 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 headends on the server have newer "modified" dates than the one that is on the client. If yes, download the updated lineup for that headend.
- If there are no changes to the headends, check the last data update in the status object. If the last data update on the server is the same as what the user has saved, then there are no updated schedules, and the client should disconnect.
- If the last update data is newer, then download the schedules for the station id's that the user has selected.
- Honor the nextScheduled time in the status object; if your client connects during server-side data processing, the nextScheduled time will be "closer", however reconnecting while server-side data is being processed will not result in newer data.
- Parse the schedule, determine if the MD5 of the program for a particular timeslot has changed. If the program ID 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" program id's as determined through the MD5 values.
Requesting only station id's and program id's that the user is interested in will minimize the time and data required in each download.
Data updates occur six days a week, Monday through Saturday and are usually complete by 10:00 Central Standard Time.
Error Codes:
The system may respond to a request and send back an error code.
<style type="text/css"> .tg-left { text-align: left; } .tg-right { text-align: right; } .tg-center { text-align: center; } .tg-bf { font-weight: bold; } .tg-it { font-style: italic; } .tg-table-plain { border-collapse: collapse; border-spacing: 0; font-size: 100%; font: inherit; } .tg-table-plain td { border: 1px #555 solid; padding: 10px; vertical-align: top; } </style>Response | Internal Code | Error |
---|---|---|
OK | 0 | |
INVALID_JSON | 1001 | JSON decode error |
API_VERSION_MISSING | 1002 | No API sent |
INVALID_API_VERSION | 1003 | Wrong API |
HASH_MISSING | 1004 | randhash wasn't sent |
UNSUPPORTED_COMMAND | 2000 | Unsupported action |
REQUIRED_ACTION_MISSING | 2001 | No action |
REQUIRED_OBJECT_MISSING | 2002 | No object |
REQUIRED_PARAMETER_INVALID | 2003 | Returned error text will contain specific information |
DUPLICATE_HEADEND | 2100 | Adding a headend which is already in account |
INVALID_HEADEND | 2101 | Requested a headend which isn't in the system |
INVALID_HEADEND_DELETE | 2102 | Deleting a headend not in account |
SERVICE_OFFLINE | 3000 | Service offline for maintenance |
ACCOUNT_EXPIRED | 4001 | Account Expired |
INVALID_HASH | 4002 | Wrong hash |
INVALID_USER | 4003 | User account doesn't exist |
ACCOUNT_LOCKOUT | 4004 | Too many failed attempts to login |
MAX_HEADEND_CHANGES_REACHED | 4100 | Max changes for lineup |
MAX_HEADENDS | 4101 | Max headends in account reached |
NO_HEADENDS | 4102 | User doesn't have headends in account |
HCF | 9999 | Unknown error |