JSON API

The JSON API gives access to Royal Mail PAF data and Geocoding. It supports CORS, can return data as JSON or JSONP and allows sorting.

JSON is the preferred way to go for any new custom integrations. Before you do lots of work, please check our list of Address Finder Plugins. You might find something suitable there.

We also have a wrapper for our JSON API on Github:

JSON API wrapper on Github

WARNING

This API gives access to UK address data only.

If you are looking to implement an international solution, please look at our Global Address Auto-Complete API.

Full Address (RapidAddress)

RapidAddress returns full address details for every address matching the search query postcode.

HTTP(S) Request

GET/POST http://pcls1.craftyclicks.co.uk/json/rapidaddress

or

GET/POST https://pcls1.craftyclicks.co.uk/json/rapidaddress

Query Parameters

Pass parameters either as GET or POST in JSON.

key

  • Required: yes
  • Values: Your 20 digit code

Using the API requires a 20 character access token, which you should insert here. You will receive an access token when you sign up for an account.

postcode

  • Required: yes
  • Values: A UK postcode

This is the postcode for which you want to request data

callback

  • Required: no
  • Values: true, false
  • Default: false

If callback is set, the JSON data will be wrapped as JSONP with the function name from the callback

response

  • Required: no
  • Values:
    • paf_compact: All address data returned
    • data_formatted: Address lines are pre-formatted
  • Default: paf_compact

This sets the format of the response from the API.

lines

  • Required: no
  • Values: 1, 2, 3
  • Default: 2

Only active when ‘response’ is set to data_formatted. This sets the number of address lines in the response from the API.

sort

  • Required: no
  • Values:
    • none: Results are not sorted
    • asc: Results returned in ascending order
    • desc: results returned in descending order.
  • Default: none

This option sets how the results are sorted in the response.

include_geocode

  • Required: no
  • Values: true, false
  • Default: false

Sets whether or not to include the geocoding data. Please note that the usage of this feature within this API endpoint is free.

TIP

We suggest using response=data_formatted in most cases, as it’s easier to work with. Use response=paf_compact only if you require all address parts separated out.

Example request

function getTestData(){
    // Pass parameters via JSON
    var parameters = {
        key: "xxxxx-xxxxx-xxxxx-xxxxx",
        postcode: "aa11aa",
        response: "data_formatted"
    };
    var url = "http://pcls1.craftyclicks.co.uk/json/rapidaddress";
    // or via GET parameters
    // var url = "http://pcls1.craftyclicks.co.uk/json/rapidaddress?key=xxxxx-xxxxx-xxxxx-xxxxx&postcode=aa11aa&response=data_formatted";

    request = new XMLHttpRequest();
    request.open('POST', url, false);
    // Only needed for the JSON parameter pass
    request.setRequestHeader('Content-Type', 'application/json');
    // Wait for change and then either JSON parse response text or throw exception for HTTP error
    request.onreadystatechange = function() {
        if (this.readyState === 4){
            if (this.status >= 200 && this.status < 400){
                // Success!
                data = JSON.parse(this.responseText);
            } else {
                throw 'HTTP Request Error';
            }
        }
    };
    // Send request
    request.send(JSON.stringify(parameters));
    return data;
}

// console.log(getTestData());
import urllib2
import urllib
import json

def getTestData():
    url = "https://pcls1.craftyclicks.co.uk/json/"

    url += 'rapidaddress'
    params = {
        'postcode': 'aa11aa',
        'key': 'xxxxx-xxxxx-xxxxx-xxxxx',
        'response': 'data_formatted'
    }

    req = urllib2.Request(url + '?' + urllib.urlencode(params))

    res = urllib2.urlopen(req)
    data = json.loads(res.read())
    return data

#print json.dumps(getTestData(), sort_keys=True, indent=4, separators=(',', ': '))
<?php
function getTestData(){
    $data = array(
        "postcode"  => "aa11aa",
        "key"       => "xxxxx-xxxxx-xxxxx-xxxxx",
        "response"  => "data_formatted"
    );
    $data_string = json_encode($data);

    $ch = curl_init('http://pcls1.craftyclicks.co.uk/json/rapidaddress');
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length: ' . strlen($data_string))
    );

    $result = curl_exec($ch);
    return $result;
}
// echo '<pre>'.getTestData().'</pre>';
?>

