# 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:
WARNING
- This API gives access to UK address data only.
- All API parameters must be in lowercase.
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
# dps
- Type:
string
Delivery point suffix
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",
"dps":"1A"
},
{
"organisation_name":"FILMS R US",
"department_name":"",
"line_1":"3 HIGH STREET",
"line_2":"CRAFTY VALLEY",
"udprn":"12345679",
"dps":"1B"
}
],
"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
# dps
- Type:
string
Delivery point suffix
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",
"dps":"1A"
},
{
"organisation_name": "FILMS R US",
"department_name": "",
"po_box_number": "",
"building_number": "3",
"sub_building_name": "",
"building_name": "",
"udprn": "12345679",
"dps":"1B"
}
],
"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. If set, it will return the same dataset as the Geocoding API endpoint. (Please view the Geocoding documentation for the details)
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 (if postcode parameter is not set)
- Available: JSON
These are the postcodes for which you request data (max 25). This parameter is not case sensitive, and it also handles the optional space in the middle of the postcodes.
# postcode
- Type:
string
- Required: yes (if postcodes parameter is not set)
- Available: GET
The postcode for which you request data. This parameter is not case sensitive, and it also handles the optional space in the middle of the postcode.
# 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: ["SW1A 2AA", "SL6 1QZ"],
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': 'SW1A 2AA',
'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" => ["SW1A 2AA", "SL6 1QZ"],
"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, with further Code Point Open data (adminstrative area information and NHS codes). If the data is not part of the OS dataset, only geocoding information is provided, and the location information is only an estimate. Every text value comes with an OS code, and a matching text.
# easting / northing
UK grid reference numbers
# country_code / country_name
England / Wales / Scotland / Northern Ireland
# nhs_regional_ha_code / nhs_regional_ha_text
NHS regional health authority code and name
# nhs_ha_code / nhs_ha_text
NHS health authority code and name
# administrative_county_code / administrative_county_text
Administrative county
# administrative_district_code / administrative_district_text
Administrative district
# administrative_ward_code / administrative_ward_text
Administrative ward
# 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.
{
"SW1A2AA": {
"lat": 51.5035,
"lng": -0.127695,
"os": {
"easting": "530047",
"northing": "179951",
"country_code": "E92000001",
"country_text": "England",
"nhs_regional_ha_code": "E19000003",
"nhs_regional_ha_text": "London Programme for IT (LPFiT)",
"nhs_ha_code": "E18000007",
"nhs_ha_text": "London",
"administrative_county_code": "",
"administrative_county_text": "",
"administrative_district_code": "E09000033",
"administrative_district_text": "City of Westminster London Boro",
"administrative_ward_code": "E05000644",
"administrative_ward_text": ""
}
},
"SL61QZ": {
"lat": 51.5233,
"lng": -0.718984,
"os": {
"easting": "488971",
"northing": "181267",
"country_code": "E92000001",
"country_text": "England",
"nhs_regional_ha_code": "E19000002",
"nhs_regional_ha_text": "Southern Programme for IT (SPFiT)",
"nhs_ha_code": "E18000009",
"nhs_ha_text": "South Central",
"administrative_county_code": "",
"administrative_county_text": "",
"administrative_district_code": "E06000040",
"administrative_district_text": "Windsor and Maidenhead (B)",
"administrative_ward_code": "E05002367",
"administrative_ward_text": "Oldfield Ward"
}
}
}
The API will respond to the request with the following structure, if preserve_index is true.
[
{
"lat": 51.5035,
"lng": -0.127695,
"os": {
"easting": "530047",
"northing": "179951",
"country_code": "E92000001",
"country_text": "England",
"nhs_regional_ha_code": "E19000003",
"nhs_regional_ha_text": "London Programme for IT (LPFiT)",
"nhs_ha_code": "E18000007",
"nhs_ha_text": "London",
"administrative_county_code": "",
"administrative_county_text": "",
"administrative_district_code": "E09000033",
"administrative_district_text": "City of Westminster London Boro",
"administrative_ward_code": "E05000644",
"administrative_ward_text": ""
},
"postcode": "SW1A2AA"
},
{
"lat": 51.5233,
"lng": -0.718984,
"os": {
"easting": "488971",
"northing": "181267",
"country_code": "E92000001",
"country_text": "England",
"nhs_regional_ha_code": "E19000002",
"nhs_regional_ha_text": "Southern Programme for IT (SPFiT)",
"nhs_ha_code": "E18000009",
"nhs_ha_text": "South Central",
"administrative_county_code": "",
"administrative_county_text": "",
"administrative_district_code": "E06000040",
"administrative_district_text": "Windsor and Maidenhead (B)",
"administrative_ward_code": "E05002367",
"administrative_ward_text": "Oldfield Ward"
},
"postcode": "SL61QZ"
}
]
In case the postcode is not part of the Code Point Open dataset, a simplified result is returned.
{
"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
}
}