Add a location
Create a location with the fields publishers need, handle validation errors, and confirm it has been queued for submission.
Listings, reviews, posts, and analytics are all keyed to a location ID.
POST /api/v4/locations creates the location and queues one listing per
publisher in your plan.
1. Gather the required fields
Ten fields are required. A service-area business sends the full address as
well: with hideAddress: true, ListingsAPI stores the address but does not
submit it to publishers. Publishers render omitted optional fields as blank,
so send everything you have.
2. Create the location
POST /api/v4/locations takes the fields in an input object in the JSON
request body. The Python SDK method locations.add() takes the same fields as
keyword arguments and validates the required ones before it sends the request.
The Node SDK method 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 the new location in
data.createLocation.location. Keep both identifiers: id is the base64 value
every later write takes, and databaseId is the numeric value shown in
dashboards and webhook payloads.
{ "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 is PENDING while the location is validated and queued. It advances
without a further API call.
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 } }}Both SDKs raise on failure. Python's locations.add() checks the required
fields locally and raises ValidationError before sending the request. Node's
createLocation() throws ValidationError when the API rejects the input,
which is why the sample above tests no success flag.
The codes you will meet most often:
5. Confirm submission has started
Creating the location queues one listing per publisher in your plan. Each
listing starts at AVAILABLE or IN_PROGRESS and moves to SYNCED with a
listingUrl once the publisher accepts it.
curl https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI5MA==/listings/premium \-H "Authorization: API $LISTINGSAPI_KEY"With webhooks configured, no polling is required. 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 listings, reviews, and posts start syncing.
- Connect Apple Business Connect: publish to Apple Maps through the owner's verified Apple Business account, or through the ListingsAPI account when they have none.
- Check listing status and live links: watch the submissions you just queued.