Add a location
Create a location with the fields publishers need, handle validation errors, and confirm it has been queued for submission.
A location is the record every listing, review, post, and analytics figure attaches to. Creating one queues it for submission to every publisher in your plan, so a complete, accurate record on day one saves a round of corrections later.
1. Gather the required fields
Five fields are mandatory. The rest are optional but each one you leave out is a field publishers show as blank.
2. Create the location
The REST body wraps every field in an input object. The Python SDK's
locations.add() takes the same fields as keyword arguments and validates the
mandatory ones before making the call. The Node SDK's createLocation()
takes the camelCase object directly.
curl -X POST https://listingsapi.com/api/v4/locations \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "name": "Acme Kitchen", "storeId": "ACME-NYC-001", "description": "Acme Kitchen is a family-owned neighborhood restaurant in downtown New York serving wood-fired pizza, hand-rolled pasta, and a short seasonal menu built around produce from nearby farms. Open for lunch and dinner seven days a week, with takeout and delivery available.", "street": "123 Jump Street", "city": "New York", "stateIso": "NY", "postalCode": "10013", "countryIso": "US", "phone": "6443859313", "bizUrl": "https://acmekitchen.example.com", "subCategoryId": 1432, "businessHours": [ { "day": "MONDAY", "type": "OPEN", "slots": [{ "start": "11:00am", "end": "10:00pm" }] }, { "day": "TUESDAY", "type": "OPEN", "slots": [{ "start": "11:00am", "end": "10:00pm" }] }, { "day": "WEDNESDAY", "type": "OPEN", "slots": [{ "start": "11:00am", "end": "10:00pm" }] }, { "day": "THURSDAY", "type": "OPEN", "slots": [{ "start": "11:00am", "end": "10:00pm" }] }, { "day": "FRIDAY", "type": "OPEN", "slots": [{ "start": "11:00am", "end": "11:00pm" }] }, { "day": "SATURDAY", "type": "OPEN", "slots": [{ "start": "12:00pm", "end": "11:00pm" }] }, { "day": "SUNDAY", "type": "CLOSED", "slots": [] } ] }}'3. Read the response
A successful create returns success: true and a summary of the new
location. Keep both ids: the base64 id is what every later write needs, and
databaseId is the plain number you will see in dashboards and webhooks.
{ "data": { "createLocation": { "success": true, "errors": null, "location": { "id": "TG9jYXRpb246MTgwMDI5MA==", "databaseId": 1800290, "storeId": "ACME-NYC-001", "name": "Acme Kitchen", "city": "New York", "stateIso": "NY", "countryIso": "US", "status": "PENDING" } } }}status starts as PENDING while the record is validated and queued. It
moves to approved on its own; you do not have to act on it.
4. Handle validation errors
A create can fail in two places. A malformed request or a bad key returns a
4xx with a top-level errors array. A well-formed request with a field the
API rejects returns 200 with success: false and the problem inside
data.createLocation.errors, so check the body of every write, not just the
status code.
{ "data": { "createLocation": { "success": false, "errors": [ { "code": "SY10005", "message": "SY10005: description must be at least 200 characters", "path": ["input", "description"] } ], "location": null } }}The SDKs turn both cases into an exception. Python's locations.add() checks
the mandatory fields locally and raises ValidationError before any network
call, so a short description never leaves your machine. Node's
createLocation() throws ValidationError when the API rejects the input,
which is why there is no success flag to test in that sample.
The codes you will meet most often:
5. Confirm submission has started
Creating the location queues one listing per publisher in your plan. Read
them back and you will see each start at AVAILABLE or IN_PROGRESS, then
move to SYNCED with a listingUrl as publishers accept it.
curl https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI5MA==/listings/premium \-H "Authorization: API $LISTINGSAPI_KEY"If you have webhooks configured you do not need to poll. A
profile.created event fires when the
record exists, and a
listing.submission event fires
for each publisher as its status changes.
Next steps
- Update a location: change hours, mark a temporary closure, add Google categories.
- Upload location photos: logo, cover, and gallery images.
- Connect Google and import locations: link the Google Business Profile so Google, Apple, and reviews start flowing.
- Check listing status and live links: watch the submissions you just queued.