Search brand-level company records — one row per brand (not per physical store) — with filters for location, ownership, store count, and more.
Overview
Use this endpoint to find brands in the Openmart database. A brand aggregates all of the physical stores that share the same business identity, so results are deduplicated at the company level.
You can filter by:
free-text search term and location
number of stores, ownership type (INDEPENDENT, FAMILY, FRANCHISE, CHAIN)
whether the brand has staff info, business email, or business phone
website root domain (include or exclude) and social media URLs
Use this endpoint when you want brand-level targeting for outbound, account research, or market sizing — and store-level results fromPOST /api/v1/search would over-count multi-location companies.
Before you start
Make sure you have:
an Openmart account
an API key
a tool to send API requests, such as Postman or curl
Authentication: send your key in the X-API-Key header. Authorization: Bearer <key> is also accepted.
1
Example 1: Search coffee shops in San Francisco, CA
Find brands whose identity matches “coffee shop” in San Francisco, ask for an approximate total, and return the first two results.
Endpoint
POST https://api.openmart.ai/api/v2/brands/search
Parameters
Parameter
search_param.search_term
Type
string
Required
No
Example
"coffee shop"
Description
Free-text relevance term used to rank brand results.
Approximate match count. Present only when the request had estimate_total=true.
Response element
encoded_cursor
Description
Opaque cursor for the NEXT page. Copy it into pagination.encoded_cursor on the next request. Empty string on the last page.
Response element
data[]
Description
One brand per entry.
Response element
data[].brand_id
Description
Stable UUID for the brand.
Response element
data[].business_name
Description
Canonical display name for the brand.
Response element
data[].domain_ident
Description
Normalized root domain; doubles as a stable brand identifier alongside brand_id.
Response element
data[].num_stores
Description
Count of physical stores currently aggregated under this brand.
Response element
data[].ownership_type
Description
One of INDEPENDENT, FAMILY, FRANCHISE, CHAIN, or "" when not classified.
Response element
data[].business_categories
Description
Top-level categories (enum list includes RESTAURANTS_DINING, BEAUTY_PERSONAL_CARE, HEALTH_WELLNESS, SHOPPING_RETAIL, and more).
Response element
data[].social_media_links
Description
Map of platform keys (FACEBOOK, LINKEDIN, INSTAGRAM, TWITTER, X, PINTEREST, TIKTOK, YOUTUBE) to arrays of URLs. Individual platform slices may be null.
Response element
data[].business_emails / business_phones / staffs
Description
Brand-level contact + people data. These array fields may be null (consumers should handle null and empty array equivalently).
Response element
Description
total
Approximate match count. Present only when the request had estimate_total=true.
encoded_cursor
Opaque cursor for the NEXT page. Copy it into pagination.encoded_cursor on the next request. Empty string on the last page.
data[]
One brand per entry.
data[].brand_id
Stable UUID for the brand.
data[].business_name
Canonical display name for the brand.
data[].domain_ident
Normalized root domain; doubles as a stable brand identifier alongside brand_id.
data[].num_stores
Count of physical stores currently aggregated under this brand.
data[].ownership_type
One of INDEPENDENT, FAMILY, FRANCHISE, CHAIN, or "" when not classified.
data[].business_categories
Top-level categories (enum list includes RESTAURANTS_DINING, BEAUTY_PERSONAL_CARE, HEALTH_WELLNESS, SHOPPING_RETAIL, and more).
data[].social_media_links
Map of platform keys (FACEBOOK, LINKEDIN, INSTAGRAM, TWITTER, X, PINTEREST, TIKTOK, YOUTUBE) to arrays of URLs. Individual platform slices may be null.
data[].business_emails / business_phones / staffs
Brand-level contact + people data. These array fields may be null (consumers should handle null and empty array equivalently).
2
Example 2: California coffee brands with 5+ stores, franchise or chain only
Combine a numeric range filter on num_stores with an ownership_type enum filter. This is a typical pattern for brand-level account targeting.
Endpoint
POST https://api.openmart.ai/api/v2/brands/search
Parameters
Parameter
search_param.search_term
Type
string
Required
No
Example
"coffee"
Description
Free-text relevance term.
Parameter
search_param.location
Type
array[object]
Required
No
Example
[{"country":"US","state":"CA"}]
Description
State-wide filter, country required on each entry.
Parameter
search_param.num_stores
Type
array[range]
Required
No
Example
[{"ge":5}]
Description
Store-count range. Each entry is {ge?,gt?,le?,lt?}; multiple entries are OR’d together.
Request body for POST /api/v2/brands/search. All fields are optional in practice — if you omit search_param entirely the server seeds a default location of [{"country":"US"}]. Array filters are capped at 20 entries each.
Most common filters
Start here. These are the fields integrations adjust first when narrowing brand results.
search_param.search_termstringRequired: No
Example: "coffee shop"
Free-text term used for brand relevance ranking. Single string, not a list.
Geographic filter. Up to 20 entries. Each entry must include country; city, state, zipcode, and geo_radius are optional narrowings. If you omit location entirely, the request defaults to [{"country":"US"}].
Opaque cursor copied from the previous response’s encoded_cursor. Omit on the first request. Preview API keys are not allowed to set this.
cURL example
cURL
curl--requestPOST\--urlhttps://api.openmart.ai/api/v2/brands/search\--header'Accept: application/json'\--header'X-API-Key: <your_api_key>'\--header'Content-Type: application/json'\--data'{"search_param":{"location":[{"country":"US"}]},"pagination":{"limit":100,"encoded_cursor":"<paste from prior response>"}}'
pagination.order_byarray[object]Required: No
Example: [{"field":"num_stores","asc":true}]
Optional sort directives. Each entry is {field, asc}. Up to 20 entries. Known limitation: the API currently requires asc to be true and rejects {"asc": false} with a 422 "Asc is required" validator error.
# Search Companies (Brands)
## Endpoint
POST https://api.openmart.ai/api/v2/brands/search
## Description
Brand-level search. One row per brand (not per store). Use this when
store-level search over-counts multi-location companies.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Request body
```json
{
"search_param": {
"search_term": "coffee shop",
"location": [{ "country": "US", "state": "CA", "city": "San Francisco" }],
"num_stores": [{ "ge": 5 }],
"ownership_type": ["FRANCHISE", "CHAIN"],
"has_staff_info": true,
"has_business_email": true,
"has_business_phone_number": true,
"website_url": ["bluebottlecoffee.com"],
"exclude_website_url": ["yelp.com"],
"social_media_link": ["https://www.instagram.com/bluebottle/"]
},
"pagination": {
"limit": 100,
"encoded_cursor": "<copy from prior response>",
"order_by": [{ "field": "num_stores", "asc": false }]
},
"estimate_total": false
}
```
### Notes
- `search_param` is optional in practice. Omitting it defaults the
location filter to `[{"country": "US"}]`.
- Each entry of `search_param.location` MUST include `country`,
otherwise the API returns HTTP 422 "Country is required".
- `search_param.num_stores` is an array of range objects; each entry
is any subset of `{ge, gt, le, lt}`.
- `ownership_type` values: `INDEPENDENT`, `FAMILY`, `FRANCHISE`, `CHAIN`.
- `has_staff_info`, `has_business_email`, `has_business_phone_number`
are tri-state: `true` = must have, `false` = must not, omit = no filter.
- Array filters are capped at 20 entries.
- `pagination.limit` defaults to 100, max 500. Preview API keys must
use `limit <= 100` and cannot set `encoded_cursor`.
- `pagination.order_by[].asc` currently MUST be `true`; sending
`false` returns 422 "Asc is required" because the server-side
`required` validator treats the zero value as missing.
- `estimate_total`: when `true`, the response includes an approximate
`total`; when `false` or omitted, `total` is omitted from the response.
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v2/brands/search" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"search_param": {
"search_term": "coffee shop",
"location": [{ "country": "US", "state": "CA", "city": "San Francisco" }]
},
"pagination": { "limit": 2 },
"estimate_total": true
}'
```
## Example Response
```json
{
"total": 87,
"encoded_cursor": "7b225f73636f7265223a3439363938...",
"data": [
{
"brand_id": "02c6be6a-d0a4-4345-9625-19442df5c8c9",
"business_name": "Cable Car Coffee SF",
"business_type": "Coffee Shop",
"business_categories": ["RESTAURANTS_DINING"],
"business_specialty": "Warm brews",
"business_keywords": ["coffee", "brews", "SF"],
"product_services_offered": ["coffee", "warm brews"],
"brand_description": "Cable Car Coffee SF is a coffee shop specializing in warm brews located in San Francisco.",
"website_url": "https://cablecarcoffeesf.com/",
"business_emails": null,
"business_phones": null,
"social_media_links": {
"FACEBOOK": null, "LINKEDIN": null, "INSTAGRAM": null,
"TWITTER": null, "X": null, "PINTEREST": null,
"TIKTOK": null, "YOUTUBE": null
},
"ownership_type": "",
"staffs": null,
"domain_ident": "cablecarcoffeesf.com",
"num_stores": 1
}
]
}
```
### Response fields
- `total`: approximate count; present only when `estimate_total=true`.
- `encoded_cursor`: opaque cursor for the NEXT page. Pass it back in
`pagination.encoded_cursor`. Empty string on the last page.
- `data[]`: one brand per entry. Each has:
- `brand_id` (UUID), `business_name`, `business_type`
- `business_categories` (array; enum values include
`RESTAURANTS_DINING`, `BEAUTY_PERSONAL_CARE`, `HEALTH_WELLNESS`,
`SHOPPING_RETAIL`, `FITNESS_RECREATION`, and more)
- `business_specialty`, `business_keywords`, `product_services_offered`
- `brand_description`, `website_url`
- `business_emails`, `business_phones`, `staffs` — arrays that may be
`null` (consumers should treat `null` and `[]` equivalently)
- `social_media_links`: map of `FACEBOOK`, `LINKEDIN`, `INSTAGRAM`,
`TWITTER`, `X`, `PINTEREST`, `TIKTOK`, `YOUTUBE` to arrays of URLs
(individual slices may be `null`)
- `ownership_type`: `INDEPENDENT`, `FAMILY`, `FRANCHISE`, `CHAIN`, or
`""` when not classified
- `domain_ident`: normalized root domain (stable brand domain identifier)
- `num_stores`: count of physical stores for this brand
## Errors
- 401 — missing or invalid API key
- 402 — credit limit reached
- 403 — banned user, or preview token used with disallowed params / path
- 422 — JSON / validation failure (e.g. `limit > 500`, missing `country`
in a location entry)