Sorry, your browser is not supported. Please upgrade to at least Internet Explorer 7 (or preferably version 8 or 9) or the latest version of Chrome/Safari/Firefox.

Developer Documentation

Help with using our API


1 Linked Data Browsing



Linked Data Browsing

1.1 URI Dereferencing

Following the standard practices for Linked Data, we distinguish between a resource and documents about a resource. Identifiers for the resource follow the pattern:


When you look them up you get redirected to the corresponding document about that thing. The document URL follows the pattern:


For example, in our Zones Dataset, the identifier for Macduff is

If you put this into your browser you get redirected to an HTML page about Macduff

1.2 Resource Document Formats

You can specify what format you want that document to be in. By default you get HTML in a human-readable form, but you can also ask for the document in one of several RDF formats: RDF/XML, N-triples, Turtle or RDF/JSON.

There are two ways to specify which format you want: you can append a format extension to the URI or you can use the HTTP 'Accept' header. For both of these approaches, you can apply it either to the resource identifier, the .../id/... URI, or the document address, the .../doc/... URI.

Format Extension Accept Header
RDF/XML .rdf application/rdf+xml
n-triples .nt application/n-triples
Turtle .ttl text/turtle
JSON .json application/json

1.3 Ruby Example

Here's an example of dereferencing a URI using the Ruby 'RestClient' library. Similar approaches can be taken in other languages.

This assumes you already have Ruby set up on your system. Also, if you don't already have it, you'll need to install the rest-client gem:

gem install rest-client

Full Rest Client documentation is here.

require 'rest-client' ## 1 Specifying the format in an accept header - in this case RDF/XML # If you're using the accept header, you can directly request the URI. # This involves two requests, because doing an HTTP GET on the resource identifier gives you a # 303 redirect to the appropriate document page. RestClient looks after that for you. puts RestClient.get '', :accept=>'application/rdf+xml' # Note: You can also request the document page directly puts RestClient.get '', :accept=>'application/rdf+xml' ## 2 Specifing the format as an extension - in this case JSON # If using an extension, you must request the document page directly # (as '.json' is not part of the URI) puts RestClient.get ''

1.4 Alternative URLs for convenient browsing

Alongside the definitive URI for a resource, we offer alternative additional URLs for the information about resources that reflects the way we organise the data into datasets and by type. These offer some convenient ways to navigate and access the data.

1.4.1 Datasets

Our 'Travel Zones' dataset has a URI of

but it can also be accessed at:

1.4.2 List resources of a type

The following URL:

provides a list of all resources in the 'Reports' dataset which have a type of:

1.4.3 Individual resources of a type

An individual incident can be found at (for example)

This view is the same as you get via dereferencing its URI:

These URLs follow the pattern:

http://{domain}/datasets/{dataset short name}/{type short name}/{resource short name}[.{format}]

1.4.4 Formats

As with the basic Linked Data Browsing, the information about a resource can be retrieved in multiple formats. Add the format extension to the URL or use the HTTP Accept header as explained above.

The list of all resources of a given type in a given dataset, together with the available triples about those resources, can also be retrieved in multiple formats, using the approaches described above. For example (N-triples)

These results are paged.Use the parameters _page and _per_page to control the paging process, with a maximum page size of 100. See the SPARQL 'Paging' section below for more details.

To get dataset metadata in machine readable formats, you can use the pattern

http://{domain}/datasets/{dataset short name}.[{format}]

1.5 Resources in external domains

When minting URIs to identify resources we want to talk about, the usual Linked Data practice is to create those URIs in a domain you control, so that it is possible to respond to them in the ways described above.

However, there are times when it is useful to hold information about external URIs in a triple store - that is URIs in a domain that we don't control. Information about those URIs can be retrieved using SPARQL, but it's also useful to have a standard URL pattern to access them.

This is possible using the pattern:

http://{domain}/resources/{external identifier, with 'http://' removed}


2.1 Introduction to SPARQL

The most flexible way to access the data is by using SPARQL. To submit a SPARQL query from your code, issue an HTTP GET to

http://{domain}/sparql.{format}?query={URL-encoded query}

For example, to run this simple query

SELECT * WHERE {<> ?p ?o}

and get the results as JSON, you need to GET the following URL (note the .json extension)

See the SPARQL Results Formats section below for more details of the different formats available.