Response: data_formatted

For each postcode, the response contains the following information:

delivery_points

  • Type: array

This is an array of objects, each of which contains the data for an individual address. See the table below for more details about the information contained in these objects.

delivery_point_count

  • Type: integer

Number of elements in the delivery_points array

postal_county

  • Type: string

Former postal county for this postcode

traditional_county

  • Type: string

Traditional county for this postcode

town

  • Type: string

Town name in uppercase (Royal Mail standard)

postcode

  • Type: string

Formatted postcode

data_formatted: delivery_points

organisation_name

  • Type: string

Registered organisation at the address.

department_name

  • Type: string

Specific department of said organisation.

line_1

  • Type: string

Line 1 of the address

line_2

  • Type: string

Line 2 of the address

line_3

  • Type: string

Line 3 of the address

udprn

  • Type: string

Royal Mail unique identifier

The API will respond to the request with the following structure.

{
    "delivery_points":[
        {
            "organisation_name":"THE BAKERY",
            "department_name":"",
            "line_1":"1 HIGH STREET",
            "line_2":"CRAFTY VALLEY",
            "udprn":"12345678"
        },
        {
            "organisation_name":"FILMS R US",
            "department_name":"",
            "line_1":"3 HIGH STREET",
            "line_2":"CRAFTY VALLEY",
            "udprn":"12345679"
        }
    ],
    "delivery_point_count":2,
    "postal_county":"POSTAL COUNTY",
    "traditional_county":"TRADITIONAL COUNTY",
    "town":"BIG CITY",
    "postcode":"AA1 1AA"
}

Response: paf_compact

For each postcode, the response contains the following information:

thoroughfares

  • Type: array

This array contains thoroughfare details and delivery_points, an array containing all the address details for every address matching the postcode. See the table below for more details.

thoroughfare_count

  • Type: integer

Number of elements in the thoroughfares array

postal_county

  • Type: string

Former postal county for this postcode

traditional_county

  • Type: string

Traditional county for this postcode

town

  • Type: string

Town name in uppercase (Royal Mail standard)

postcode

  • Type: string

Formatted postcode

dependent_locality

  • Type: string

Sub-locality within town or city

double_dependent_locality

  • Type: string

District within sub-locality

paf_compact: thoroughfares

delivery_points

  • Type: array

This is an array of objects, each of which contains the data for an individual address. See the table below for more details about the information contained in these objects.

delivery_point_count

  • Type: integer

Number of elements in the delivery_points array

dependent_thoroughfare_name

  • Type: string

Name of the dependent thoroughfare

dependent_thoroughfare_descriptor

  • Type: string

The dependent thoroughfare descriptor, e.g. Road, Street, Avenue

thoroughfare_name

  • Type: string

Name of the thoroughfare

thoroughfare_descriptor

  • Type: string

The thoroughfare descriptor, e.g. Road, Street, Avenue

paf_compact: delivery_points

organisation_name

  • Type: string

Registered organisation at the address.

department_name

  • Type: string

Specific department of said organisation.

po_box_number

  • Type: string

PO Box number

building_number

  • Type: string

Number of building

sub_building_name

  • Type: string

Sub-name of building

building_name

  • Type: string

Name of building

udprn

  • Type: string

Royal Mail unique identifier

The API will respond to the request with the following structure.

