{"openapi":"3.1.0","info":{"title":"Brand Identity API","version":"1.0.0","summary":"Brand colors, fonts, logos and company data for any domain.","description":"Brand data for any company domain. Authenticate with `Authorization: Bearer <key>` (or `X-Api-Key`). Only a publishable key (`lh_pk_`) may travel in a URL (`?key=` on the logo CDN, `?c=` on `/v2/search`); a secret key in a URL is never used.\n\nOnly successful brand lookups cost a credit: ones that find a brand with a logo. Search, the logo CDN, every failed lookup and every record without a logo cost no credit. Credits come from the free plan, subscriptions and top-up packs, and never expire. Searches and logo requests with a key count against the plan's monthly allowance; `/v1/me` shows yours.\n\nResponses may be cached and stored forever. Brandfetch-compatible paths live under `/v2`."},"servers":[{"url":"https://brandidentityapi.com"}],"security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"tags":[{"name":"Brands","description":"Brand records, metered per successful lookup."},{"name":"Search","description":"Find brands by name or domain. No credit; a monthly allowance by plan."},{"name":"Account","description":"Your plan and usage."},{"name":"Logo CDN","description":"Images for `<img src>`. No credit; keyed requests count monthly."},{"name":"Brandfetch compatible","description":"Drop-in paths for a Brandfetch integration."},{"name":"Agents","description":"Model Context Protocol server."}],"paths":{"/v1/brands/{identifier}":{"get":{"operationId":"getBrand","summary":"Get a brand","description":"The brand for a domain. A found brand costs one credit; a 404, any failure, and a record with no logo file (returned all the same) cost nothing. With no credits left it answers 402 `insufficient_credits`. A domain the index does not hold yet is crawled live, within the plan's live-crawl limit per minute. Secret keys only. A URL as the identifier must be percent-encoded: an unencoded `https://` is redirected by the router before it reaches the API.","tags":["Brands"],"parameters":[{"name":"identifier","in":"path","required":true,"description":"A domain (`stripe.com`), a URL-encoded URL, an email address (only its domain is used), or a `brandId` from search.","schema":{"type":"string"},"example":"stripe.com"},{"name":"refresh","in":"query","required":false,"description":"`true` re-crawls the site now instead of serving the index, and counts against the live-crawl limit. Paid plans; ignored on Free.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The brand.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Credits-Remaining":{"$ref":"#/components/headers/X-Credits-Remaining"},"X-Cache":{"$ref":"#/components/headers/X-Cache"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"$ref":"#/components/responses/UpstreamFailed"},"503":{"$ref":"#/components/responses/Unavailable"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/v1/brands/batch":{"post":{"operationId":"getBrandsBatch","summary":"Get many brands","description":"Up to your plan's batch size in different domains (and at most 100 identifiers) in one request, looked up five at a time. Each brand found with a logo costs one credit; identifiers for the same domain count once, and count once against the batch size. More different domains than the plan allows is a 400 and costs nothing. When credits run short, a lookup that fails hands its credit to the next domain. Items can fail on their own: `rate_limited` past the live-crawl limit, `insufficient_credits` once the credits run out, `timeout` when the batch ran out of time before trying them. None of those is charged; send them again. With no credits at all the whole request answers 402.","tags":["Brands"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchRequest"}}}},"responses":{"200":{"description":"One result per identifier, in request order.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Credits-Remaining":{"$ref":"#/components/headers/X-Credits-Remaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/search":{"get":{"operationId":"searchBrands","summary":"Search brands","description":"Brands by name or domain, best match first. Costs no credit; each search that answers counts against the plan's monthly allowance, and past it the answer is 429 `quota_exceeded` until the 1st (UTC). Publishable keys allowed.","tags":["Search"],"parameters":[{"name":"q","in":"query","required":true,"description":"A company name or domain.","schema":{"type":"string","minLength":1,"maxLength":100},"example":"stripe"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"default":10}}],"responses":{"200":{"description":"Matches.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/me":{"get":{"operationId":"getAccount","summary":"Plan, credits and usage","tags":["Account"],"responses":{"200":{"description":"The calling key's account.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Credits-Remaining":{"$ref":"#/components/headers/X-Credits-Remaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/openapi.json":{"get":{"operationId":"getOpenApi","summary":"This document","tags":["Account"],"security":[],"responses":{"200":{"description":"OpenAPI 3.1.","content":{"application/json":{}}}}}},"/v2/brands/{identifier}":{"get":{"operationId":"getBrandV2","summary":"Get a brand (Brandfetch path)","description":"The brand for a domain. A found brand costs one credit; a 404, any failure, and a record with no logo file (returned all the same) cost nothing. With no credits left it answers 402 `insufficient_credits`. A domain the index does not hold yet is crawled live, within the plan's live-crawl limit per minute. Secret keys only. A URL as the identifier must be percent-encoded: an unencoded `https://` is redirected by the router before it reaches the API.","tags":["Brandfetch compatible"],"parameters":[{"name":"identifier","in":"path","required":true,"description":"A domain, or a `brandId` from search.","schema":{"type":"string"},"example":"stripe.com"},{"name":"refresh","in":"query","required":false,"description":"`true` re-crawls the site now instead of serving the index, and counts against the live-crawl limit. Paid plans; ignored on Free.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The brand.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Credits-Remaining":{"$ref":"#/components/headers/X-Credits-Remaining"},"X-Cache":{"$ref":"#/components/headers/X-Cache"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"$ref":"#/components/responses/UpstreamFailed"},"503":{"$ref":"#/components/responses/Unavailable"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/v2/brands/id/{id}":{"get":{"operationId":"getBrandByIdV2","summary":"Get a brand by id (Brandfetch path)","description":"The brand for a domain. A found brand costs one credit; a 404, any failure, and a record with no logo file (returned all the same) cost nothing. With no credits left it answers 402 `insufficient_credits`. A domain the index does not hold yet is crawled live, within the plan's live-crawl limit per minute. Secret keys only. A URL as the identifier must be percent-encoded: an unencoded `https://` is redirected by the router before it reaches the API.","tags":["Brandfetch compatible"],"parameters":[{"name":"id","in":"path","required":true,"description":"A `brandId` from search.","schema":{"type":"string","format":"uuid"},"example":"0b9d8f4e-2c1a-4e5b-9a7c-3d2e1f0a9b8c"},{"name":"refresh","in":"query","required":false,"description":"`true` re-crawls the site now instead of serving the index, and counts against the live-crawl limit. Paid plans; ignored on Free.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The brand.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Credits-Remaining":{"$ref":"#/components/headers/X-Credits-Remaining"},"X-Cache":{"$ref":"#/components/headers/X-Cache"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"$ref":"#/components/responses/UpstreamFailed"},"503":{"$ref":"#/components/responses/Unavailable"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/v2/brands/domain/{domain}":{"get":{"operationId":"getBrandByDomainV2","summary":"Get a brand by domain (Brandfetch path)","description":"The brand for a domain. A found brand costs one credit; a 404, any failure, and a record with no logo file (returned all the same) cost nothing. With no credits left it answers 402 `insufficient_credits`. A domain the index does not hold yet is crawled live, within the plan's live-crawl limit per minute. Secret keys only. A URL as the identifier must be percent-encoded: an unencoded `https://` is redirected by the router before it reaches the API.","tags":["Brandfetch compatible"],"parameters":[{"name":"domain","in":"path","required":true,"description":"A domain.","schema":{"type":"string"},"example":"stripe.com"},{"name":"refresh","in":"query","required":false,"description":"`true` re-crawls the site now instead of serving the index, and counts against the live-crawl limit. Paid plans; ignored on Free.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The brand.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Credits-Remaining":{"$ref":"#/components/headers/X-Credits-Remaining"},"X-Cache":{"$ref":"#/components/headers/X-Cache"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"$ref":"#/components/responses/UpstreamFailed"},"503":{"$ref":"#/components/responses/Unavailable"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/v2/search/{name}":{"get":{"operationId":"searchBrandsV2","summary":"Search brands (Brandfetch path)","description":"The same matches as `/v1/search`, as a bare array. Like Brandfetch, it also takes a publishable key as `?c=`.","tags":["Brandfetch compatible"],"security":[{"bearerAuth":[]},{"apiKeyHeader":[]},{"clientIdQuery":[]}],"parameters":[{"name":"name","in":"path","required":true,"description":"A company name or domain.","schema":{"type":"string"},"example":"stripe.com"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"default":10}},{"name":"c","in":"query","required":false,"description":"A publishable key (`lh_pk_`), Brandfetch's client id parameter. A secret key here is refused with a 401.","schema":{"type":"string","pattern":"^lh_pk_"}}],"responses":{"200":{"description":"Matches.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BrandSearchResult"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/logo/{domain}":{"get":{"operationId":"getLogo","summary":"Logo image","description":"A brand's logo as an image, for `<img src>`. Costs no credit. Without a key, indexed brands only (and a fallback for the rest), limited per visitor address. A request with a key counts against the plan's monthly logo allowance. A key never breaks the image: one that is invalid, over the account's per-minute logo limit or past this month's allowance is served as keyless and named in `X-Api-Key-Status`. Browser code may read that header and send a key header: preflights are answered.","tags":["Logo CDN"],"security":[{},{"apiKeyQuery":[]},{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"domain","in":"path","required":true,"description":"A domain.","schema":{"type":"string"},"example":"stripe.com"},{"name":"type","in":"query","schema":{"type":"string","enum":["icon","symbol","logo"]},"description":"Default `icon`."},{"name":"size","in":"query","schema":{"type":"integer","minimum":1,"default":128},"description":"The longest side in pixels. Served between 16 and 1024: a smaller or larger value is clamped, not refused."},{"name":"w","in":"query","schema":{"type":"integer","minimum":1},"description":"Alias of `size` (Brandfetch's name), used when `size` is absent."},{"name":"width","in":"query","schema":{"type":"integer","minimum":1},"description":"Alias of `size`, used when `size` and `w` are absent."},{"name":"format","in":"query","schema":{"type":"string","enum":["webp","png","svg","jpeg"]},"description":"Default: `webp` when the Accept header lists image/webp, else `png`. `svg` answers a PNG when the brand has no vector file; the `Content-Type` header always names the format sent."},{"name":"theme","in":"query","schema":{"type":"string","enum":["light","dark"]},"description":"The ink: `dark` for light backgrounds, `light` for dark ones."},{"name":"background","in":"query","schema":{"type":"string","enum":["light","dark"]},"description":"The background the logo sits on; the opposite of `theme`. Ignored when `theme` is set."},{"name":"fallback","in":"query","schema":{"type":"string","enum":["monogram","404","transparent"]},"description":"What to return for an unknown brand. Default `monogram`."},{"name":"key","in":"query","schema":{"type":"string","pattern":"^lh_pk_"},"description":"Optional publishable key (`lh_pk_`). With one, a domain not in the index yet may be crawled on the spot, within the account's logo crawl limit. A secret key here is never used (`X-Api-Key-Status: secret-key-in-url`): send secret keys in a header only."}],"responses":{"200":{"description":"The image. Cached by browsers for a day and by the CDN longer.","content":{"image/webp":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-Api-Key-Status":{"$ref":"#/components/headers/X-Api-Key-Status"}}},"304":{"description":"Not modified (`If-None-Match`)."},"400":{"description":"A parameter or the path type is not valid.","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"No logo and `fallback=404`.","content":{"image/webp":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"429":{"description":"Too many requests from this address. See Retry-After.","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"The logo could not be rendered.","content":{"text/plain":{"schema":{"type":"string"}}}},"503":{"description":"The rate limiter could not be reached. See Retry-After.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/logo/{domain}/{type}":{"get":{"operationId":"getLogoByType","summary":"Logo image, type in the path","description":"The same image as `/logo/{domain}?type=`. Brandfetch Logo Link path options are accepted after the domain too (`/w/{n}`, `/h/{n}`, `/theme/{light|dark}`, `/type/{type}`, `/fallback/{lettermark|transparent|404}`), so a Logo Link URL works with only the host changed. Any other path segment, or a `?type=` that disagrees with the path, is a 400.","tags":["Logo CDN"],"security":[{},{"apiKeyQuery":[]},{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"domain","in":"path","required":true,"description":"A domain.","schema":{"type":"string"},"example":"stripe.com"},{"name":"type","in":"path","required":true,"schema":{"type":"string","enum":["icon","symbol","logo"]}},{"name":"size","in":"query","schema":{"type":"integer","minimum":1,"default":128},"description":"The longest side in pixels. Served between 16 and 1024: a smaller or larger value is clamped, not refused."},{"name":"w","in":"query","schema":{"type":"integer","minimum":1},"description":"Alias of `size` (Brandfetch's name), used when `size` is absent."},{"name":"width","in":"query","schema":{"type":"integer","minimum":1},"description":"Alias of `size`, used when `size` and `w` are absent."},{"name":"format","in":"query","schema":{"type":"string","enum":["webp","png","svg","jpeg"]},"description":"Default: `webp` when the Accept header lists image/webp, else `png`. `svg` answers a PNG when the brand has no vector file; the `Content-Type` header always names the format sent."},{"name":"theme","in":"query","schema":{"type":"string","enum":["light","dark"]},"description":"The ink: `dark` for light backgrounds, `light` for dark ones."},{"name":"background","in":"query","schema":{"type":"string","enum":["light","dark"]},"description":"The background the logo sits on; the opposite of `theme`. Ignored when `theme` is set."},{"name":"fallback","in":"query","schema":{"type":"string","enum":["monogram","404","transparent"]},"description":"What to return for an unknown brand. Default `monogram`."},{"name":"key","in":"query","schema":{"type":"string","pattern":"^lh_pk_"},"description":"Optional publishable key (`lh_pk_`). With one, a domain not in the index yet may be crawled on the spot, within the account's logo crawl limit. A secret key here is never used (`X-Api-Key-Status: secret-key-in-url`): send secret keys in a header only."}],"responses":{"200":{"description":"The image.","content":{"image/webp":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-Api-Key-Status":{"$ref":"#/components/headers/X-Api-Key-Status"}}},"304":{"description":"Not modified (`If-None-Match`)."},"400":{"description":"A parameter or the path type is not valid.","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"No logo and `fallback=404`.","content":{"image/webp":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"429":{"description":"Too many requests from this address. See Retry-After.","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"The logo could not be rendered.","content":{"text/plain":{"schema":{"type":"string"}}}},"503":{"description":"The rate limiter could not be reached. See Retry-After.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/cdn/{file}":{"get":{"operationId":"getAsset","summary":"Stored asset","description":"The file behind a `formats[].src` URL. Immutable, cached for a year.","tags":["Logo CDN"],"security":[],"parameters":[{"name":"file","in":"path","required":true,"schema":{"type":"string"},"description":"`{assetId}.{ext}`; the extension must match the stored format."}],"responses":{"200":{"description":"The file.","content":{"image/webp":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Unknown asset, or the wrong extension.","content":{"text/plain":{"schema":{"type":"string"}}}},"503":{"description":"Storage could not be reached. See Retry-After.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/mcp":{"post":{"operationId":"mcp","summary":"MCP server","description":"Model Context Protocol (Streamable HTTP, stateless JSON-RPC 2.0) with tools `get_brand`, `search_brands` and `get_logo_url`. `get_brand` is metered like `GET /v1/brands/{identifier}`.","tags":["Agents"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"A JSON-RPC 2.0 message."}}}},"responses":{"200":{"description":"A JSON-RPC response (an array for a batch). Invalid tool arguments are a JSON-RPC error -32602.","content":{"application/json":{}}},"202":{"description":"Only notifications or client responses arrived; no body."},"400":{"description":"Not JSON (-32700), an unsupported `MCP-Protocol-Version`, or a batch on 2025-06-18 or of more than ten messages (-32600).","content":{"application/json":{}}},"401":{"description":"The key sent is not valid.","content":{"application/json":{}}},"403":{"description":"The key's account is suspended.","content":{"application/json":{}}},"413":{"description":"The body is larger than 64 KB.","content":{"application/json":{}}},"503":{"description":"The key could not be checked. See Retry-After.","content":{"application/json":{}}}}},"get":{"operationId":"mcpStream","summary":"MCP server-sent events (not offered)","description":"This server is stateless and opens no stream: GET (and DELETE) answer 405, which MCP clients read as \"no stream\".","tags":["Agents"],"security":[],"responses":{"405":{"description":"Method not allowed. `Allow: POST, OPTIONS`.","content":{"application/json":{}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"`lh_sk_...` or `lh_pk_...`."},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-Api-Key"},"apiKeyQuery":{"type":"apiKey","in":"query","name":"key","description":"Logo CDN only. Publishable keys (`lh_pk_`) only."},"clientIdQuery":{"type":"apiKey","in":"query","name":"c","description":"`/v2/search` only, Brandfetch's client id. Publishable keys (`lh_pk_`) only."}},"headers":{"X-Request-Id":{"description":"Unique id for this request. Quote it to support.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed per minute on your plan.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current minute window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"When the window ends, Unix seconds.","schema":{"type":"integer"}},"X-Credits-Remaining":{"description":"Credits left after this request, never below zero. On brand lookups, batches and /v1/me.","schema":{"type":"integer"}},"X-Cache":{"description":"`HIT` when served from the index, `MISS` after a live crawl.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying (429 and 503 only).","schema":{"type":"integer"}},"X-Api-Key-Status":{"description":"Logo CDN only, when a key was sent but not used: `invalid` (unknown or revoked), `secret-key-in-url` (a secret key in `?key=`, never used), `rate-limited` (the account's per-minute logo limit) or `quota-exceeded` (this month's logo allowance on the account's plan). Each is served as keyless.","schema":{"type":"string"}}},"responses":{"BadRequest":{"description":"The request is not valid: `invalid_request` or `invalid_domain`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"No key, a key that is unknown or revoked, or a secret key sent in a URL (never used).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"A publishable key on a secret-only endpoint, or a suspended account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No brand at that domain (`domain_not_found`, `no_brand_data`) or with that id (`not_found`). Not counted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unprocessable":{"description":"The site refused to be crawled: `fetch_blocked`. Not counted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PaymentRequired":{"description":"`insufficient_credits`: no credits left for this request. `error.details` has the `balance`, what was `required` and the `billing_url`. Nothing was charged; retrying will not help until credits are added.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooManyRequests":{"description":"`rate_limited`: the per-minute request limit, or the live-crawl limit for a domain not in the index yet. `quota_exceeded`: the plan's searches for this month (UTC) are used up; Retry-After runs to the 1st. See Retry-After. Not counted.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServerError":{"description":"Something failed on our side. Not counted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"UpstreamFailed":{"description":"The brand's site could not be fetched: `fetch_failed`. Not counted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unavailable":{"description":"The key or the usage counters could not be checked, so nothing ran; or the domain's last crawl timed out or failed (`timeout`, `fetch_failed`) and that answer is remembered until it is crawled again. Not counted. See Retry-After.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Timeout":{"description":"The live crawl ran out of time: `timeout`. Not counted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Brand":{"type":"object","description":"A brand. Field names follow Brandfetch's Brand API v2, so an integration moves over unchanged.","properties":{"id":{"type":"string","description":"Stable brand id."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string","description":"The registrable domain the brand is stored under."},"claimed":{"type":"boolean"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"longDescription":{"anyOf":[{"type":"string"},{"type":"null"}]},"links":{"type":"array","items":{"$ref":"#/components/schemas/BrandLink"}},"logos":{"type":"array","items":{"$ref":"#/components/schemas/BrandLogo"}},"colors":{"type":"array","items":{"$ref":"#/components/schemas/BrandColor"}},"fonts":{"type":"array","items":{"$ref":"#/components/schemas/BrandFont"}},"images":{"type":"array","items":{"$ref":"#/components/schemas/BrandImage"}},"ogImage":{"anyOf":[{"type":"string","description":"The site's own share image URL: `og:image`, or `twitter:image` when the page has no `og:image`. The file on the site, not a copy. An addition to Brandfetch's shape."},{"type":"null"}]},"company":{"anyOf":[{"$ref":"#/components/schemas/BrandCompany"},{"type":"null"}]},"qualityScore":{"type":"number","minimum":0,"maximum":1,"description":"How complete and verified the record is."},"isNsfw":{"type":"boolean"},"restriction":{"anyOf":[{"$ref":"#/components/schemas/BrandRestriction"},{"type":"null"}]},"urn":{"type":"string"},"status":{"type":"string","enum":["ready","partial","pending","failed"],"description":"`ready` is complete; `partial` is missing parts and retried sooner."},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","domain","claimed","description","longDescription","links","logos","colors","fonts","images","ogImage","company","qualityScore","isNsfw","restriction","urn","status","updatedAt"]},"BrandLogo":{"type":"object","description":"A logo, with every format it is stored in.","properties":{"type":{"type":"string","enum":["icon","symbol","logo","other"],"description":"icon: a square mark. symbol: the mark without words. logo: the wordmark or lockup."},"theme":{"anyOf":[{"type":"string","enum":["light","dark"],"description":"The ink: a `dark` logo is for light backgrounds, a `light` logo for dark ones."},{"type":"null"}]},"formats":{"type":"array","items":{"$ref":"#/components/schemas/AssetFormatEntry"}},"tags":{"type":"array","items":{"type":"string"}}},"required":["type","theme","formats","tags"]},"AssetFormatEntry":{"type":"object","description":"One file of an asset, in one format.","properties":{"src":{"type":"string","description":"Absolute URL of the file on the asset CDN. Immutable: cache it forever."},"format":{"type":"string","enum":["svg","png","webp","jpeg","ico"]},"background":{"anyOf":[{"type":"string","enum":["transparent"]},{"type":"null"}]},"width":{"anyOf":[{"type":"integer"},{"type":"null"}]},"height":{"anyOf":[{"type":"integer"},{"type":"null"}]},"size":{"type":"integer","description":"Bytes."}},"required":["src","format","background","width","height","size"]},"BrandColor":{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-f]{6}$","description":"Lower case, six digits."},"type":{"type":"string","enum":["accent","dark","light","brand"]},"brightness":{"type":"integer","minimum":0,"maximum":255,"description":"Perceived brightness."}},"required":["hex","type","brightness"]},"BrandFont":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["title","body"]},"origin":{"type":"string","enum":["google","adobe","custom","system"]},"originId":{"anyOf":[{"type":"string","description":"The family id at its origin, e.g. the Google Fonts family name."},{"type":"null"}]},"weights":{"type":"array","items":{"type":"integer"}}},"required":["name","type","origin","originId","weights"]},"BrandImage":{"type":"object","description":"One of the site's pictures, never an icon, stored as a JPEG on our CDN.","properties":{"type":{"type":"string","enum":["banner","other"],"description":"`banner` is the site's share image (og:image); `other` is another picture from its page."},"formats":{"type":"array","items":{"$ref":"#/components/schemas/AssetFormatEntry"}},"tags":{"type":"array","items":{"type":"string"}}},"required":["type","formats","tags"]},"BrandLink":{"type":"object","properties":{"name":{"type":"string","enum":["twitter","linkedin","github","instagram","facebook","youtube","tiktok","crunchbase","discord","pinterest","threads","bluesky","medium","wikipedia"]},"url":{"type":"string"}},"required":["name","url"]},"BrandIndustry":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"emoji":{"type":"string"},"score":{"type":"number","minimum":0,"maximum":1,"description":"Classifier confidence."},"parent":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"emoji":{"type":"string"}},"required":["id","name","slug","emoji"]},{"type":"null"}]}},"required":["id","name","slug","emoji","score","parent"]},"BrandLocation":{"type":"object","properties":{"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"countryCode":{"anyOf":[{"type":"string","description":"ISO 3166-1 alpha-2."},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"subregion":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["city","state","country","countryCode","region","subregion"]},"BrandRestriction":{"type":"object","description":"Why a record carries no data on purpose. An addition to Brandfetch's shape.","properties":{"code":{"type":"string","enum":["nsfw"],"description":"`nsfw`: the site is adult content."},"message":{"type":"string","description":"Why the record is empty, in a sentence."}},"required":["code","message"]},"BrandCompany":{"type":"object","properties":{"employees":{"anyOf":[{"type":"integer","description":"A headcount bucket's floor: 1, 2, 11, 51, 201, 501, 1001, 5001 or 10001."},{"type":"null"}]},"foundedYear":{"anyOf":[{"type":"integer"},{"type":"null"}]},"kind":{"anyOf":[{"type":"string","enum":["PUBLIC_COMPANY","PRIVATELY_HELD","NON_PROFIT","GOVERNMENT_AGENCY","EDUCATIONAL","SELF_EMPLOYED","PARTNERSHIP"]},{"type":"null"}]},"location":{"anyOf":[{"$ref":"#/components/schemas/BrandLocation"},{"type":"null"}]},"industries":{"type":"array","items":{"$ref":"#/components/schemas/BrandIndustry"}},"ticker":{"anyOf":[{"type":"string","description":"Exchange ticker for a listed company, e.g. `NASDAQ:AAPL`."},{"type":"null"}]},"financialIdentifiers":{"$ref":"#/components/schemas/BrandFinancialIdentifiers"}},"required":["employees","foundedYear","kind","location","industries","ticker","financialIdentifiers"]},"BrandFinancialIdentifiers":{"type":"object","description":"Brandfetch's identifiers for a listed company. `isin` is not collected yet and is always empty.","properties":{"isin":{"type":"array","items":{"type":"string"}},"ticker":{"type":"array","items":{"type":"string","description":"A bare ticker symbol, e.g. `AAPL`."}}},"required":["isin","ticker"]},"BrandSearchResult":{"type":"object","properties":{"brandId":{"anyOf":[{"type":"string","description":"Null until the brand has been indexed."},{"type":"null"}]},"name":{"type":"string"},"domain":{"type":"string"},"icon":{"type":"string","description":"Absolute URL of a small square icon on the logo CDN."},"claimed":{"type":"boolean"},"qualityScore":{"anyOf":[{"type":"number"},{"type":"null"}]}},"required":["brandId","name","domain","icon","claimed","qualityScore"]},"SearchResponse":{"type":"object","properties":{"query":{"type":"string"},"results":{"type":"array","items":{"$ref":"#/components/schemas/BrandSearchResult"}}},"required":["query","results"]},"BatchRequest":{"type":"object","properties":{"identifiers":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string"},"example":["stripe.com","https://linear.app","jane@notion.so"]}},"required":["identifiers"]},"BatchItem":{"type":"object","properties":{"identifier":{"type":"string","description":"As sent."},"domain":{"anyOf":[{"type":"string","description":"The domain it was read as."},{"type":"null"}]},"status":{"type":"integer","description":"The status this item would have had as a single lookup."},"brand":{"$ref":"#/components/schemas/Brand"},"error":{"type":"object","properties":{"code":{"type":"string","enum":["unauthorized","forbidden","invalid_request","not_found","insufficient_credits","rate_limited","quota_exceeded","upstream_failed","internal_error","invalid_domain","domain_not_found","fetch_failed","fetch_blocked","timeout","no_brand_data"]},"message":{"type":"string"}},"required":["code","message"]},"retryAfter":{"type":"integer","description":"With status 503: seconds until the domain, whose last crawl timed out or failed, is crawled again."}},"required":["identifier","domain","status"]},"BatchResponse":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/BatchItem"}}},"required":["results"]},"Account":{"type":"object","properties":{"plan":{"type":"string","enum":["free","starter","growth","custom"]},"credits":{"type":"object","properties":{"balance":{"type":"integer","description":"Credits left, exact. Below zero after a refund of spent credits."},"remaining":{"type":"integer","description":"Credits the next requests can spend: the balance, never below zero."}},"required":["balance","remaining"]},"period":{"type":"string","description":"The calendar month (UTC), `2026-10`."},"usage":{"type":"object","properties":{"lookups":{"type":"integer","description":"Successful brand lookups this month."},"logos":{"type":"integer","description":"Logo CDN requests with one of your keys this month."},"searches":{"type":"integer","description":"Searches that answered this month, from any key."}},"required":["lookups","logos","searches"]},"limits":{"type":"object","properties":{"perMinute":{"type":"integer"},"batchSize":{"type":"integer"},"crawlsPerMinute":{"type":"integer","description":"Live crawls of domains not in the index yet, per minute."},"logosPerMonth":{"anyOf":[{"type":"integer","description":"Logo CDN requests with a key per calendar month (UTC). Null: unlimited."},{"type":"null"}]},"searchesPerMonth":{"anyOf":[{"type":"integer","description":"Searches per calendar month (UTC). Null: unlimited."},{"type":"null"}]}},"required":["perMinute","batchSize","crawlsPerMinute","logosPerMonth","searchesPerMonth"]},"key":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["secret","publishable"]}},"required":["id","kind"]}},"required":["plan","credits","period","usage","limits","key"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["unauthorized","forbidden","invalid_request","not_found","insufficient_credits","rate_limited","quota_exceeded","upstream_failed","internal_error","invalid_domain","domain_not_found","fetch_failed","fetch_blocked","timeout","no_brand_data"]},"message":{"type":"string","description":"A sentence a developer can act on."},"docs":{"type":"string","description":"Link to this error's section of the docs."},"details":{"type":"object","description":"Machine-readable facts for some codes. `insufficient_credits`: `balance`, `required`, `billing_url`. `rate_limited`: `retry_after`. `quota_exceeded`: `retry_after`, `limit`, `billing_url`.","properties":{"balance":{"type":"integer","description":"Credits left. Below zero after a refund of credits already spent."},"required":{"type":"integer","description":"Credits this request needed."},"billing_url":{"type":"string","description":"Where to add credits, or to upgrade."},"retry_after":{"type":"integer","description":"Seconds until the rate-limit window ends, or until the month starts over (`quota_exceeded`)."},"limit":{"type":"integer","description":"`quota_exceeded`: what the plan allows a month."}}}},"required":["code","message","docs"]}},"required":["error"]}}}}