Most languages have simple libraries for URL-encoding strings. This simple example will work in Ruby.

require 'rubygems' require 'cgi' query = 'SELECT * WHERE {<> ?p ?o}' encodedquery = CGI::escape(query) puts encodedquery

2.2 Parameter Interpolation

You can parameterize your SPARQL by including %{tokens} in your queries, and providing values for the tokens on the url query string.

2.3 Named Queries

Named queries can be called via 'shortcut' urls. Available named queries appear on the API tab of the dataset pages.

2.4 SPARQL Results formats

The available formats depend on the type of SPARQL query. A SPARQL query can be one of four main forms: SELECT, ASK, CONSTRUCT or DESCRIBE

Query Type Format Extension Accept Header
SELECT xml .xml application/xml
json .json application/json
text .text text/plain
csv .csv text/csv
ASK json .json application/json
xml .xml application/xml
text .text text/plain
CONSTRUCT RDF/XML .rdf application/rdf+xml
N-triples .nt text/plain
Turtle .ttl text/turtle
DESCRIBE RDF/XML .rdf application/rdf+xml
N-triples .nt text/plain
Turtle .ttl text/turtle

2.5 Errors

If you make a SPARQL request with a malformed query to any of the formats above (i.e. not via the HTML form at /sparql, or the in-page SPARQL console), then a blank response will be returned, with HTTP status 400.

Additionally, if you make a request for a CONSTRUCT or DESCRIBE query which returns over 2MB of data, the server will also respond with a 400 status.

2.6 JSON-P

If you're requesting JSON, you can additionally pass a callback parameter and the results will be wrapped in that function. This is useful for getting round cross-domain issues if you're writing JavaScript. For example:

or to make a JSONP request with jQuery, you can omit the callback parameter from the url and just set the dataType to jsonp.

