Learn what Openmart is, what the Openmart API gives you, and where to go next depending on whether you want to get started fast or understand business discovery in more detail.
Openmart is a local business database that helps teams find and work with business data more efficiently. It gives users access to structured business records, search tools, and company information for prospecting, enrichment, CRM workflows, and internal tools.
Whether you are building lead lists, researching local businesses, or powering outbound workflows, Openmart helps you go from search to action faster.
The Openmart API gives you programmatic access to Openmart's local business database and search capabilities. You can use it to search for businesses, retrieve business records, and power workflows inside your own product, CRM, or internal systems.
Use cases for the Openmart API include:
Search businesses by keyword, category, location, website, and other filters.
Find employees at target companies for outbound and enrichment workflows.
Detect a company's tech stack for prospecting, account research, and qualification.
# Openmart API Overview
## What is Openmart?
Openmart is a local business database that helps teams find and work with business data more efficiently. It gives users access to structured business records, search tools, and company information for prospecting, enrichment, CRM workflows, and internal tools.
## Introduction to the Openmart API
Base URL: https://api.openmart.ai
Authentication: Pass your API key in the `X-API-Key` header on every request.
The Openmart API gives you programmatic access to Openmart's local business database and search capabilities. You can use it to search for businesses, retrieve business records, and power workflows inside your own product, CRM, or internal systems.
## Use cases
- **Search businesses** – Search businesses by keyword, category, location, website, and other filters.
- **Find employees** – Find employees at target companies for outbound and enrichment workflows.
- **Detect tech stack** – Detect a company's tech stack for prospecting, account research, and qualification.
## Endpoints at a glance
| Method | Path | Description | Async |
|--------|------|-------------|-------|
| POST | /api/v1/search | Search businesses | No |
| POST | /api/v1/search/only_ids | Search business IDs (fast) | No |
| GET | /api/v1/business_records/list/openmart_id | Get business by Openmart ID | No |
| GET | /api/v1/business_records/list/google_place_id | Get business by Google Place ID | No |
| POST | /api/v1/enrich_company | Enrich company | No |
| POST | /api/v1/task/batch/find_people | Find employees | Yes |
| POST | /api/v1/task/batch/find_tech | Detect tech stack | Yes |
| POST | /api/v1/task/batch/lookup_business_email | Find company emails | Yes |
| POST | /api/v1/task/batch/lookup_people | Enrich known people | Yes |
| POST | /api/v2/brands/search | Search companies (brands) | No |
| GET | /api/v2/credit-balance | Get credit balance | No |
| POST | /api/v2/deny-rules | Create deny rules | No |
| POST | /api/v2/deny-rules/check | Check deny rules | No |
| DELETE | /api/v2/deny-rules | Delete deny rules | No |
| GET | /api/v1/task/batch/:batch_id/status | Check batch status | – |
| GET | /api/v1/task/batch/:batch_id/task_ids | Get task IDs in a batch | – |
| GET | /api/v1/task/:task_id | Get task results | – |
---
# Quickstart
Make your first Openmart API call.
## Prerequisites
- An Openmart account
- An Openmart API key
- A tool to send API requests, such as Postman or curl
## Step 1 – Create an API key
1. Sign in to your Openmart account
2. Go to the API management page
3. Create a new API token
4. Copy and save the key somewhere secure
Keep your API key private. Do not share it in client-side code or public repos.
## Step 2 – Call the API
```bash
curl -X POST "https://api.openmart.ai/api/v1/search" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"query": "dentists in San Jose",
"location": [{"city": "San Jose", "state": "CA", "country": "US"}],
"limit": 10
}'
```
## Step 3 – Inspect the response
```json
{
"results": [
{
"openmart_id": "om_12345",
"name": "Bright Smile Dental",
"website": "https://brightsmiledental.com",
"city": "San Jose",
"state": "CA",
"category": "Dentist"
}
]
}
```
## Async workflow (for find_people, find_tech, lookup_business_email, lookup_people)
1. **Submit a task** → receive a `batch_id`
2. **Poll batch status** → GET /api/v1/task/batch/:batch_id/status until `batch_ready` is true
3. **Get task IDs** → GET /api/v1/task/batch/:batch_id/task_ids?status=COMPLETED
4. **Get task results** → GET /api/v1/task/:task_id
---
# Search Businesses
## Endpoint
POST https://api.openmart.ai/api/v1/search
## Description
Search and retrieve Openmart business records by keyword, location, and business attributes. Use this endpoint to build lead lists, find target businesses, or pull business data into your own workflow.
## Authentication
Header: `X-API-Key: <your_api_key>`
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v1/search" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"query": "hair salons",
"location": [{"country": "USA", "state": "CA", "city": "San Francisco"}],
"has_website": true,
"has_valid_website": true,
"has_contact_info": true
}'
```
## Parameters
### Most common parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| query | string | No | Primary free-text search (1–500 chars). Ignored when tags is non-empty. |
| limit | integer | No | Page size: 1–1000. Recommended 100. Preview keys must be ≤100. |
| location | array[object] | No | Geographic filters. Array of Location objects. |
| has_website | boolean | No | Only businesses that have any website URL. |
| has_valid_website | boolean | No | Only businesses with a validated website URL. |
| has_contact_info | boolean | No | Only businesses that have contact-related signals. |
| tags | array[string] | No | Search by tag labels (up to 100). If non-empty, tag-based matching replaces query. |
| store_name | string | No | Filter or boost by store name. |
| min_locations | integer | No | Minimum number of locations for the brand. |
### Location object fields
| Name | Type | Required | Description |
|------|------|----------|-------------|
| country | string | No | Country code or name. Defaults to US. |
| state | string | No | State or region name. |
| city | string | No | City name filter. |
| zip_code | array[string] | No | One or more postal/ZIP codes. |
| lat | number | No | Latitude (WGS84), paired with long for radius search. |
| long | number | No | Longitude (WGS84), paired with lat for radius search. |
| geo_radius | integer | No | Radius in meters around lat/long. |
| use_geo_fuzz | boolean | No | If true, prefer radius/geo behavior over city/state/zip. |
### Business quality and scale filters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| min_overall_rating | number | No | Minimum Google-style overall rating (0–5). |
| max_overall_rating | number | No | Maximum Google-style overall rating (0–5). |
| min_total_reviews | integer | No | Minimum total review count. |
| max_total_reviews | integer | No | Maximum total review count. |
| min_price_tier | integer | No | Minimum price tier. |
| max_price_tier | integer | No | Maximum price tier. |
| max_locations | integer | No | Maximum number of locations for the brand. |
| ownership_type | string | No | Filter by ownership classification. |
### Keyword and domain filters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| include_keywords | array[string] | No | Businesses whose text should mention these terms (up to 64). |
| exclude_keywords | array[string] | No | Businesses whose text must not mention these terms (up to 64). |
| exclude_root_domains | array[string] | No | Exclude businesses with these root domains. |
### Time-based filters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| open_date_after | string | No | Only businesses opened on or after this ISO 8601 date. |
| open_date_before | string | No | Only businesses opened on or before this ISO 8601 date. |
| info_updated_after | string | No | Lower bound on last info refresh time. |
| info_updated_before | string | No | Upper bound on last info refresh time. |
### Pagination and response shape
| Name | Type | Required | Description |
|------|------|----------|-------------|
| cursor | array | No | Opaque pagination token: [match_score, store_id]. Omit for first page, reuse last result's cursor for next page. |
| estimate_total | boolean | No | If true, response wraps as {data, total_count}. |
## Example Response
```json
[
{
"id": "54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04",
"content": {
"business_name": "Curls are Fun",
"store_name": "Curls Are Fun",
"root_domain": "antonioberducci.com",
"website_url": "http://www.antonioberducci.com/",
"city": "San Francisco",
"state": "California",
"country": "US",
"street_address": "300 Divisadero St",
"zipcode": "94117",
"store_phones": ["+14156264782"],
"google_rating": 5,
"google_reviews_count": 1,
"tags": ["beauty salon", "hair salon", "hair care service"],
"business_categories": ["BEAUTY_PERSONAL_CARE"],
"num_stores": 4,
"latitude": 37.7723988,
"longitude": -122.4370998
},
"match_score": 24.264505,
"match_highlights": ["hair salon", "hair care service", "hairdresser"],
"cursor": [24.264505, "54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04"]
}
]
```
---
# Search Business IDs (Fast)
## Endpoint
POST https://api.openmart.ai/api/v1/search/only_ids
## Description
Lightweight search that returns IDs and cursors first, then you can fetch full business records with the detail endpoint. Uses the same request body schema as POST /api/v1/search.
## Authentication
Header: `X-API-Key: <your_api_key>`
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v1/search/only_ids" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"query": "hair salons",
"location": [{"country": "USA", "state": "CA", "city": "San Francisco"}],
"limit": 20
}'
```
## Example Response
```json
[
{
"id": "f7f7f5b7-1111-2222-3333-123456789abc",
"place_id": "ChIJ123abcXYZ",
"match_score": 0.93,
"cursor": [0.93, "f7f7f5b7-1111-2222-3333-123456789abc"]
}
]
```
Use the returned `id` values with GET /api/v1/business_records/list/openmart_id to fetch full records.
---
# Get Business by Openmart ID
## Endpoint
GET https://api.openmart.ai/api/v1/business_records/list/openmart_id
## Description
Hydrate 1–100 previously-known Openmart IDs into full business records
in one call. Response is keyed by input ID; IDs with no matching record
are silently omitted.
This is an HTTP GET that requires a JSON body — some clients / proxies
drop GET bodies, so verify your tooling forwards them.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Request body
Raw JSON array of 1–100 openmart_id strings (UUID v4):
```json
["54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04","3f77d0ec-15c3-40d4-8a48-b74d7c009822"]
```
- Size outside [1, 100] → 422 `{"error":"the number of ids should be between 1 and 100"}`.
- Entries that fail uuid.Parse are silently dropped; all-invalid input
→ 422 `{"error":"no valid UUIDs provided"}`.
## Billing
1 credit per returned row.
## Example Request
```bash
curl -X GET "https://api.openmart.ai/api/v1/business_records/list/openmart_id" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '["54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04"]'
```
## Example Response
```json
{
"54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04": {
"brand_id": "cc7eb8ef-8a51-4a53-a1ab-d2a39c163952",
"store_id": "54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04",
"business_name": "Curls are Fun",
"root_domain": "antonioberducci.com",
"city": "San Francisco",
"state": "California",
"country": "US",
"num_stores": 4,
"business_emails": null,
"business_phones": null,
"staffs": [{ "name": "Antonio Berducci", "role": "Curly Hair Stylist & Specialist", "source_urls": ["http://www.curlsarefun.com/antonioberducci"] }],
"from_sources": { "GOOGLE_MAP": { "id": "ChIJfeiVPq-AhYARoD84VjA_-Tg", "ref_url": "..." } }
}
}
```
Value shape matches `content` objects from POST /api/v1/search.
## Errors
- 401 — missing or invalid API key
- 402 — credit limit reached
- 403 — preview token (not allowed on this route) or banned user
- 422 — size out of range / no valid UUIDs / JSON bind failure
- 400 — datacenter downstream error
---
# Get Business by Google Place ID
## Endpoint
GET https://api.openmart.ai/api/v1/business_records/list/google_place_id
## Description
Resolve 1–100 Google Place IDs to Openmart business records. Response
is keyed by the place_id (the server strips the "GOOGLE_MAP@" prefix
from each source_id). IDs with no matching record are silently
omitted.
HTTP GET with a JSON body — same client-compatibility caveat as the
openmart_id variant.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Request body
Raw JSON array of 1–100 Google place_id strings:
```json
["ChIJfeiVPq-AhYARoD84VjA_-Tg","ChIJN1t_tDeuEmsRUsoyG83frY4"]
```
- Size outside [1, 100] → 422 `{"error":"the number of ids should be between 1 and 100"}`.
- Unlike the openmart_id variant, entries are not validated
client-side; every string is forwarded to the datacenter.
## Billing
1 credit per returned row.
## Example Request
```bash
curl -X GET "https://api.openmart.ai/api/v1/business_records/list/google_place_id" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '["ChIJfeiVPq-AhYARoD84VjA_-Tg"]'
```
## Example Response
```json
{
"ChIJfeiVPq-AhYARoD84VjA_-Tg": {
"brand_id": "cc7eb8ef-8a51-4a53-a1ab-d2a39c163952",
"store_id": "54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04",
"business_name": "Curls are Fun",
"root_domain": "antonioberducci.com",
"city": "San Francisco",
"state": "California",
"country": "US",
"from_sources": {
"GOOGLE_MAP": {
"id": "ChIJfeiVPq-AhYARoD84VjA_-Tg",
"ref_url": "https://www.google.com/maps/place/?q=place_id:ChIJfeiVPq-AhYARoD84VjA_-Tg",
"raw_associated_website": "http://www.antonioberducci.com/",
"name": "Curls Are Fun"
}
}
}
}
```
Value shape matches `content` objects from POST /api/v1/search.
## Errors
- 401 — missing or invalid API key
- 402 — credit limit reached
- 403 — preview token (not allowed on this route) or banned user
- 422 — size out of range / JSON bind failure
- 400 — datacenter downstream error
---
# Enrich Company
## Endpoint
POST https://api.openmart.ai/api/v1/enrich_company
## Description
Resolve a website URL or a social-media URL into matching Openmart
business records. Thin wrapper over the main search backend, returning
the same row shape as POST /api/v1/search.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Request body
```json
{
"website": "https://bluebottlecoffee.com",
"social_media_link": "https://www.instagram.com/bluebottle/",
"limit": 50,
"estimate_total": false,
"location": [{ "country": "US", "state": "CA" }]
}
```
- `website`, `social_media_link` — both optional, but you should
supply at least one. If both are empty you get an unfiltered top-N
slice of the index (the server does NOT enforce "at least one").
- `limit` — validator range [1, 50]. Values >50 return HTTP 422
`{"error":"Limit maximum value is 50"}`. Default 50.
- `estimate_total` — toggles the response envelope shape (see below).
- `location` — accepts EITHER a single Location object OR an array of
them (normalized to []Location server-side). Location fields:
`country`, `state`, `city`, `zip_code` (array), `lat`, `long`,
`geo_radius` (meters). Note the spelling: `zip_code` with
underscore and `long` with "g" — different from
/api/v2/brands/search.
## Billing
1 credit per returned row.
## Response shape
- `estimate_total=false` or omitted → response is a raw array:
`[{id, content, match_score, match_highlights, cursor}, …]`
- `estimate_total=true` → response is wrapped:
`{"data": [<same rows>], "total_count": 123}`
`content` mirrors POST /api/v1/search row content.
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v1/enrich_company" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"website": "https://bluebottlecoffee.com",
"location": [{"country": "US"}],
"limit": 2,
"estimate_total": true
}'
```
## Example Response
```json
{
"data": [
{
"id": "0044652b-7dea-4196-a4be-1b580c72fefe",
"content": {
"business_name": "Blue Bottle Coffee",
"root_domain": "bluebottlecoffee.com",
"num_stores": 82,
"ownership_type": "CHAIN"
},
"match_score": 24.2,
"cursor": [24.2, "0044652b-7dea-4196-a4be-1b580c72fefe"]
}
],
"total_count": 1
}
```
## Errors
- 401 — missing or invalid API key
- 402 — credit limit reached
- 403 — preview token or banned user
- 422 — validator failure (e.g. `limit > 50`)
- 400 — datacenter downstream error
---
# Find Employees
## Endpoint
POST https://api.openmart.ai/api/v1/task/batch/find_people
## Description
Submit async enrichment tasks for known company domains. Returns a batch_id; poll for status, then retrieve results. This is an asynchronous workflow.
## Authentication
Header: `X-API-Key: <your_api_key>`
## Parameters
### Most common parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| domain | string | Yes | Company email domain (e.g. acme.com, no https://). |
| title | string | Yes | Role to match (e.g. VP Sales, Head of Marketing). |
| max_k | integer | Yes | Max contacts to return for this item (1–8). |
| company_name | string | No | Brand/legal name; helps disambiguate common domains. |
| info_access | array[string] | No | Include "EMAIL", "PHONE", or both. Default: both. |
### Location hints
| Name | Type | Required | Description |
|------|------|----------|-------------|
| city | string | No | Location hint when one domain maps to multiple regions. |
| state | string | No | Location hint when one domain maps to multiple regions. |
| country | string | No | Location hint when one domain maps to multiple regions. |
### Pipeline and delivery
| Name | Type | Required | Description |
|------|------|----------|-------------|
| version | integer | No | 0 = default pipeline; 1 = alternate all-in-one variant. |
| notify_url | string | No | HTTPS URL for completion callback. |
### Optional metadata
| Name | Type | Required | Description |
|------|------|----------|-------------|
| tracking_id | string | No | Your ID; echoed on GET /api/v1/task/{task_id} for correlation. |
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v1/task/batch/find_people" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '[
{
"domain": "@bluebottlecoffee.com",
"company_name": "Blue Bottle",
"title": "Head of Marketing",
"country": "US"
}
]'
```
## Example Response (submit)
```json
{
"batch_id": "183219bc-066e-4641-9d6f-48205b7fbada",
"submit_for": "find_people",
"status": {
"processing": 1,
"completed": 0,
"errored": 0,
"total": 1,
"batch_ready": false
}
}
```
## Async workflow
1. Submit → receive batch_id (above)
2. Poll: GET /api/v1/task/batch/<batch_id>/status → wait until batch_ready is true
3. Get IDs: GET /api/v1/task/batch/<batch_id>/task_ids?status=COMPLETED
4. Get results: GET /api/v1/task/<task_id>
## Task result example
```json
{
"task_id": "2fc8b627-1111-2222-3333-123456789abc",
"status": "COMPLETED",
"tracking_id": "customer-42",
"data": [
{
"first_name": "Jane",
"last_name": "Doe",
"title": "Head of Marketing",
"email": { "email": "jane@bluebottlecoffee.com", "verified": true }
}
]
}
```
---
# Detect Tech Stack
## Endpoint
POST https://api.openmart.ai/api/v1/task/batch/find_tech
## Description
Submit async technology detection tasks for known company domains. Returns a batch_id. This is an asynchronous workflow.
## Authentication
Header: `X-API-Key: <your_api_key>`
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| domain | string | Yes | Company domain to check. |
| tech_type | string | Yes | Technology identifier to detect (e.g. shopify, hubspot, klaviyo). |
| company_name | string | No | Optional company name hint. |
| tracking_id | string | No | Optional client-defined tracking key returned with results. |
## Example Request (single domain)
```bash
curl -X POST "https://api.openmart.ai/api/v1/task/batch/find_tech" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '[
{
"domain": "bluebottlecoffee.com",
"company_name": "Blue Bottle Coffee",
"tech_type": "shopify"
}
]'
```
## Example Request (multiple domains)
```bash
curl -X POST "https://api.openmart.ai/api/v1/task/batch/find_tech" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '[
{"domain": "bluebottlecoffee.com", "tech_type": "hubspot", "tracking_id": "bluebottle-hubspot"},
{"domain": "allbirds.com", "tech_type": "hubspot", "tracking_id": "allbirds-hubspot"}
]'
```
## Async workflow
1. Submit → receive batch_id
2. Poll: GET /api/v1/task/batch/<batch_id>/status → wait until batch_ready is true
3. Get IDs: GET /api/v1/task/batch/<batch_id>/task_ids?status=COMPLETED
4. Get results: GET /api/v1/task/<task_id>
---
# Find Company Emails
## Endpoint
POST https://api.openmart.ai/api/v1/task/batch/lookup_business_email
## Description
Submit an async batch to discover shared company mailboxes (info@,
support@, sales@…) for a known domain. Not for individuals — for those
use find_people or lookup_people.
Submission enqueues tasks and returns immediately with a batch_id.
Fetch results via the standard batch → task flow.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Latency
This route sleeps ~26 seconds before the handler runs, even when the
body is invalid (deliberate concurrency throttle). Use a client
timeout of at least 60s.
## Request body
JSON array of 1–100 task objects. Per-task fields:
- `domain` — required, company root domain.
- `company_name` — required (validator rejects nil/empty), company display name.
- `city`, `state`, `country` — optional, narrow when company names clash.
- `tracking_id` — optional, echoed back on task read.
- `notify_url` — optional, must be a valid URL.
Batch-size errors → 400 `{"detail":"the number of tasks in each batch should be between 1 and 100"}`.
Missing required fields → 400 `{"detail":"<field> is required"}`.
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v1/task/batch/lookup_business_email" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '[
{
"domain": "milvali.com",
"company_name": "Milvali",
"tracking_id": "milvali-emails"
}
]'
```
## Submission Response
```json
{
"batch_id": "2fc8b627-1111-2222-3333-123456789abc",
"submit_for": "lookup_business_email",
"status": { "processing": 1, "completed": 0, "errored": 0, "total": 1, "batch_ready": false }
}
```
## Async workflow
1. Submit → receive batch_id.
2. Poll `GET /api/v1/task/batch/<batch_id>/status` until
`batch_ready == true`.
3. List task IDs with `GET /api/v1/task/batch/<batch_id>/task_ids?status=COMPLETED`.
4. For each task ID: `GET /api/v1/task/<task_id>`. `data` is an array
of `{email, status}`.
## Errors
- 400 — JSON bind / batch-size / per-task validator failure (`{"detail":"..."}`)
- 401 — missing or invalid API key
- 402 — credit limit reached
- 403 — banned user
- 500 — internal failure
---
# Enrich Known People
## Endpoint
POST https://api.openmart.ai/api/v1/task/batch/lookup_people
## Description
Submit an async batch to enrich KNOWN people (name + optional
LinkedIn) for a company domain. Returns email and/or phone per person.
If you don't know the specific people yet and want to discover them by
title, use find_people instead.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Latency
This route sleeps ~26 seconds before the handler runs, even when the
body is invalid. Use a client timeout of at least 60s.
## Request body
JSON array of 1–100 task objects. Per-task fields:
- `domain` — required, company root domain.
- `company_name` — optional, improves resolution.
- `city`, `state`, `country` — optional, narrow when company names clash.
- `info_access` — optional array of `"EMAIL"` and/or `"PHONE"`.
Default when omitted: both.
- `people` — required, 1–8 entries. Each is
`{ "first_name": "...", "last_name": "...", "linkedin_url": "..." }`.
LinkedIn URL is optional but improves match quality.
- `tracking_id` — optional, echoed back on task read.
- `notify_url` — optional, must be a valid URL.
Batch-size errors → 400 `{"detail":"the number of tasks in each batch should be between 1 and 100"}`.
Missing required fields → 400 `{"detail":"<field> is required"}`.
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v1/task/batch/lookup_people" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '[
{
"domain": "bluebottlecoffee.com",
"company_name": "Blue Bottle",
"people": [{"first_name": "Jane", "last_name": "Doe"}],
"info_access": ["EMAIL"],
"tracking_id": "bluebottle-jane"
}
]'
```
## Submission Response
```json
{
"batch_id": "2fc8b627-1111-2222-3333-123456789abc",
"submit_for": "lookup_people",
"status": { "processing": 1, "completed": 0, "errored": 0, "total": 1, "batch_ready": false }
}
```
## Async workflow
1. Submit → receive batch_id.
2. Poll `GET /api/v1/task/batch/<batch_id>/status` until
`batch_ready == true`.
3. List task IDs with `GET /api/v1/task/batch/<batch_id>/task_ids?status=COMPLETED`.
4. For each task ID: `GET /api/v1/task/<task_id>`. `data` is an array
of PeopleInfo (`first_name`, `last_name`, `linkedin_url`, `email`,
`phones`).
## Errors
- 400 — JSON bind / batch-size / per-task validator failure (`{"detail":"..."}`)
- 401 — missing or invalid API key
- 402 — credit limit reached
- 403 — banned user
- 500 — internal failure
---
# 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)
---
# Get Credit Balance
## Endpoint
GET https://api.openmart.ai/api/v2/credit-balance
## Description
Returns the calling team's remaining Openmart credits and the current
billing period window.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
Missing or unknown keys return HTTP 401 with
`{"detail":"Invalid API Key"}`.
## Plan branches
- Subscription keys — live balance from the credit ledger; period
mirrors the active Stripe subscription window.
- Trial keys — balance is `5000 - credits_used`; period is the current
calendar year (UTC).
- Unlimited keys (e.g. Clay production) — balance is a fixed sentinel
of `10000` (NOT the real cap); period is the current calendar year.
## Example Request
```bash
curl -X GET "https://api.openmart.ai/api/v2/credit-balance" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>"
```
## Example Response
```json
{
"period_start": "2025-08-05T20:22:47Z",
"period_end": "2026-08-05T20:22:47Z",
"balance": 998931751
}
```
## Errors
- 401 — missing or invalid API key (`{"detail":"Invalid API Key"}`)
- 500 — subscription lookup or balance calculation failed
---
# Create Deny Rules
## Endpoint
POST https://api.openmart.ai/api/v2/deny-rules
## Description
Add deny rules scoped to your API key. Any email or phone matching one
of your rules is suppressed from future enrichment output across
find_people, lookup_people, and lookup_business_email. Safe to replay.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Request body
```json
{
"type": "email",
"values": ["blocked@example.com", "spam@example.com"]
}
```
- `type` — required, must be exactly `"email"` or `"phone"`. Invalid
values return HTTP 400 with `{"detail":"Type must be one of [email phone]"}`.
- `values` — required, one or more literal identifiers. No wildcards.
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v2/deny-rules" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"type": "email", "values": ["blocked@example.com"]}'
```
## Example Response
```json
{
"status": "success"
}
```
## Errors
- 400 — bad JSON or bad `type` (`{"detail":"..."}`)
- 401 — missing or invalid API key
- 500 — persistence failure
---
# Check Deny Rules
## Endpoint
POST https://api.openmart.ai/api/v2/deny-rules/check
## Description
Look up whether specific values are currently denied for your API key.
The server always returns one entry per requested value, so the output
map has the same size as the input `values` array.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Request body
```json
{
"type": "email",
"values": ["a@x.com", "b@y.com"]
}
```
Same shape as create and delete.
## Example Request
```bash
curl -X POST "https://api.openmart.ai/api/v2/deny-rules/check" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"type": "email", "values": ["blocked@example.com", "ok@example.com"]}'
```
## Example Response
```json
{
"denied": {
"blocked@example.com": true,
"ok@example.com": false
}
}
```
## Errors
- 400 — bad JSON or bad `type` (`{"detail":"..."}`)
- 401 — missing or invalid API key
- 500 — persistence read failure
---
# Delete Deny Rules
## Endpoint
DELETE https://api.openmart.ai/api/v2/deny-rules
## Description
Remove deny rules that you previously created. Values with no matching
rule are silently ignored — the call is safe to replay.
## Authentication
- `X-API-Key: <your_api_key>` (recommended)
- `Authorization: Bearer <your_api_key>` (also accepted)
## Request body
```json
{
"type": "email",
"values": ["blocked@example.com"]
}
```
Same shape as create and check.
## Example Request
```bash
curl -X DELETE "https://api.openmart.ai/api/v2/deny-rules" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"type": "email", "values": ["blocked@example.com"]}'
```
## Example Response
```json
{
"status": "success"
}
```
## Errors
- 400 — bad JSON or bad `type` (`{"detail":"..."}`)
- 401 — missing or invalid API key
- 500 — persistence failure
---
# Check Batch Status
## Endpoint
GET https://api.openmart.ai/api/v1/task/batch/:batch_id/status
## Description
Poll aggregate progress for a batch until `batch_ready` becomes true.
## Authentication
Header: `X-API-Key: <your_api_key>`
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| batch_id | string (path) | Yes | The batch ID returned when you submit a batch request. |
## Example Request
```bash
curl -X GET "https://api.openmart.ai/api/v1/task/batch/<batch_id>/status" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>"
```
## Example Response
```json
{
"processing": 0,
"completed": 1,
"errored": 0,
"total": 1,
"batch_ready": true
}
```
---
# Get Task IDs in a Batch
## Endpoint
GET https://api.openmart.ai/api/v1/task/batch/:batch_id/task_ids?status=COMPLETED
## Description
After a batch is ready, fetch task IDs for completed tasks so you can retrieve final task results.
## Authentication
Header: `X-API-Key: <your_api_key>`
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| batch_id | string (path) | Yes | The batch ID returned when you submit a batch request. |
| status | string (query) | No | Optional status filter (e.g. COMPLETED). |
## Example Request
```bash
curl -X GET "https://api.openmart.ai/api/v1/task/batch/<batch_id>/task_ids?status=COMPLETED" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>"
```
## Example Response
```json
[
"2fc8b627-1111-2222-3333-123456789abc"
]
```
---
# Get Task Results
## Endpoint
GET https://api.openmart.ai/api/v1/task/:task_id
## Description
Fetch the final payload for an individual async task after the batch has produced task IDs.
## Authentication
Header: `X-API-Key: <your_api_key>`
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| task_id | string (path) | Yes | The task ID returned for an individual task inside a batch. |
## Example Request
```bash
curl -X GET "https://api.openmart.ai/api/v1/task/<task_id>" \
-H "Accept: application/json" \
-H "X-API-Key: <your_api_key>"
```
## Example Response
```json
{
"task_id": "2fc8b627-1111-2222-3333-123456789abc",
"status": "COMPLETED",
"tracking_id": "customer-42",
"data": [
{
"first_name": "Jane",
"last_name": "Doe",
"title": "Head of Marketing",
"email": { "email": "jane@bluebottlecoffee.com", "verified": true }
}
]
}
```
Statuses: PROCESSING, COMPLETED, ERRORED, or CANCELLED.