AI Entity Match
Decides whether a business an AI named is the business you are tracking. Takes an answer's businesses plus a target and returns matched, confidence, and which signal decided it.
When to use this
The hardest part of AI visibility work is deciding whether "Cellino Plumbing, Heating, Cooling & Electric" is your client. Matching on the domain misses about a third of appearances — that is how often ChatGPT names a business with no website. Matching on the name fails on Google AI Mode, which labels cards editorially. This resolves your business against the local graph first, then matches on CID, domain, phone, name-with-address or name, and tells you which.
POST
/v1/ai/matchCost: 5 credits when the target is resolved against the business graph, 1 credit when you supply a cid, domain, website or phone yourself.
Rate Limit: Varies by plan
Response: ~5-15 seconds with the target lookup; immediate without it
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| target.business_name | string | Yes | The business being tracked |
| target.location | string | No | City and state (e.g. "Buffalo, NY"). With this, the business is looked up and matched on its real identifiers rather than on its name. |
| target.cid | string | No | Google CID in decimal, if you hold one. Strongest possible signal, and skips the lookup. |
| target.place_id | string | No | Google place_id, used to resolve the business exactly rather than by name. |
| target.domain | string | No | The business's domain. Skips the lookup. |
| target.website | string | No | The business's website URL. Skips the lookup. |
| target.phone | string | No | The business's phone number, in any format. Skips the lookup. |
| target.address | string | No | Street address. Strengthens a name match when nothing else is available. |
| businesses | array | No | One answer's businesses, exactly as /v1/ai/scraper, /v1/serp/ai-mode or a single /v1/ai/sample run returns them. Extra fields are ignored. Max 100. |
| runs | array | No | The runs array from a /v1/ai/sample result, to get a rate across the whole sample instead of one verdict. Max 25. Pass this or businesses, never both. |
| resolve | boolean | No | Force the profile lookup on or off. Default: on when there is a location and no identifier was supplied. |
Example Request
curl -X POST https://api.localseodata.com/v1/ai/match \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"target": { "business_name": "Cellino Plumbing", "location": "Buffalo, NY" },
"businesses": [
{ "rank": 1, "name": "Roto-Rooter", "domain": "rotorooter.com" },
{ "rank": 2, "name": "The Classic Staple", "phone": "716-631-8080" }
]
}'Example Response
JSON
{
"status": "success",
"credits_used": 5,
"data": {
"target": {
"business_name": "Cellino Plumbing",
"resolved_from": "business_profile",
"cid": "12345678901234567",
"domain": "",
"website": "https://www.cellino.com",
"phone": "+1 716-631-8080",
"address": "3 Coventry Green, Buffalo, NY 14221"
},
"matched": true,
"confidence": 0.9,
"matched_on": "phone",
"rank": 2,
"match": {
"rank": 2,
"name": "The Classic Staple",
"phone": "716-631-8080"
},
"candidates": [
{ "name": "The Classic Staple", "score": 0.9, "matched_on": "phone", "rank": 2 }
]
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| target.resolved_from | string | "business_profile" means the identifiers below came from a profile lookup, "not_found" that the lookup ran and found nothing, "request" that none was made |
| matched | boolean | Whether the target was found in the answer |
| confidence | float | 0-1. The signal's strength, reduced when two candidates tied on a name-only match. matched is true exactly when this is 0.5 or above |
| matched_on | string | "cid", "domain", "phone", "name_address", "name" or "none" — which signal decided it |
| rank | integer | Position in the answer, when the matched business carried one |
| match | object | The business that matched, exactly as it arrived |
| candidates | array | Everything that scored above zero, best first — the near misses, not just the verdict |
Notes
- Matching on the domain alone misses roughly a third of appearances: that is how often ChatGPT names a business with an empty website and domain. Matching on the name alone fails on AI Mode, where Google labels cards editorially — the same business came back as "The Classic Staple" in one answer and under its trading name in the next.
- Filter on matched_on rather than on confidence when you need identifier-grade certainty. A name match at 0.65 and a domain match at 0.9 are different kinds of answer, not the same answer at different strengths.
- A website on a host many businesses share — Facebook, Instagram, Linktree, business.site, the big directories — is not a domain match. A Facebook page is a very common website for a small local business, and matching on the host alone would pair a client with the first rival in the answer who also has one.
- A name matches only when the shorter of the two is wholly contained in the longer, and a one-word name never matches on its own. "Bolt Plumbing LLC" matches "Bolt Plumbing"; "Smith & Sons Plumbing" does not match "Smith & Sons Roofing"; "Buffalo" is left to an identifier.
- target.place_id requires target.location alongside it — the lookup resolves the location before it uses the place_id.
- Pass runs from a /v1/ai/sample result instead of businesses to get appearance_rate, best_rank, worst_rank and mean_rank for your business across the whole sample.
- Supplying a cid, domain, website or phone yourself skips the lookup and drops the price to 1 credit.