{
    "thoroughfare_count": 1,
    "thoroughfares": [
        {
            "delivery_points": [
                {
                    "organisation_name": "THE BAKERY",
                    "department_name": "",
                    "po_box_number": "",
                    "building_number": "1",
                    "sub_building_name": "",
                    "building_name": "",
                    "udprn": "12345678"
                },
                {
                    "organisation_name": "FILMS R US",
                    "department_name": "",
                    "po_box_number": "",
                    "building_number": "3",
                    "sub_building_name": "",
                    "building_name": "",
                    "udprn": "12345679"
                }
            ],
            "delivery_point_count": 2,
            "dependent_thoroughfare_name": "",
            "dependent_thoroughfare_descriptor": "",
            "thoroughfare_name": "HIGH",
            "thoroughfare_descriptor": "STREET"
        }
    ],
    "postal_county": "POSTAL COUNTY",
    "traditional_county": "TRADITIONAL COUNTY",
    "dependent_locality": "CRAFTY VALLEY",
    "double_dependent_locality": "",
    "town": "BIG CITY",
    "postcode": "AA1 1AA"
}

Street Level (BasicAddress)

BasicAddress returns details of every street matching the search query postcode.

HTTP(s) Request

GET/POST http://pcls1.craftyclicks.co.uk/json/basicaddress

or

GET/POST https://pcls1.craftyclicks.co.uk/json/basicaddress

Query Parameters

Pass parameters either in GET or in JSON.

key

  • Required: yes
  • Values: Your 20 digit code

Using the API requires a 20 character access token, which you should insert here. You will receive an access token when you sign up for an account.

postcode

  • Required: yes
  • Values: A UK postcode

This is the postcode for which you want to request data

callback

  • Required: no
  • Values: true, false
  • Default: false

If callback is set, the JSON data will be wrapped as JSONP with the function name from the callback

response

  • Required: no
  • Values:
    • paf_compact: All address data returned
    • data_formatted: Address lines are pre-formatted
  • Default: paf_compact

This sets the format of the response from the API.

lines

  • Required: no
  • Values: 1, 2, 3
  • Default: 2

Only active when 'response’ is set to data_formatted. This sets the number of address lines in the response from the API.

sort

  • Required: no
  • Values:
    • none: Results are not sorted
    • asc: Results returned in ascending order
    • desc: results returned in descending order.
  • Default: none

This option sets how the results are sorted in the response.

include_geocode

  • Required: no
  • Values: true, false
  • Default: false

Sets whether or not to include the geocoding data. Please note that the usage of this feature within this API endpoint is free.

TIP

We suggest using response=data_formatted in most cases, as it’s easier to work with. Use response=paf_compact only if you require all address parts separated out.

Example request

function getTestData(){
    // Pass parameters via JSON
    var parameters = {
        key: "xxxxx-xxxxx-xxxxx-xxxxx",
        postcode: "aa11aa",
    };
    var url = "http://pcls1.craftyclicks.co.uk/json/basicaddress";
    // or via GET parameters
    // var url = "http://pcls1.craftyclicks.co.uk/json/basicaddress?key=xxxxx-xxxxx-xxxxx-xxxxx&postcode=aa11aa&response=data_formatted";

    request = new XMLHttpRequest();
    request.open('POST', url, false);
    // Only needed for the JSON parameter pass
    request.setRequestHeader('Content-Type', 'application/json');
    // Wait for change and then either JSON parse response text or throw exception for HTTP error
    request.onreadystatechange = function() {
        if (this.readyState === 4){
            if (this.status >= 200 && this.status < 400){
                // Success!
                data = JSON.parse(this.responseText);
            } else {
                throw 'HTTP Request Error';
            }
        }
    };
    // Send request
    request.send(JSON.stringify(parameters));
    return data;
}

// console.log(getTestData());
import urllib2
import urllib
import json

def getTestData():
    url = "https://pcls1.craftyclicks.co.uk/json/"

    url += 'basicaddress'
    params = {
        'postcode': 'aa11aa',
        'key': 'xxxxx-xxxxx-xxxxx-xxxxx',
        'response': 'data_formatted'
    }

    req = urllib2.Request(url + '?' + urllib.urlencode(params))

    res = urllib2.urlopen(req)
    data = json.loads(res.read())
    return data

