curl --request POST \
--url https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"address_line_1": "1250 Main St",
"allow_create": true,
"city": "Springfield",
"country": "US",
"country_derived": true,
"extras": {
"branch_code": "595",
"opening_hours_spec": [
{
"closes": "20:00",
"dayOfWeek": "Monday",
"opens": "10:00"
}
],
"services": [
"Salon",
"Brow Bar"
]
},
"first_party": true,
"lat": 39.7817,
"lon": -89.6501,
"name": "Ulta Beauty",
"opening_hours": "Mo-Sa 10:00-20:00; Su 11:00-18:00",
"phone": "+12175550100",
"postal_code": "62704",
"region": "IL",
"source": "ulta_site",
"source_url": "https://www.ulta.com/stores/springfield-il-595",
"store_number": "595",
"website": "https://www.ulta.com/stores/springfield-il-595"
}
'import requests
url = "https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores"
payload = {
"address_line_1": "1250 Main St",
"allow_create": True,
"city": "Springfield",
"country": "US",
"country_derived": True,
"extras": {
"branch_code": "595",
"opening_hours_spec": [
{
"closes": "20:00",
"dayOfWeek": "Monday",
"opens": "10:00"
}
],
"services": ["Salon", "Brow Bar"]
},
"first_party": True,
"lat": 39.7817,
"lon": -89.6501,
"name": "Ulta Beauty",
"opening_hours": "Mo-Sa 10:00-20:00; Su 11:00-18:00",
"phone": "+12175550100",
"postal_code": "62704",
"region": "IL",
"source": "ulta_site",
"source_url": "https://www.ulta.com/stores/springfield-il-595",
"store_number": "595",
"website": "https://www.ulta.com/stores/springfield-il-595"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
address_line_1: '1250 Main St',
allow_create: true,
city: 'Springfield',
country: 'US',
country_derived: true,
extras: {
branch_code: '595',
opening_hours_spec: [{closes: '20:00', dayOfWeek: 'Monday', opens: '10:00'}],
services: ['Salon', 'Brow Bar']
},
first_party: true,
lat: 39.7817,
lon: -89.6501,
name: 'Ulta Beauty',
opening_hours: 'Mo-Sa 10:00-20:00; Su 11:00-18:00',
phone: '+12175550100',
postal_code: '62704',
region: 'IL',
source: 'ulta_site',
source_url: 'https://www.ulta.com/stores/springfield-il-595',
store_number: '595',
website: 'https://www.ulta.com/stores/springfield-il-595'
})
};
fetch('https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores', 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://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores",
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([
'address_line_1' => '1250 Main St',
'allow_create' => true,
'city' => 'Springfield',
'country' => 'US',
'country_derived' => true,
'extras' => [
'branch_code' => '595',
'opening_hours_spec' => [
[
'closes' => '20:00',
'dayOfWeek' => 'Monday',
'opens' => '10:00'
]
],
'services' => [
'Salon',
'Brow Bar'
]
],
'first_party' => true,
'lat' => 39.7817,
'lon' => -89.6501,
'name' => 'Ulta Beauty',
'opening_hours' => 'Mo-Sa 10:00-20:00; Su 11:00-18:00',
'phone' => '+12175550100',
'postal_code' => '62704',
'region' => 'IL',
'source' => 'ulta_site',
'source_url' => 'https://www.ulta.com/stores/springfield-il-595',
'store_number' => '595',
'website' => 'https://www.ulta.com/stores/springfield-il-595'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <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://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores"
payload := strings.NewReader("{\n \"address_line_1\": \"1250 Main St\",\n \"allow_create\": true,\n \"city\": \"Springfield\",\n \"country\": \"US\",\n \"country_derived\": true,\n \"extras\": {\n \"branch_code\": \"595\",\n \"opening_hours_spec\": [\n {\n \"closes\": \"20:00\",\n \"dayOfWeek\": \"Monday\",\n \"opens\": \"10:00\"\n }\n ],\n \"services\": [\n \"Salon\",\n \"Brow Bar\"\n ]\n },\n \"first_party\": true,\n \"lat\": 39.7817,\n \"lon\": -89.6501,\n \"name\": \"Ulta Beauty\",\n \"opening_hours\": \"Mo-Sa 10:00-20:00; Su 11:00-18:00\",\n \"phone\": \"+12175550100\",\n \"postal_code\": \"62704\",\n \"region\": \"IL\",\n \"source\": \"ulta_site\",\n \"source_url\": \"https://www.ulta.com/stores/springfield-il-595\",\n \"store_number\": \"595\",\n \"website\": \"https://www.ulta.com/stores/springfield-il-595\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/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://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"address_line_1\": \"1250 Main St\",\n \"allow_create\": true,\n \"city\": \"Springfield\",\n \"country\": \"US\",\n \"country_derived\": true,\n \"extras\": {\n \"branch_code\": \"595\",\n \"opening_hours_spec\": [\n {\n \"closes\": \"20:00\",\n \"dayOfWeek\": \"Monday\",\n \"opens\": \"10:00\"\n }\n ],\n \"services\": [\n \"Salon\",\n \"Brow Bar\"\n ]\n },\n \"first_party\": true,\n \"lat\": 39.7817,\n \"lon\": -89.6501,\n \"name\": \"Ulta Beauty\",\n \"opening_hours\": \"Mo-Sa 10:00-20:00; Su 11:00-18:00\",\n \"phone\": \"+12175550100\",\n \"postal_code\": \"62704\",\n \"region\": \"IL\",\n \"source\": \"ulta_site\",\n \"source_url\": \"https://www.ulta.com/stores/springfield-il-595\",\n \"store_number\": \"595\",\n \"website\": \"https://www.ulta.com/stores/springfield-il-595\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"address_line_1\": \"1250 Main St\",\n \"allow_create\": true,\n \"city\": \"Springfield\",\n \"country\": \"US\",\n \"country_derived\": true,\n \"extras\": {\n \"branch_code\": \"595\",\n \"opening_hours_spec\": [\n {\n \"closes\": \"20:00\",\n \"dayOfWeek\": \"Monday\",\n \"opens\": \"10:00\"\n }\n ],\n \"services\": [\n \"Salon\",\n \"Brow Bar\"\n ]\n },\n \"first_party\": true,\n \"lat\": 39.7817,\n \"lon\": -89.6501,\n \"name\": \"Ulta Beauty\",\n \"opening_hours\": \"Mo-Sa 10:00-20:00; Su 11:00-18:00\",\n \"phone\": \"+12175550100\",\n \"postal_code\": \"62704\",\n \"region\": \"IL\",\n \"source\": \"ulta_site\",\n \"source_url\": \"https://www.ulta.com/stores/springfield-il-595\",\n \"store_number\": \"595\",\n \"website\": \"https://www.ulta.com/stores/springfield-il-595\"\n}"
response = http.request(request)
puts response.read_body{
"committed": false,
"coverage_after": {
"stores": 1622,
"with_phone": 3,
"with_point": 1622
},
"created": 1,
"enriched": 2,
"errors": 0,
"existing_stores": 1621,
"fields_superseded": 4,
"legacy_keys_preserved": 2,
"matched_address": 0,
"matched_proximity": 2,
"matched_store_number": 0,
"near_misses": 1,
"not_created": 0,
"phones_written": 3,
"rekey_skipped_conflict": 0,
"row_errors": [],
"rows": [
{
"conflict": "",
"distance_m": 18.4,
"error": "",
"index": 0,
"match_method": "proximity",
"outcome": "enriched",
"store_number": "595"
}
],
"submitted_rows": 3,
"unchanged": 0,
"unmatched_existing": 1619,
"urls_written": 3
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Upsert one physical store
Reconcile and apply a single store row for one retailer. Identical to the batch endpoint with one row — the response is the same envelope, with a single entry in rows — so a one-store correction needs no list wrapping.
Rows are reconciled, not inserted. Each row is tied to an existing store by exact store number, then by proximity within proximity_m, then by normalised street plus postal code — one-to-one, highest-confidence tier first. A match enriches the existing store in place; only a row that matches nothing creates one. This is why the endpoint is safe to point at a full dataset that overlaps rows already in the database: an insert-only surface would plant a duplicate beside every store whose recorded key predates the retailer’s own numbering.
Nothing is ever merged, deactivated or deleted here. An existing store no row claims is counted in unmatched_existing and left exactly as it is; a pair the matcher finds contradictory is reported in the row’s conflict and left unrekeyed.
dry_run defaults to true. Send dry_run: false to commit.
retailer_id is a retailers.Retailer. An organization-private retailer requires OWNER or MANAGER on the organization that owns it; a canonical (Closient-curated) retailer requires a staff account, because those rows were previously writable only from a management command. The organization this credential acts for becomes the owning organization of any location record created.
curl --request POST \
--url https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"address_line_1": "1250 Main St",
"allow_create": true,
"city": "Springfield",
"country": "US",
"country_derived": true,
"extras": {
"branch_code": "595",
"opening_hours_spec": [
{
"closes": "20:00",
"dayOfWeek": "Monday",
"opens": "10:00"
}
],
"services": [
"Salon",
"Brow Bar"
]
},
"first_party": true,
"lat": 39.7817,
"lon": -89.6501,
"name": "Ulta Beauty",
"opening_hours": "Mo-Sa 10:00-20:00; Su 11:00-18:00",
"phone": "+12175550100",
"postal_code": "62704",
"region": "IL",
"source": "ulta_site",
"source_url": "https://www.ulta.com/stores/springfield-il-595",
"store_number": "595",
"website": "https://www.ulta.com/stores/springfield-il-595"
}
'import requests
url = "https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores"
payload = {
"address_line_1": "1250 Main St",
"allow_create": True,
"city": "Springfield",
"country": "US",
"country_derived": True,
"extras": {
"branch_code": "595",
"opening_hours_spec": [
{
"closes": "20:00",
"dayOfWeek": "Monday",
"opens": "10:00"
}
],
"services": ["Salon", "Brow Bar"]
},
"first_party": True,
"lat": 39.7817,
"lon": -89.6501,
"name": "Ulta Beauty",
"opening_hours": "Mo-Sa 10:00-20:00; Su 11:00-18:00",
"phone": "+12175550100",
"postal_code": "62704",
"region": "IL",
"source": "ulta_site",
"source_url": "https://www.ulta.com/stores/springfield-il-595",
"store_number": "595",
"website": "https://www.ulta.com/stores/springfield-il-595"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
address_line_1: '1250 Main St',
allow_create: true,
city: 'Springfield',
country: 'US',
country_derived: true,
extras: {
branch_code: '595',
opening_hours_spec: [{closes: '20:00', dayOfWeek: 'Monday', opens: '10:00'}],
services: ['Salon', 'Brow Bar']
},
first_party: true,
lat: 39.7817,
lon: -89.6501,
name: 'Ulta Beauty',
opening_hours: 'Mo-Sa 10:00-20:00; Su 11:00-18:00',
phone: '+12175550100',
postal_code: '62704',
region: 'IL',
source: 'ulta_site',
source_url: 'https://www.ulta.com/stores/springfield-il-595',
store_number: '595',
website: 'https://www.ulta.com/stores/springfield-il-595'
})
};
fetch('https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores', 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://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores",
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([
'address_line_1' => '1250 Main St',
'allow_create' => true,
'city' => 'Springfield',
'country' => 'US',
'country_derived' => true,
'extras' => [
'branch_code' => '595',
'opening_hours_spec' => [
[
'closes' => '20:00',
'dayOfWeek' => 'Monday',
'opens' => '10:00'
]
],
'services' => [
'Salon',
'Brow Bar'
]
],
'first_party' => true,
'lat' => 39.7817,
'lon' => -89.6501,
'name' => 'Ulta Beauty',
'opening_hours' => 'Mo-Sa 10:00-20:00; Su 11:00-18:00',
'phone' => '+12175550100',
'postal_code' => '62704',
'region' => 'IL',
'source' => 'ulta_site',
'source_url' => 'https://www.ulta.com/stores/springfield-il-595',
'store_number' => '595',
'website' => 'https://www.ulta.com/stores/springfield-il-595'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <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://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores"
payload := strings.NewReader("{\n \"address_line_1\": \"1250 Main St\",\n \"allow_create\": true,\n \"city\": \"Springfield\",\n \"country\": \"US\",\n \"country_derived\": true,\n \"extras\": {\n \"branch_code\": \"595\",\n \"opening_hours_spec\": [\n {\n \"closes\": \"20:00\",\n \"dayOfWeek\": \"Monday\",\n \"opens\": \"10:00\"\n }\n ],\n \"services\": [\n \"Salon\",\n \"Brow Bar\"\n ]\n },\n \"first_party\": true,\n \"lat\": 39.7817,\n \"lon\": -89.6501,\n \"name\": \"Ulta Beauty\",\n \"opening_hours\": \"Mo-Sa 10:00-20:00; Su 11:00-18:00\",\n \"phone\": \"+12175550100\",\n \"postal_code\": \"62704\",\n \"region\": \"IL\",\n \"source\": \"ulta_site\",\n \"source_url\": \"https://www.ulta.com/stores/springfield-il-595\",\n \"store_number\": \"595\",\n \"website\": \"https://www.ulta.com/stores/springfield-il-595\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/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://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"address_line_1\": \"1250 Main St\",\n \"allow_create\": true,\n \"city\": \"Springfield\",\n \"country\": \"US\",\n \"country_derived\": true,\n \"extras\": {\n \"branch_code\": \"595\",\n \"opening_hours_spec\": [\n {\n \"closes\": \"20:00\",\n \"dayOfWeek\": \"Monday\",\n \"opens\": \"10:00\"\n }\n ],\n \"services\": [\n \"Salon\",\n \"Brow Bar\"\n ]\n },\n \"first_party\": true,\n \"lat\": 39.7817,\n \"lon\": -89.6501,\n \"name\": \"Ulta Beauty\",\n \"opening_hours\": \"Mo-Sa 10:00-20:00; Su 11:00-18:00\",\n \"phone\": \"+12175550100\",\n \"postal_code\": \"62704\",\n \"region\": \"IL\",\n \"source\": \"ulta_site\",\n \"source_url\": \"https://www.ulta.com/stores/springfield-il-595\",\n \"store_number\": \"595\",\n \"website\": \"https://www.ulta.com/stores/springfield-il-595\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/retailers/api/v1/retailers/{retailer_id}/stores")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"address_line_1\": \"1250 Main St\",\n \"allow_create\": true,\n \"city\": \"Springfield\",\n \"country\": \"US\",\n \"country_derived\": true,\n \"extras\": {\n \"branch_code\": \"595\",\n \"opening_hours_spec\": [\n {\n \"closes\": \"20:00\",\n \"dayOfWeek\": \"Monday\",\n \"opens\": \"10:00\"\n }\n ],\n \"services\": [\n \"Salon\",\n \"Brow Bar\"\n ]\n },\n \"first_party\": true,\n \"lat\": 39.7817,\n \"lon\": -89.6501,\n \"name\": \"Ulta Beauty\",\n \"opening_hours\": \"Mo-Sa 10:00-20:00; Su 11:00-18:00\",\n \"phone\": \"+12175550100\",\n \"postal_code\": \"62704\",\n \"region\": \"IL\",\n \"source\": \"ulta_site\",\n \"source_url\": \"https://www.ulta.com/stores/springfield-il-595\",\n \"store_number\": \"595\",\n \"website\": \"https://www.ulta.com/stores/springfield-il-595\"\n}"
response = http.request(request)
puts response.read_body{
"committed": false,
"coverage_after": {
"stores": 1622,
"with_phone": 3,
"with_point": 1622
},
"created": 1,
"enriched": 2,
"errors": 0,
"existing_stores": 1621,
"fields_superseded": 4,
"legacy_keys_preserved": 2,
"matched_address": 0,
"matched_proximity": 2,
"matched_store_number": 0,
"near_misses": 1,
"not_created": 0,
"phones_written": 3,
"rekey_skipped_conflict": 0,
"row_errors": [],
"rows": [
{
"conflict": "",
"distance_m": 18.4,
"error": "",
"index": 0,
"match_method": "proximity",
"outcome": "enriched",
"store_number": "595"
}
],
"submitted_rows": 3,
"unchanged": 0,
"unmatched_existing": 1619,
"urls_written": 3
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Authorizations
Path Parameters
Unique identifier of the retailer this store belongs to.
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$Body
A single store plus the same reconciliation knobs the batch form takes.
The key this source uses for the store — the retailer's own store number where it publishes one, otherwise a stable synthesized key (e.g. SYN-…). This is the highest-confidence match tier, so a source that can supply a real store number should: it is what makes a repeated call idempotent rather than proximity-matched.
50Stable name of the dataset this row came from (e.g. ulta_site, sephora_csv, osm). Load-bearing, not a label: per-column authorship is recorded against it, and a source may later correct a value it wrote itself but never one another source wrote. Sending a different name on a rerun of the same dataset therefore forfeits that source's own right to update the columns it authored.
1 - 100Store or branch display name.
255Street address, number and street name.
255City, town or locality.
255State, province or region.
255ZIP, postal code or postcode.
20ISO 3166-1 alpha-2 country code for the store. An assigned code: this value is written to the place's country column, and a store filed under a code that names no country is the same class of defect C-5969 found 75 instances of. A bare two-letter string would have admitted 427 unassigned combinations (C-5975).
2^[A-Za-z]{2}$WGS84 latitude in decimal degrees. Null is accepted — a store with a good address and no coordinates still matches on the address tier and is still worth having.
-90 <= x <= 90WGS84 longitude in decimal degrees. Null is accepted; see lat.
-180 <= x <= 180Store phone number; normalised to E.164 on write.
50The store's own page on the retailer's site.
1000Opening hours in OSM opening_hours syntax (e.g. Mo-Sa 10:00-20:00; Su 11:00-18:00). There is no hours column on a location, so this is stored in Place.source_extras under this row's source — sending it here is equivalent to sending extras.opening_hours, and an explicit extras.opening_hours wins. A structured schema.org openingHoursSpecification can be sent alongside it in extras.
1000Where this specific row was read from.
1000True when the row comes from the retailer's own site or feed. Only a first-party row may overwrite an existing non-placeholder value or rename a storefront; community mapping data enriches blanks instead.
Whether a row that matches nothing may create a new store. Set false for a secondary source: it may enrich a store the retailer confirms exists, but a location only a community extract believes in is not evidence enough to seed a storefront customers would be sent to.
True when country came from a coordinate lookup rather than from a feed label or address field. This is a provenance assertion, and it grants the row power: only a derived country may correct a country already stored on the place. A country that came from a label can fill a blank and nothing more.
Set it only when you actually resolved the country from lat/lon. The reason it exists is concrete — Sephora's North America feed labels 482 of its 483 rows US, and trusting that label would have filed 75 Canadian stores as American (C-5969). A label is not evidence; a coordinate is. Asserting this on a label-derived country re-opens exactly that defect, so leave it false when in doubt: the cost is a country that stays wrong until a better row arrives, not one that gets overwritten with a worse value.
Everything this source carries that has no column of its own — raw hours specifications, service lists, OSM tags, source-conflict flags. Stored in Place.source_extras under this row's source. Nesting is allowed here, unlike the flat-string metadata field on other resources.
When true (the default) the write is rolled back. Send false to commit.
Match radius in metres for the proximity tier.
x <= 500ISO 3166-1 alpha-2 region for phone normalisation.
2^[A-Za-z]{2}$Response
OK
Batch census plus the per-row results.
created + enriched + unchanged + not_created + errors equals the
number of submitted rows for any 200 response. The endpoint returns 200
even when individual rows fail: a per-row failure is reported here rather
than aborting the batch, so a single malformed row cannot cost the other
999. Request-level failures (auth, an unwritable retailer, a batch over
the row cap) are 4xx instead.
False when this was a dry run — every path ran and the transaction was rolled back.
Number of rows in the request.
x >= 0Stores this retailer already had, i.e. the size of the candidate match set.
x >= 0Rows that produced a new store.
x >= 0Rows that matched and changed something.
x >= 0Rows that matched and needed no change.
x >= 0Rows that matched nothing and were not allowed to create a store.
x >= 0Rows that raised. Equals the length of row_errors.
x >= 0Rows matched on the exact store-number tier.
x >= 0Rows matched on the proximity tier.
x >= 0Rows matched on the normalised-address tier.
x >= 0Pairs beyond proximity_m but within 500 m that were deliberately NOT matched. A judgement call for a human, never auto-matched by widening the radius.
x >= 0Existing stores no submitted row claimed. For a full-dataset run these are stores the retailer's own list no longer carries, i.e. probably closed — reported, never deactivated or deleted.
x >= 0Phone numbers written or refreshed.
x >= 0Store URLs written or refreshed.
x >= 0Existing non-placeholder values a first-party row overwrote. The previous value is preserved under Place.source_extras['superseded'] rather than discarded.
x >= 0Stores whose pre-existing store number was replaced by this source's real one, with the old key kept in Place.source_extras['legacy_store_key'].
x >= 0Stores left on their existing key because the evidence for re-keying was contradictory.
x >= 0Per-column coverage for this retailer's stores after the call — stores, with_point, with_real_address, with_phone, with_url, with_source_extras. On a dry run these are the post-rollback figures the run would have produced, measured inside the transaction.
Show child attributes
Show child attributes
One result per submitted row, in request order.
Show child attributes
Show child attributes
Batch-level restatement of every row that raised, for callers that read only the census.