Create a key
An account owner creates API keys in Settings โ API & developer tools. Give the key a name describing what will use it, and decide whether it may write.
The key is shown once, at creation. Handled stores only a hash of it, so it cannot be displayed again โ if it is lost, revoke it and create another.
The API is available on the Pro and Business plans.
Authentication
Send the key as a bearer token. Requests without one, or with a revoked one, return 401.
curl -H "Authorization: Bearer $HANDLED_KEY" \
"https://app.handledlocal.com/api/v1/locations?limit=5"Rate limits are per key: 120 reads and 30 writes per minute. Exceeding either returns 429.
Endpoints
GET /api/v1/locationslists locations, newest first. Acceptslimit(max 200),offset,visibilityandsearch. Returns apaginationobject withtotalandhasMore.GET /api/v1/locations/:idreturns one location.POST /api/v1/locationscreates one.nameis required.PATCH /api/v1/locations/:idupdates one. Only the fields you send change.DELETE /api/v1/locations/:idremoves one from the locator. This is a soft delete, matching the dashboard: analytics history for that location survives.
curl -X POST "https://app.handledlocal.com/api/v1/locations" \
-H "Authorization: Bearer $HANDLED_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Katy Freeway Store",
"address": "1000 Katy Fwy, Houston, TX 77024",
"phone": "+1 713 555 0100",
"hours": { "1": { "open": "09:00", "close": "17:00" }, "7": null },
"customFields": { "Manager": "Dana" }
}'Send an address without lat and lng and Handled geocodes it for you, filling in city, state, postcode and country. If the lookup fails the location is still created, marked so it appears in the dashboard's list of locations needing attention โ the same place a failed CSV row lands.
Absent is not null
On a PATCH, leaving a field out means "leave it alone" and sending null means "clear it". They are different instructions, which is what makes it safe for two systems to update different fields of the same location.
curl -X PATCH "https://app.handledlocal.com/api/v1/locations/$ID" \
-H "Authorization: Bearer $HANDLED_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "+1 713 555 0199" }'Query API
GET /api/v1/query answers "what is near this point", for building your own store-finder page or a mobile app. Results come back nearest-first with a distance, ranked by the same function the widget itself uses, so your page and your locator agree.
curl -H "Authorization: Bearer $HANDLED_KEY" \
"https://app.handledlocal.com/api/v1/query?near=29.76,-95.36&radius=25&units=mi&limit=5"Accepts near (as lat,lng), radius, units (km or mi), tag, q and limit. Without near it returns locations in the locator's own order, highest priority first.
Hidden locations stay hidden unless you pass includeHidden=true, so a location you paused in the dashboard cannot reappear through a page built on this endpoint. Online stockists have no coordinates and are therefore left out of distance queries.
Errors
Failures return a JSON body of the form { "error": { "code": "...", "message": "..." } }.
401 missing_key/invalid_keyโ no bearer token, or one that is not valid or has been revoked.403 plan_requiredโ the account is not on a plan that includes the API.403 read_only_keyโ a write was attempted with a read-only key.403 location_limit_reachedโ creating this location would exceed the plan's allowance. Includeslimitandcurrent.422 validation_failedโ includes afieldsarray naming each field and what was wrong with it.429 rate_limitedโ too many requests for this key this minute.
What this API does not do
There are no webhooks: nothing calls your systems when a location changes in Handled, so keep the schedule on your side. Categories are created in the dashboard rather than through the API โ tag filters against ones that already exist. Widget settings, branding and labels are not exposed here.