#print json.dumps(getTestData(), sort_keys=True, indent=4, separators=(',', ': '))
<?php
function getTestData(){
    $data = array(
        "postcode"  => "aa11aa",
        "key"       => "xxxxx-xxxxx-xxxxx-xxxxx",
        "response"  => "data_formatted"
    );
    $data_string = json_encode($data);

    $ch = curl_init('http://pcls1.craftyclicks.co.uk/json/basicaddress');
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length: ' . strlen($data_string))
    );

    $result = curl_exec($ch);
    return $result;
}
// echo '<pre>'.getTestData().'</pre>';
?>

Response: data_formatted

For each postcode, the response contains the following information:

thoroughfares
  • Type: array

This array contains thoroughfare details and delivery_points, an array containing all the address details for every address matching the postcode. See the table below for more details.

thoroughfare_count
  • Type: integer

Number of elements in the thoroughfares array

postal_county
  • Type: string

Former postal county for this postcode

traditional_county
  • Type: string

Traditional county for this postcode

town
  • Type: string

Town name in uppercase (Royal Mail standard)

postcode
  • Type: string

Formatted postcode

thoroughfares

line_1

  • Type: string

Line 1 of the formatted address

line_2

  • Type: string

Line 2 of the formatted address

line_3

  • Type: string

Line 3 of the formatted address

The API will respond to the request with the following structure.

{
    "thoroughfares": [
        {
            "line_1": "HIGH STREET",
            "line_2": "CRAFTY VALLEY"
        }
    ],
    "thoroughfare_count": 1,
    "postal_county": "POSTAL COUNTY",
    "traditional_county": "TRADITIONAL COUNTY",
    "town": "BIG CITY",
    "postcode": "AA1 1AA"
}

Response: paf_compact

For each postcode, the response contains the following information:

thoroughfares

  • Type: array

This array contains thoroughfare details and delivery_points, an array containing all the address details for every address matching the postcode. See the table below for more details.

thoroughfare_count

  • Type: integer

Number of elements in the thoroughfares array

postal_county

  • Type: string

Former postal county for this postcode

traditional_county

  • Type: string

Traditional county for this postcode

town

  • Type: string

Town name in uppercase (Royal Mail standard)

postcode

  • Type: string

Formatted Postcode

dependent_locality

  • Type: string

Sub-locality within town or city

double_dependent_locality

  • Type: string

District within sub-locality

thoroughfares

dependent_thoroughfare_name

  • Type: string

Name of the dependent thoroughfare

dependent_thoroughfare_descriptor

  • Type: string

The dependent thoroughfare descriptor, e.g. Road, Street, Avenue

thoroughfare_name

  • Type: string

Name of the thoroughfare

thoroughfare_descriptor

  • Type: string

The thoroughfare descriptor, e.g. Road, Street, Avenue

The API will respond to the request with the following structure.

{
    "thoroughfare_count": 1,
    "thoroughfares": [
        {
            "dependent_thoroughfare_name": "",
            "dependent_thoroughfare_descriptor": "",
            "thoroughfare_name": "HIGH",
            "thoroughfare_descriptor": "STREET"
        }
    ],
    "postal_county": "POSTAL COUNTY",
    "traditional_county": "TRADITIONAL COUNTY",
    "dependent_locality": "CRAFTY VALLEY",
    "double_dependent_locality": "",
    "town": "BIG CITY",
    "postcode": "AA1 1AA"
}

Geocoding

HTTP(S) Request

GET/POST http://pcls1.craftyclicks.co.uk/json/geocode

or

GET/POST https://pcls1.craftyclicks.co.uk/json/geocode

Query Parameters

Pass parameters either in GET or in JSON. Some parameters are only available in JSON.

key

  • Type: string
  • Required: yes
  • Available: Both

Using the API requires a 20 character access token, which you should insert here. You will receive an access token when you sign up for an account.

postcodes

  • Type: array of strings
  • Required: yes
  • Available: JSON

These are the postcodes for which you request data (max 25).

postcode

  • Type: string
  • Required: yes
  • Available: GET

The postcode for which you request data

callback

  • Type: string
  • Required: no
  • Available: Both

If callback is set, the JSON data will be wrapped as JSONP with the function name from the callback.

distance

  • Type: object
  • Required: no
  • Available: JSON

