curl --request POST \
--url https://api.ctrl-hub.com/v3/location-imports \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Session-Token: <api-key>' \
--data '
{
"data": {
"type": "location-imports",
"attributes": {
"upload_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"column_mapping": {
"reference": "POLE_NO",
"name": "NAME",
"description": "<string>",
"location_type": "ASSET_TYPE",
"latitude": "<string>",
"longitude": "<string>",
"easting": "<string>",
"northing": "<string>",
"address_number": "<string>",
"address_name": "<string>",
"address_thoroughfare": "<string>",
"address_post_town": "<string>",
"address_postcode": "<string>"
}
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
},
"default_location_type": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-types"
}
}
}
}
}
'import requests
url = "https://api.ctrl-hub.com/v3/location-imports"
payload = { "data": {
"type": "location-imports",
"attributes": {
"upload_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"column_mapping": {
"reference": "POLE_NO",
"name": "NAME",
"description": "<string>",
"location_type": "ASSET_TYPE",
"latitude": "<string>",
"longitude": "<string>",
"easting": "<string>",
"northing": "<string>",
"address_number": "<string>",
"address_name": "<string>",
"address_thoroughfare": "<string>",
"address_post_town": "<string>",
"address_postcode": "<string>"
}
},
"relationships": {
"organisation": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
} },
"default_location_type": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-types"
} }
}
} }
headers = {
"X-Session-Token": "<api-key>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Session-Token': '<api-key>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: 'location-imports',
attributes: {
upload_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
column_mapping: {
reference: 'POLE_NO',
name: 'NAME',
description: '<string>',
location_type: 'ASSET_TYPE',
latitude: '<string>',
longitude: '<string>',
easting: '<string>',
northing: '<string>',
address_number: '<string>',
address_name: '<string>',
address_thoroughfare: '<string>',
address_post_town: '<string>',
address_postcode: '<string>'
}
},
relationships: {
organisation: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: 'organisations'}},
default_location_type: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: 'location-types'}}
}
}
})
};
fetch('https://api.ctrl-hub.com/v3/location-imports', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ctrl-hub.com/v3/location-imports",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'type' => 'location-imports',
'attributes' => [
'upload_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'column_mapping' => [
'reference' => 'POLE_NO',
'name' => 'NAME',
'description' => '<string>',
'location_type' => 'ASSET_TYPE',
'latitude' => '<string>',
'longitude' => '<string>',
'easting' => '<string>',
'northing' => '<string>',
'address_number' => '<string>',
'address_name' => '<string>',
'address_thoroughfare' => '<string>',
'address_post_town' => '<string>',
'address_postcode' => '<string>'
]
],
'relationships' => [
'organisation' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => 'organisations'
]
],
'default_location_type' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => 'location-types'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/vnd.api+json",
"X-Session-Token: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ctrl-hub.com/v3/location-imports"
payload := strings.NewReader("{\n \"data\": {\n \"type\": \"location-imports\",\n \"attributes\": {\n \"upload_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"column_mapping\": {\n \"reference\": \"POLE_NO\",\n \"name\": \"NAME\",\n \"description\": \"<string>\",\n \"location_type\": \"ASSET_TYPE\",\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\",\n \"easting\": \"<string>\",\n \"northing\": \"<string>\",\n \"address_number\": \"<string>\",\n \"address_name\": \"<string>\",\n \"address_thoroughfare\": \"<string>\",\n \"address_post_town\": \"<string>\",\n \"address_postcode\": \"<string>\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n },\n \"default_location_type\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"location-types\"\n }\n }\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Session-Token", "<api-key>")
req.Header.Add("Content-Type", "application/vnd.api+json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ctrl-hub.com/v3/location-imports")
.header("X-Session-Token", "<api-key>")
.header("Content-Type", "application/vnd.api+json")
.body("{\n \"data\": {\n \"type\": \"location-imports\",\n \"attributes\": {\n \"upload_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"column_mapping\": {\n \"reference\": \"POLE_NO\",\n \"name\": \"NAME\",\n \"description\": \"<string>\",\n \"location_type\": \"ASSET_TYPE\",\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\",\n \"easting\": \"<string>\",\n \"northing\": \"<string>\",\n \"address_number\": \"<string>\",\n \"address_name\": \"<string>\",\n \"address_thoroughfare\": \"<string>\",\n \"address_post_town\": \"<string>\",\n \"address_postcode\": \"<string>\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n },\n \"default_location_type\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"location-types\"\n }\n }\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ctrl-hub.com/v3/location-imports")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Session-Token"] = '<api-key>'
request["Content-Type"] = 'application/vnd.api+json'
request.body = "{\n \"data\": {\n \"type\": \"location-imports\",\n \"attributes\": {\n \"upload_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"column_mapping\": {\n \"reference\": \"POLE_NO\",\n \"name\": \"NAME\",\n \"description\": \"<string>\",\n \"location_type\": \"ASSET_TYPE\",\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\",\n \"easting\": \"<string>\",\n \"northing\": \"<string>\",\n \"address_number\": \"<string>\",\n \"address_name\": \"<string>\",\n \"address_thoroughfare\": \"<string>\",\n \"address_post_town\": \"<string>\",\n \"address_postcode\": \"<string>\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n },\n \"default_location_type\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"location-types\"\n }\n }\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-imports",
"attributes": {
"status": "processing",
"filename": "enwl-poles-2026-09.csv",
"column_mapping": {
"reference": "POLE_NO",
"name": "NAME",
"description": "<string>",
"location_type": "ASSET_TYPE",
"latitude": "<string>",
"longitude": "<string>",
"easting": "<string>",
"northing": "<string>",
"address_number": "<string>",
"address_name": "<string>",
"address_thoroughfare": "<string>",
"address_post_town": "<string>",
"address_postcode": "<string>"
},
"progress": {
"total_rows": 30000,
"processed_rows": 12500
},
"results": {
"inserted": 29850,
"updated": 146,
"skipped": 4,
"row_error_count": 4
},
"row_errors": [
{
"row": 4512,
"reason": "the latitude \"53.4o8\" is not a number",
"reference": "POLE-004512"
}
],
"error": "<string>"
},
"meta": {
"requested_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z"
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
},
"requester": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "users"
}
},
"default_location_type": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-types"
}
}
}
},
"jsonapi": {
"version": "1.0"
},
"included": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations",
"attributes": {
"name": "Acme Construction Ltd",
"slug": "acme-construction",
"sandbox": false,
"description": "Leading construction company specializing in infrastructure projects",
"settings": {
"teams": {
"customer_representatives": [
"b234c567-8901-2345-6789-abcdef012345"
]
}
}
},
"meta": {
"v3": true,
"status": "active",
"created_at": "2023-01-15T10:30:00.000Z",
"updated_at": "2023-02-20T14:45:00.000Z",
"features": [
{
"name": "advanced_reporting",
"enabled": true,
"limit": 1000
}
]
},
"relationships": {
"users": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "users"
}
]
},
"service_accounts": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "service-accounts"
}
]
},
"groups": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "groups"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "teams"
}
]
},
"nomenclature": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "nomenclature"
}
}
}
}
]
}{
"id": "98ca4a78-b66f-4234-9719-aaf832ee6669",
"status": "400",
"title": "A validation error was encountered",
"source": {
"parameter": "include"
},
"meta": {
"resource": "wrong_value"
}
}{
"id": "05fc9c8d-73b9-4697-9337-57f7a567a48f",
"status": "401",
"title": "You are not authorised to access this resource",
"detail": "In order to access this resource, you need the 'admin' role.",
"code": "AUTH.001"
}{
"id": "7b4c8f12-3e9a-4d5b-8c6f-1a2b3c4d5e6f",
"status": "404",
"title": "Resource not found",
"detail": "The requested resource could not be found or does not exist.",
"code": "NOT_FOUND.001"
}{
"id": "8e2f9a34-b5c6-4d7e-9f8a-2b3c4d5e6f7g",
"status": "409",
"title": "Conflict",
"detail": "The request conflicts with the current state of the resource.",
"code": "CONFLICT.001"
}{
"id": "fe9d9a69-f0a7-4fdc-bb2c-176027f316c5",
"status": "500",
"title": "Internal Server Error",
"detail": "An unexpected error occurred on the server."
}Load a file of locations
Load a CSV of locations in bulk.
Upload the file first with POST /v3/uploads, then name the id it returns here together with a
column mapping. The request reads and validates the whole file before returning, so a mapping that
names a column the file does not have, or that names no reference column, is refused now rather
than becoming an import that fails later with nobody watching. The response carries the row count
the import will work through.
The rows are written afterwards, in chunks, and the record’s progress and results are what a
caller polls. Nothing is pushed: GET /v3/location-imports/{location_import_id} until status is
completed or failed.
reference is mandatory in the mapping. It is the identity rows are matched on: a row whose
reference already names a location in the organisation updates it, and one whose reference is new
creates a location. That is what makes re-importing a corrected file idempotent instead of
doubling the population, and it is why a file with no reference column is refused rather than
loaded once.
A row that cannot be read is skipped with a reason and the import still completes. A file of 30,000 poles with four bad coordinates loads 29,996 locations and reports four rows, because making somebody find and fix all four before any of it lands is worse than loading most of it.
Authorised by the locations grants that govern the records it writes: both locations:create
and locations:update, because an import does both and which of the two a given file does is not
knowable until it has been read. There is no import permission of its own.
The bulk path deliberately emits no per-row audit or entity events. This record is the audit trail, and anything that needs to react to a bulk import reacts to the import’s own completion.
curl --request POST \
--url https://api.ctrl-hub.com/v3/location-imports \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Session-Token: <api-key>' \
--data '
{
"data": {
"type": "location-imports",
"attributes": {
"upload_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"column_mapping": {
"reference": "POLE_NO",
"name": "NAME",
"description": "<string>",
"location_type": "ASSET_TYPE",
"latitude": "<string>",
"longitude": "<string>",
"easting": "<string>",
"northing": "<string>",
"address_number": "<string>",
"address_name": "<string>",
"address_thoroughfare": "<string>",
"address_post_town": "<string>",
"address_postcode": "<string>"
}
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
},
"default_location_type": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-types"
}
}
}
}
}
'import requests
url = "https://api.ctrl-hub.com/v3/location-imports"
payload = { "data": {
"type": "location-imports",
"attributes": {
"upload_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"column_mapping": {
"reference": "POLE_NO",
"name": "NAME",
"description": "<string>",
"location_type": "ASSET_TYPE",
"latitude": "<string>",
"longitude": "<string>",
"easting": "<string>",
"northing": "<string>",
"address_number": "<string>",
"address_name": "<string>",
"address_thoroughfare": "<string>",
"address_post_town": "<string>",
"address_postcode": "<string>"
}
},
"relationships": {
"organisation": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
} },
"default_location_type": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-types"
} }
}
} }
headers = {
"X-Session-Token": "<api-key>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Session-Token': '<api-key>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: 'location-imports',
attributes: {
upload_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
column_mapping: {
reference: 'POLE_NO',
name: 'NAME',
description: '<string>',
location_type: 'ASSET_TYPE',
latitude: '<string>',
longitude: '<string>',
easting: '<string>',
northing: '<string>',
address_number: '<string>',
address_name: '<string>',
address_thoroughfare: '<string>',
address_post_town: '<string>',
address_postcode: '<string>'
}
},
relationships: {
organisation: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: 'organisations'}},
default_location_type: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: 'location-types'}}
}
}
})
};
fetch('https://api.ctrl-hub.com/v3/location-imports', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ctrl-hub.com/v3/location-imports",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'type' => 'location-imports',
'attributes' => [
'upload_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'column_mapping' => [
'reference' => 'POLE_NO',
'name' => 'NAME',
'description' => '<string>',
'location_type' => 'ASSET_TYPE',
'latitude' => '<string>',
'longitude' => '<string>',
'easting' => '<string>',
'northing' => '<string>',
'address_number' => '<string>',
'address_name' => '<string>',
'address_thoroughfare' => '<string>',
'address_post_town' => '<string>',
'address_postcode' => '<string>'
]
],
'relationships' => [
'organisation' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => 'organisations'
]
],
'default_location_type' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => 'location-types'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/vnd.api+json",
"X-Session-Token: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ctrl-hub.com/v3/location-imports"
payload := strings.NewReader("{\n \"data\": {\n \"type\": \"location-imports\",\n \"attributes\": {\n \"upload_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"column_mapping\": {\n \"reference\": \"POLE_NO\",\n \"name\": \"NAME\",\n \"description\": \"<string>\",\n \"location_type\": \"ASSET_TYPE\",\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\",\n \"easting\": \"<string>\",\n \"northing\": \"<string>\",\n \"address_number\": \"<string>\",\n \"address_name\": \"<string>\",\n \"address_thoroughfare\": \"<string>\",\n \"address_post_town\": \"<string>\",\n \"address_postcode\": \"<string>\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n },\n \"default_location_type\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"location-types\"\n }\n }\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Session-Token", "<api-key>")
req.Header.Add("Content-Type", "application/vnd.api+json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ctrl-hub.com/v3/location-imports")
.header("X-Session-Token", "<api-key>")
.header("Content-Type", "application/vnd.api+json")
.body("{\n \"data\": {\n \"type\": \"location-imports\",\n \"attributes\": {\n \"upload_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"column_mapping\": {\n \"reference\": \"POLE_NO\",\n \"name\": \"NAME\",\n \"description\": \"<string>\",\n \"location_type\": \"ASSET_TYPE\",\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\",\n \"easting\": \"<string>\",\n \"northing\": \"<string>\",\n \"address_number\": \"<string>\",\n \"address_name\": \"<string>\",\n \"address_thoroughfare\": \"<string>\",\n \"address_post_town\": \"<string>\",\n \"address_postcode\": \"<string>\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n },\n \"default_location_type\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"location-types\"\n }\n }\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ctrl-hub.com/v3/location-imports")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Session-Token"] = '<api-key>'
request["Content-Type"] = 'application/vnd.api+json'
request.body = "{\n \"data\": {\n \"type\": \"location-imports\",\n \"attributes\": {\n \"upload_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"column_mapping\": {\n \"reference\": \"POLE_NO\",\n \"name\": \"NAME\",\n \"description\": \"<string>\",\n \"location_type\": \"ASSET_TYPE\",\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\",\n \"easting\": \"<string>\",\n \"northing\": \"<string>\",\n \"address_number\": \"<string>\",\n \"address_name\": \"<string>\",\n \"address_thoroughfare\": \"<string>\",\n \"address_post_town\": \"<string>\",\n \"address_postcode\": \"<string>\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n },\n \"default_location_type\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"location-types\"\n }\n }\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-imports",
"attributes": {
"status": "processing",
"filename": "enwl-poles-2026-09.csv",
"column_mapping": {
"reference": "POLE_NO",
"name": "NAME",
"description": "<string>",
"location_type": "ASSET_TYPE",
"latitude": "<string>",
"longitude": "<string>",
"easting": "<string>",
"northing": "<string>",
"address_number": "<string>",
"address_name": "<string>",
"address_thoroughfare": "<string>",
"address_post_town": "<string>",
"address_postcode": "<string>"
},
"progress": {
"total_rows": 30000,
"processed_rows": 12500
},
"results": {
"inserted": 29850,
"updated": 146,
"skipped": 4,
"row_error_count": 4
},
"row_errors": [
{
"row": 4512,
"reason": "the latitude \"53.4o8\" is not a number",
"reference": "POLE-004512"
}
],
"error": "<string>"
},
"meta": {
"requested_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z"
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
},
"requester": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "users"
}
},
"default_location_type": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "location-types"
}
}
}
},
"jsonapi": {
"version": "1.0"
},
"included": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations",
"attributes": {
"name": "Acme Construction Ltd",
"slug": "acme-construction",
"sandbox": false,
"description": "Leading construction company specializing in infrastructure projects",
"settings": {
"teams": {
"customer_representatives": [
"b234c567-8901-2345-6789-abcdef012345"
]
}
}
},
"meta": {
"v3": true,
"status": "active",
"created_at": "2023-01-15T10:30:00.000Z",
"updated_at": "2023-02-20T14:45:00.000Z",
"features": [
{
"name": "advanced_reporting",
"enabled": true,
"limit": 1000
}
]
},
"relationships": {
"users": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "users"
}
]
},
"service_accounts": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "service-accounts"
}
]
},
"groups": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "groups"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "teams"
}
]
},
"nomenclature": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "nomenclature"
}
}
}
}
]
}{
"id": "98ca4a78-b66f-4234-9719-aaf832ee6669",
"status": "400",
"title": "A validation error was encountered",
"source": {
"parameter": "include"
},
"meta": {
"resource": "wrong_value"
}
}{
"id": "05fc9c8d-73b9-4697-9337-57f7a567a48f",
"status": "401",
"title": "You are not authorised to access this resource",
"detail": "In order to access this resource, you need the 'admin' role.",
"code": "AUTH.001"
}{
"id": "7b4c8f12-3e9a-4d5b-8c6f-1a2b3c4d5e6f",
"status": "404",
"title": "Resource not found",
"detail": "The requested resource could not be found or does not exist.",
"code": "NOT_FOUND.001"
}{
"id": "8e2f9a34-b5c6-4d7e-9f8a-2b3c4d5e6f7g",
"status": "409",
"title": "Conflict",
"detail": "The request conflicts with the current state of the resource.",
"code": "CONFLICT.001"
}{
"id": "fe9d9a69-f0a7-4fdc-bb2c-176027f316c5",
"status": "500",
"title": "Internal Server Error",
"detail": "An unexpected error occurred on the server."
}Authorizations
Session token for authentication.
Body
The file to load, and how to read it.
The file itself is not sent here. Upload it first with POST /v3/uploads and name the id it
returns as upload_id: a 30,000-row CSV is a binary, and the same two-stage ingest already serves
videos, documents and certificates. The upload is consumed by this request, and the import keeps
its own copy of the bytes, so the hour-long upload expiry cannot outrun a queued import.
The requester is taken from the authenticated principal rather than accepted here, so an import can never be attributed to somebody else.
Show child attributes
Show child attributes
Response
An individual location import.
JSON API response object
One bulk load of locations from an uploaded CSV, and what became of every row.
The record is the import's audit trail, and that is by design rather than by accident: the bulk write path emits no per-row events, because a per-row event for a 30,000-row file would put 30,000 messages on the platform's bus for one upload. So this record answers "who loaded what, and what did it do" on its own.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Related resources that can be included when a location import is returned.
An organisation
- Option 1
- Option 2
- Option 3
Show child attributes
Show child attributes