If your GoHighLevel API v2 request just blew up with a 422 Unprocessable Entity or returned an empty array despite a valid bearer token, you’re almost certainly tripping over the locationId.
API v2 handles sub-account scoping very differently than v1 did. Here is where to pull the Location ID from the UI and API, and how to pass it properly across headers, query strings, and request payloads.

What the Location ID Actually Does in API v2
Back in HighLevel API v1, you generated a single API key directly inside a sub-account’s settings. That key was permanently pinned to that specific sub-account—you couldn’t query anything else.
API v2 moved to Agency-level and OAuth-level auth. A single Agency bearer token might have access to hundreds of client sub-accounts. Because the token itself isn’t tied to one workspace, you have to tell HighLevel which sub-account sandbox you want to touch on every call.
That sandbox key is the Location ID—a 20-to-22 character alphanumeric string (like ve9AqPMhyLnn7dau0V7Z). If you omit it, misspell the casing, or hand it a token that lacks permission for that location, the API shuts the door immediately.
Method 1: Grab the Location ID from the Web App URL
If you just need an ID for a quick Postman test, grab it straight out of your browser’s address bar.
- Log in to your HighLevel dashboard.
- Switch into the target sub-account using the top-left account switcher.
- Look at the URL in your browser.
It looks like this:
https://app.gohighlevel.com/v2/location/ve9AqPMhyLnn7dau0V7Z/dashboardThat string right between /location/ and the next slash is your Location ID. If you need more ways to locate it across different agency views, check out our guide on finding sub-account location IDs across the app and URL.
Method 2: Find the Location ID via Company Settings
If you’re managing multiple sub-accounts from an agency admin seat, jumping into each workspace individually gets tedious fast. You can grab IDs in bulk from the agency dashboard:
- Head to Agency View.
- Click Sub-Accounts in the sidebar.
- Find the target sub-account.
- Click the sub-account name or gear icon to open Settings > Business Profile.
Under General Info, you’ll find the Location ID field with a one-click copy button. Make sure your team has the right sub-account user roles and permissions if they’re unable to see agency settings.
Method 3: Fetch Location IDs Programmatically with API v2
Building a sync service or dynamic onboarding pipeline? You should be fetching Location IDs programmatically using an Agency-level token against the /locations/search endpoint.
You’ll need a Private Integration token generated at the Agency level with the locations.readonly scope enabled. Double-check the HighLevel API v2 Documentation if you need to review required scopes.
Here’s a straightforward Node.js script using native fetch to pull the first 10 locations on your agency account:
const searchLocations = async () => { const agencyToken = process.env.GHL_AGENCY_TOKEN; const companyId = process.env.GHL_COMPANY_ID; const url = new URL('https://services.leadconnectorhq.com/locations/search'); url.searchParams.append('companyId', companyId); url.searchParams.append('limit', '10'); const response = await fetch(url.toString(), { method: 'GET', headers: { 'Authorization': `Bearer ${agencyToken}`, 'Version': '2021-07-28', 'Accept': 'application/json' } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to fetch locations: ${response.status} - ${errorText}`); } const data = await response.json(); data.locations.forEach(loc => { console.log(`Name: ${loc.name} | Location ID: ${loc.id}`); });
}; searchLocations();When I ran this against a live agency with 42 sub-accounts, the query came back in about 380ms with clean objects containing both id and name attributes.
How to Pass Location ID in API v2 Calls
This is where most integrations break. HighLevel API v2 isn’t completely uniform: some endpoints expect locationId in query params, while others demand it in the JSON body.
1. In GET Requests (Query Parameters)
Read endpoints (like fetching contacts, pipelines, or calendars) require locationId as a URL query param.
Here’s a cURL call pulling contacts for a specific location:
curl -X GET "https://services.leadconnectorhq.com/contacts/?locationId=ve9AqPMhyLnn7dau0V7Z&limit=20" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Version: 2021-07-28" -H "Accept: application/json"Pay attention to the Version: 2021-07-28 header. HighLevel API v2 requires this exact version header on every request. Skip it, and you’ll get hit with validation errors even if your token and Location ID are 100% correct.
2. In POST/PUT Requests (JSON Body)
Write endpoints (creating contacts, booking appointments, setting custom field values) expect the locationId inside the JSON body payload.
const createContact = async (locationId, contactData) => { const token = process.env.GHL_ACCESS_TOKEN; const response = await fetch('https://services.leadconnectorhq.com/contacts/', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Version': '2021-07-28', 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ locationId: locationId, firstName: contactData.firstName, lastName: contactData.lastName, email: contactData.email, phone: contactData.phone }) }); const result = await response.json(); return result;
};Troubleshooting Common Location ID Errors
These are the two errors I run into most often when debugging HighLevel integrations.
Error 1: 422 Unprocessable Entity (Location ID is Required)
Your payload looks fine, your auth token works, but the API spits this back:
{ "statusCode": 422, "message": "locationId is required", "error": "Unprocessable Entity"
}Two common culprits here: you sent location_id (snake_case) instead of locationId (camelCase), or you tacked the ID onto the URL as a query param on an endpoint that only inspects the JSON body. Always use camelCase (locationId) for core v2 endpoints.
Error 2: 401 / 403 Forbidden (Token Not Associated with Location)
If you get a 403 Forbidden or an Invalid Location Context error, your token is active, but it has no authority over that specific sub-account. This happens when you create a Location-Level token inside Sub-Account A, then try using it to read data from Sub-Account B.
Use an Agency-level token with company-wide scopes for multi-tenant scripts, or generate separate location tokens inside each target workspace.
Using Location IDs in Automation Workflows
If you’re triggering outbound webhooks from HighLevel workflows into your own backend or serverless functions, don’t hardcode static Location IDs. HighLevel provides workflow merge tags for this.
In your Custom Webhook action, drop {{location.id}} into your query string, headers, or body payload. If you’re building out authenticated webhook receivers, check out our guide on sending authenticated webhooks with custom headers in GoHighLevel workflows.
If payloads aren’t landing during testing, take a look at how to fix workflow webhooks not firing to trace the execution history.
Frequently Asked Questions
Can a Location ID ever change for an existing sub-account?
No. It’s a permanent identifier assigned at creation. Renaming the business, changing custom domains, or moving addresses won’t change the Location ID.
Is the Location ID case-sensitive?
Yes. Strings like ve9AqPMhyLnn7dau0V7Z must preserve exact casing. If your ORM, database column, or sanitization script coerces strings to lowercase, HighLevel will return 404s or 422s.
What is the difference between Company ID and Location ID?
companyId identifies the top-level Agency account. locationId identifies an individual Sub-Account under that agency. Agency-level management endpoints (like snapshot distribution or sub-account creation) use companyId, while day-to-day data endpoints (contacts, conversations, pipelines) use locationId.
Can I look up a Location ID by client phone number or domain?
Not via a single filtered endpoint. You’ll need to query /locations/search with your Agency token and filter through the response list on your end by business name, email, or domain.
Next Steps
With your Location ID handling sorted, you can safely build out multi-tenant automations. If you manage templates across client accounts, take a look at how to push snapshot updates to existing sub-accounts in GoHighLevel to keep configurations in sync.

