Skip to content
Docs page

API reference

Batch lookups

POST /v1/brands/batch: look up many domains in one request. Only the brands that are found cost a credit.

Request

POSThttps://brandidentityapi.com/v1/brands/batch

Needs a secret key. Send a JSON body with an identifiers array. Each identifier can be a domain, a URL or an email address, as for the Brand API.

curl https://brandidentityapi.com/v1/brands/batch \
  -H "Authorization: Bearer $BRAND_IDENTITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"identifiers":["stripe.com","https://www.linear.app/pricing","jane@notion.so","not a domain"]}'
Request body
{
  "identifiers": [
    "stripe.com",
    "https://www.linear.app/pricing",
    "jane@notion.so",
    "not a domain"
  ]
}

Batch size

How many identifiers one request may hold depends on your plan, up to 100. A larger batch is refused with invalid_request; split it.

API limits by plan
PlanDomains per batch
Free25
Starter50
Growth100
Custom100

Response

The request answers 200 whenever the batch itself was valid. Each identifier gets one result, in the order you sent them, with the status it would have had as a single lookup and either a brand or an error.

200 OK · trimmed
{
  "results": [
    {
      "identifier": "stripe.com",
      "domain": "stripe.com",
      "status": 200,
      "brand": {
        "id": "0b7e9a52-3c1d-4f6e-8a2b-5d9c1e7f4a30",
        "name": "Stripe",
        "domain": "stripe.com",
        "...": "the full record"
      }
    },
    {
      "identifier": "https://www.linear.app/pricing",
      "domain": "linear.app",
      "status": 200,
      "brand": {
        "name": "Linear",
        "domain": "linear.app",
        "...": "the full record"
      }
    },
    {
      "identifier": "jane@notion.so",
      "domain": "notion.so",
      "status": 200,
      "brand": {
        "name": "Notion",
        "domain": "notion.so",
        "...": "the full record"
      }
    },
    {
      "identifier": "not a domain",
      "domain": null,
      "status": 400,
      "error": {
        "code": "invalid_domain",
        "message": "Not a domain, URL or email address with a public domain."
      }
    }
  ]
}
FieldTypeDescription
identifierstringWhat you sent, unchanged.
domainstring | nullThe domain it was read as, or null when it has none.
statusnumberThe status a single lookup would have returned.
brandBrandThe full record, when the brand was found.
error{ code, message }Why there is no brand. The codes are those on the Errors page.

What counts

  • Each brand found counts one lookup. Errors cost nothing.
  • Identifiers that name the same domain (stripe.com and https://stripe.com/about) share one lookup and count once.
  • When your credits cover fewer domains than you sent, the ones that fit are looked up and the rest come back as insufficient_credits, uncharged.

Timing

Domains are looked up five at a time. Indexed brands come back at once; unknown ones are crawled live. A batch has a time budget of under a minute in total, so a large batch of unknown domains may answer some of them from the index only. Those come back with an error and are not counted: retry them on their own, or in a later batch.

Big lists
For thousands of domains, send batches one after another and read X-RateLimit-Remaining between them. Each batch weighs as many requests against your per-minute limit as the domains it looks up.

Errors

The whole batch is refused, and nothing counted, when:

StatusCodeWhy
400invalid_requestThe body is not JSON, has no identifiers, or holds too many.
401unauthorizedNo key, or a key that is not valid.
403forbiddenA publishable key, or a suspended account.
429rate_limitedToo many requests this minute.
402insufficient_creditsNo credits left at all.