Specify an extra location to calculate distance to

preserve_index

  • Type: bool
  • Required: no
  • Available: JSON

Specify how the results should be grouped. false: index by formatted postcode true: keep input order and return array

Example request

function getTestData(){
    // Pass parameters via JSON
    var parameters = {
        key: "xxxxx-xxxxx-xxxxx-xxxxx",
        // supply the array of postcodes to geocode. max 25.
        postcodes: ["aa11aa","aa11ab"],
        distance: {
            // supply a postcode to measure to
            "base_postcode": "aa11ae"
            /* or northing easting
            "base_ne" : {
                "northing" : 182949,
                "easting"  : 542267
            }
            */
        },
        preserve_index: 1
    };
    var url = "http://pcls1.craftyclicks.co.uk/json/geocode";
    // or via GET parameters
    // var url = "http://pcls1.craftyclicks.co.uk/json/geocode?key=xxxxx-xxxxx-xxxxx-xxxxx&postcode=aa11aa";

    request = new XMLHttpRequest();
    request.open('POST', url, false);
    // Only needed for the JSON parameter pass
    request.setRequestHeader('Content-Type', 'application/json');
    // Wait for change and then either JSON parse response text or throw exception for HTTP error
    request.onreadystatechange = function() {
        if (this.readyState === 4){
            if (this.status >= 200 && this.status < 400){
                // Success!
                data = JSON.parse(this.responseText);
            } else {
                throw 'HTTP Request Error';
            }
        }
    };
    // Send request
    request.send(JSON.stringify(parameters));
    return data;
}

// console.log(getTestData());
import urllib2
import urllib
import json

def getTestData():
    url = "https://pcls1.craftyclicks.co.uk/json/"

    url += 'basicaddress'
    params = {
        'postcode': 'aa11aa',
        'key': 'xxxxx-xxxxx-xxxxx-xxxxx',
        'response': 'data_formatted'
    }

    req = urllib2.Request(url + '?' + urllib.urlencode(params))

    res = urllib2.urlopen(req)
    data = json.loads(res.read())
    return data

#print json.dumps(getTestData(), sort_keys=True, indent=4, separators=(',', ': '))
<?php
function getTestData(){
    $data = array(
        "postcodes" => ["aa11aa","aa11ab"],
        "key" => "xxxxx-xxxxx-xxxxx-xxxxx",
        "distance" => [
            "base_postcode" => "aa11ae"
        ]
    );
    $data_string = json_encode($data);

    $ch = curl_init('http://pcls1.craftyclicks.co.uk/json/geocode');
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length: ' . strlen($data_string))
    );

    $result = curl_exec($ch);
    return $result;
}
// echo '<pre>'.getTestData().'</pre>';
?>

Response

For each postcode, the response contains the following information:

lat

Latitude

lng

Longitude

os

If the postcode exists in OS Code Point Open, northing and easting is available. If the data is not part of the OS dataset, it’s not set. In this case, the lat and lng are estimates only.

distance

In meters. (the official Ordnance Survey NE system is based on the metric system.)

The API will respond to the request with the following structure, if preserve_index is unset or false.

{
    "AA11AA": {
        "lat": 51.5132253,
        "lng": -0.0748047,
        "os": {
            "easting": 533689,
            "northing": 181123
        },
        "distance": 46922
    },
    "AA11AB": {
        "lat": 51.513362,
        "lng": -0.0891883,
        "os": {
            "easting": 532691,
            "northing": 181112
        },
        "distance": 45930
    }
}

The API will respond to the request with the following structure, if preserve_index is true.

[
    {
        "lat": 51.5132253,
        "lng": -0.0748047,
        "os": {
            "easting": 533689,
            "northing": 181123
        },
        "distance": 46922,
        "postcode": "AA11AA"
    },
    {
        "lat": 51.513362,
        "lng": -0.0891883,
        "os": {
            "easting": 532691,
            "northing": 181112
        },
        "distance": 45930,
        "postcode": "AA11AB"
    }
]
Last Updated: 9/5/2018, 5:04:57 PM