queryUrl = '' $.ajax({ dataType: 'jsonp', url: queryUrl, success: function(data) { // callback code here alert('success!'); } });

2.7 Paging

The results of SELECT queries through PublishMyData SPARQL endpoints are paged. We take this approach to make sure that queries respond quickly and to avoid queries with very large result sets putting undue load on the server. The maximum number of results per page is 1000. The default for machine-readable formats is 1000 results per page, and for HTML format results is 20 per page. (We are still experimenting with this feature and would welcome your feedback on it.)

There are two parameters that can be added to the URLs described above to control paging. These are:

  • _per_page: defaults to 10 in the in-page console, 20 on the SPARQL page (at '/sparql'), or 1000 for data-formats. (Maximum of 1000).
  • _page: defaults to 1.

For example, this query returns all resources of the Interval Type

SELECT * WHERE {?s a <>}

To get results 51 to 100 in text format, use this URL:

The results of CONSTRUCT queries are currently limited to 2MB of data triples and we don't do automatic paging. If you have a CONSTRUCT query with a bigger result than that, you'll need to do your own paging using the SPARQL OFFSET and LIMIT keywords.

This sample Ruby code will loop through all pages of the results of a query and combine them into a single array

require 'rubygems' require 'cgi' require 'rest-client' require 'json' # find all resources of type Interval query = 'SELECT * WHERE {?s a <>}' encodedquery = CGI::escape(query) # results per page per_page = 50 base_url = '' + encodedquery # the final result is an array of hashes # each element of the array looks like: # {'s'=>{'value'=>'', 'type'=>'uri'}} result = [] # we add the results into this array, page by page done = false page = 1 while (!done) query_url = base_url + "&_page=#{page}&_per_page=#{per_page}" part_result = JSON.parse(RestClient.get(query_url)) part_result_array = part_result['results']['bindings'] # this reflects the hash structure of the JSON returned if (part_result_array.length > 0) result = result + part_result_array page += 1 else done = true end end puts 'total number of results = ' + result.length.to_s

2.8 Use of named graphs

Each dataset in PublishMyData-driven sites is contained within a separate named graph. The dataset itself has a URI, for example

The web page for the dataset lists the named graph that contains the dataset, in this case

The graph name for the dataset is contained in the dataset metadata, using a predicate called and can be obtained by a query like this:

SELECT ?graph WHERE { <> <> ?graph }


3.1 Overview

We provide a REST JSON API for reading and writing incident reports. The read-API is fully open, but writes require an API Key. Please get in touch to request one.

3.2 JSON Read API

A few convenience REST / JSON API routes exist for querying data, which don’t require an API key. These routes are used by JavaScript in the web application.

3.2.1 Lists of Reports

The url can be used to get lists of reports. Filters can be applied to the results.


future (boolean, default=false)

tags (string, no default)

selected_zones_only (boolean, default=false, only applies if a user's API key is provided)

Current Reports

The simplest option, with no parameters provides you with a list of all currently open reports.

To get this as JSON, make a GET request to

or (with an application/json accept header).

e.g. curl -v -H "Accept: application/json"

This will return an array of JSON objects. For example:

[{"uri":"","description":"A96 Kintore - Aberdeen (A90) - Closure. All lanes closed in both directions for more than an hou...","created_at":"December 13, 2012 10:00","incident_begins_at":"December 13, 2012 10:00","incident_begins_in_future":false,"incident_ends_in_future":null,"latitude":"57.196545","longitude":"-2.264773","tags":["trafficscotland"],"tags_string":"trafficscotland","guid":"c47fd679-11c5-91f2-b790-4d9abc93833e","status":"Open","creator":"trafficscot1"}, {}, {}, ... ]

Applying Filters

Here's an example of applying the filters to get planned reports with tags snow or rain. Again, this returns an array of JSON objects.

curl -v -H "Accept: application/json" ",rain"

3.2.2 Details of a Single Report

You can the details of a single report as JSON by making a GET request to the url of a report (these urls match those used by the web app, as opposed to the URIs of the RDF resources).


or{GUID} (with an application/json accept header).

This will return a single JSON object. e.g.

{"uri":"","description":"A96 Kintore - Aberdeen (A90) - Closure. All lanes closed in both directions for more than an hou...","created_at":"December 13, 2012 10:00","incident_begins_at":"December 13, 2012 10:00","incident_begins_in_future":false,"incident_ends_in_future":null,"latitude":"57.196545","longitude":"-2.264773","tags":["trafficscotland"],"tags_string":"trafficscotland","guid":"c47fd679-11c5-91f2-b790-4d9abc93833e","status":"Open","creator":"trafficscot1"}

3.3 JSON Write API

All requests to the write-API must include an API key as a request header. This key must be assigned to an existing user. Contact us to request an API key.

To create a planned/future report, the key must be assigned to a user who has administration rights.

An admin user API key can close or update any report. A normal user API key can only close or update reports created by that user.

3.3.1 Report Data

The report is described as a JSON object, with this structure (and some example data).

Current report (i.e. open now)
{ “report”: { “latitude”:57.15, “longitude”:-2.1, “description”:”blah”, “tags_string”:”tag1,tag2” } }
Planned report (starts in the future)
{ “report”: { “latitude”:57.15, “longitude”:-2.1, “description”:”blah”, “tags_string”:”tag1,tag2”, “incident_begins_at”:”2013-01-01 09:00", “incident_ends_at”:”2013-02-01 15:00" } }

3.3.1 Create a new report

Send a POST with the JSON report details as payload to

If successful, returns a status code of 201 in the header, with a JSON response giving the GUID of the newly created report

e.g. {“guid”:”d0fdb9d9-a53f-08a9-ebf4-54ccdbbcaa6b”}

Example request:

curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "api-key: blah" -X POST -d '{"report":{"latitude":57.15, "longitude":-2.1, "description": "lorry shed its load of jam", "tags_string": "lorry, traffic-jam", "incident_begins_at":"2012-01-01 12:00", "incident_ends_at":"2013-01-01 11:01" }}'

3.3.2 Modifying an existing report

Send a PUT with the updated JSON report details as payload to{GUID}.

Returns status 200 header if successful. Example request:

curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "api-key: blah" -X PUT -d '{"report":{"latitude":57.15, "longitude":-2.1, "description": "updated desc", "tags_string": "lorry, traffic-jam" }}' "

3.3.3 Closing an existing report

Send a PUT with no (or empty) payload to{GUID}/close

Returns status 200 if successful. Example request:

curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "api-key: blah" -X PUT

3.3.4 Error Codes

400 Bad request.

401 Unauthorized: If the API key doesn’t identify a user in the system, or the identified user does not have rights to perform the action.

404 Not Found.

  • This page is available as
  • HTML