{
  "openapi": "3.0.1",
  "info": {
    "title": "Brandfetch API",
    "description": "Our APIs help you personalize your customer journey through unique branded experiences.",
    "license": {
      "name": "MIT"
    },
    "version": "1.0.0",
    "contact": {
      "name": "Brandfetch Support",
      "url": "https://brandfetch.com",
      "email": "support@brandfetch.io"
    }
  },
  "x-service-info": {
    "categories": [
      "brand-data",
      "company-data",
      "logos"
    ],
    "docs": {
      "homepage": "https://docs.brandfetch.com",
      "apiReference": "https://docs.brandfetch.com/reference/brand-api",
      "llms": "https://brandfetch.com/llms.txt"
    }
  },
  "servers": [
    {
      "url": "https://api.brandfetch.io"
    }
  ],
  "paths": {
    "/v2/brands/{identifier}": {
      "get": {
        "summary": "Get brand data",
        "description": "Get brand data using a Domain, Website URL, Email address, Brand ID, ISIN, Stock/ETF ticker, or Crypto symbol. Authenticate with an API key sent as `Authorization: Bearer <key>`, or pay for the single request with x402 or MPP: https://docs.brandfetch.com/agents/pay-per-request.",
        "operationId": "getBrandData",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            }
          ],
          "offers": [
            {
              "amount": "100000",
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Brand API request",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "parameters": [
          {
            "name": "identifier",
            "in": "path",
            "description": "Identifier to retrieve brand data. Accepted formats:\n\n- **Domain:** `nike.com`\n- **Email address:** `john@example.brandfetch.com`\n- **Website URL:** `https://www.brandfetch.com/developers/pricing`\n- **Brand ID:** `id_0dwKPKT`\n- **Stock or ETF ticker:** `NKE`\n- **ISIN:** `US6541061031`\n- **Crypto symbol:** `BTC`, `ETH`\n\n**Note:** When using this generic endpoint, the identifier is resolved in the following order: `domain` \u2192 `ticker` \u2192 `isin` \u2192 `crypto`. To avoid naming collisions, use explicit type routes: `/v2/brands/{type}/{identifier}` where `type` can be `domain`, `ticker`, `isin`, or `crypto`.\n\n**Email addresses:** The API reads an identifier that contains `@` (or the percent-encoded `%40`) as an email address. It resolves the address to its registrable domain. `john@example.brandfetch.com` returns the same response as `brandfetch.com`. A mailbox provider's address resolves like any other address: a gmail.com address returns the brand of gmail.com. The API does not tell you whether the domain is the contact's company. A malformed address returns `400`, and the API does not bill the request. Refused lookups do not count against your quota. The API does not store the address. Your request logs show only the resolved domain. This endpoint and the Brand Context API accept email addresses. The explicit type routes refuse an email address with a `400`.\n\n**Website URLs:** The API reads an identifier that starts with `http://` or `https://` (or the percent-encoded `https%3A%2F%2F`) as a website URL. The API also reads a domain with a path (`brandfetch.com/developers/pricing`) as a website URL. The API resolves the URL to the registrable domain of its host. The scheme, `www.`, port, path, and query do not change the result. `https://www.brandfetch.com/developers/pricing` returns the same response as `brandfetch.com`. A URL whose host is not a domain name returns `400`, and the API does not bill the request. Refused lookups do not count against your quota. The API does not store the URL. Your request logs show only the resolved domain. This endpoint and the Brand Context API accept website URLs. The explicit type routes refuse a website URL with a `400`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "domain": {
                "summary": "Domain",
                "value": "nike.com"
              },
              "email": {
                "summary": "Email address",
                "value": "john@example.brandfetch.com"
              },
              "url": {
                "summary": "Website URL",
                "value": "https://www.brandfetch.com/developers/pricing"
              },
              "brandId": {
                "summary": "Brand ID",
                "value": "id_0dwKPKT"
              },
              "ISIN": {
                "summary": "ISIN",
                "value": "US6541061031"
              },
              "stockSymbol": {
                "summary": "Stock or ETF ticker",
                "value": "NKE"
              },
              "cryptoSymbol": {
                "summary": "Crypto symbol",
                "value": "BTC"
              }
            }
          },
          {
            "name": "allowNsfw",
            "in": "query",
            "required": false,
            "description": "Brandfetch evaluates brands for NSFW content and reserves the right to not return inappropriate brands. Depending on the severity, a brand may either not be returned at all (`404`), or be returned with its `isNsfw` property set to `true`. The `allowNsfw` query parameter lets you control this behavior:\n\n- **Not set** (default) \u2014 Some NSFW brands are not returned (`404`), others are returned with `isNsfw: true`.\n- **`true`** \u2014 Returns the brand regardless of its NSFW status.\n- **`false`** \u2014 Filters out all brands flagged as NSFW (returns `404`).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "cachedOnly",
            "in": "query",
            "description": "When `true`, the Brand API answers from its store alone. A brand that is already indexed is returned as usual, and a brand that is not is answered with `204 No Content` instead of being indexed live, which can take several seconds. Nothing is crawled, and a ticker, ISIN, or crypto symbol that is not yet indexed is not resolved either. A `204` does not count towards your quota. Any value other than `true`, including omitting the parameter, keeps the default behaviour of indexing the brand live on a miss. Defaults to `false`.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "examples": {
              "cachedOnly": {
                "summary": "Cached only (skip crawling)",
                "value": true
              }
            }
          },
          {
            "name": "palette",
            "in": "query",
            "required": false,
            "description": "Opt in to the brand's color palette. Set `true` or `1` to add a `palette` object to the response. If you omit the parameter, or set another value, the response does not change and has no `palette` key.\n\nIf the brand has no palette yet, this request builds one from the brand's last crawl and can take some seconds longer.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "PAYMENT-RESPONSE": {
                "description": "Present on responses paid with x402: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`).",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "Present on responses paid with MPP: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). Such responses also carry `Cache-Control: private`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Successful request. A request paid with MPP whose response was lost can be retried with the same credential for two minutes: it is served from the payment already taken and not charged again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandResponse"
                }
              }
            }
          },
          "204": {
            "description": "Returned when `cachedOnly=true` and the brand is not yet indexed. The response body is empty. Because live indexing is disabled there is nothing to return, and the request does not count towards your quota. Retry without `cachedOnly` to index the brand live."
          },
          "400": {
            "description": "The request could not be read. `error` says which part: the identifier, the route, the lookup kind, or an email address or URL used as the identifier. A `400` consumes no API credit.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_invalid",
                    "route_invalid",
                    "lookup_kind_invalid",
                    "email_invalid",
                    "url_invalid",
                    "identifier_ambiguous"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "The `Authorization` header is present but carries no usable token (`authorization_required`). A request with no credential at all receives a `402` with a payment challenge instead.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Returned when the request carries no credential: no API key, no x402 payment, no MPP credential. The `PAYMENT-REQUIRED` header prices this request at $0.10 in USDC on Base, and each `WWW-Authenticate: Payment` challenge quotes the same price over MPP. Pay either way, or send an API key. Also returned, with a `reason`, when a `PAYMENT-SIGNATURE` or an `Authorization: Payment …` credential was presented but the payment was not accepted or could not be settled. Nothing is charged in that case. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "The MPP challenge: one `Payment` challenge for USDC.e on Tempo, which settles from a cent. Answer it with an `Authorization: Payment …` credential. Cards start at $0.50, above this price, so no card challenge is issued here; a card can pay for standing access on `POST /v2/agents/access`.",
                "schema": {
                  "type": "string"
                }
              },
              "x-bf-error": {
                "description": "Only the header names this refusal: the body is the payment protocols' own.",
                "schema": {
                  "type": "string",
                  "enum": ["payment_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), the plan includes no Brand API credits (`no_api_credits`), or the key could not be checked just now (`auth_unavailable`, worth a retry).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "no_api_credits", "auth_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Nothing can be served for the identifier. `error` says why: no brand and the crawl found nothing (`brand_not_found`), a ticker, ISIN or crypto symbol we do not know (`identifier_unknown`), the brand was removed or withheld (`brand_removed`, `brand_withheld_nsfw`), the domain is invalid, does not resolve or redirects elsewhere (`domain_invalid`, `domain_unresolvable`, `domain_redirected`), the site could not be read just now (`site_unavailable`), or we are still collecting the brand (`crawl_queued`). Every `404` consumes an API credit. A payment presented with a `404` is settled, except when the response carries `x-bf-error: crawl_queued`: that payment is not charged, the body carries a `payment` object saying so, and the same payment can be presented again for the retry while it is still valid.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "brand_not_found",
                    "identifier_unknown",
                    "brand_removed",
                    "brand_withheld_nsfw",
                    "crawl_queued",
                    "domain_invalid",
                    "domain_unresolvable",
                    "domain_redirected",
                    "site_unavailable"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "payment": {
                          "type": "object",
                          "description": "Present on a paid request answered with `x-bf-error: crawl_queued`.",
                          "properties": {
                            "charged": {
                              "type": "boolean",
                              "enum": [false]
                            },
                            "documentation": {
                              "type": "string",
                              "format": "uri"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "The key's monthly quota is used up (`quota_exceeded`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["quota_exceeded"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "A failure on our side (`internal_error`). Retry; nothing in the request caused it.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["internal_error"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "head": {
        "summary": "Check availability and prefetch a brand",
        "description": "Tells you whether Brandfetch already holds the brand and, when it does not, queues a crawl so that the `GET` which follows is answered from our store instead of waiting on a live crawl. Available on paid plans. A `HEAD` request carries no body and never consumes a credit.\n\n- `200` — the brand is held. A `GET` answers from the store.\n- `202` — the brand is not held and a crawl has been queued. A `GET` made before the crawl finishes still crawls live.\n- `404` — nothing can be fetched for the identifier: an unknown brand ID, ticker, ISIN or crypto symbol, a domain without a public suffix, or a brand that has been removed.\n\nPrefetch requests may be throttled to prevent abuse and ensure quality of service. A typical use is warming a brand at signup: send the new user's email address, and the brand is ready by the time you render it.",
        "operationId": "prefetchBrand",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "identifier",
            "in": "path",
            "description": "Same identifier formats as `GET /v2/brands/{identifier}`: domain, email address, brand ID, stock or ETF ticker, ISIN, or crypto symbol. Only a domain — or the registrable domain of an email address — can have a crawl queued for it; the other kinds answer `200` or `404`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "domain": {
                "summary": "Domain",
                "value": "nike.com"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The brand is held. A `GET` answers from the store.",
            "headers": {
              "x-api-key-quota": {
                "description": "Your organization's API credit quota for the current period. The check itself consumes no credit.",
                "schema": {
                  "type": "integer"
                }
              },
              "x-api-key-approximate-usage": {
                "description": "Credits used so far this period. Usage is counted asynchronously, so the figure trails your latest requests slightly.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "202": {
            "description": "The brand is not held; a crawl has been queued.",
            "headers": {
              "x-api-key-quota": {
                "description": "Your organization's API credit quota for the current period. The check itself consumes no credit.",
                "schema": {
                  "type": "integer"
                }
              },
              "x-api-key-approximate-usage": {
                "description": "Credits used so far this period. Usage is counted asynchronously, so the figure trails your latest requests slightly.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read. `error` says which part: the identifier, the route, the lookup kind, or an email address or URL used as the identifier. A `400` consumes no API credit.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_invalid",
                    "route_invalid",
                    "lookup_kind_invalid",
                    "email_invalid",
                    "url_invalid",
                    "identifier_ambiguous"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "No credential was sent, or the `Authorization` header carries no usable token (`authorization_required`). Send `Authorization: Bearer <api key>`.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), it could not be checked just now (`auth_unavailable`, worth a retry), or your organization is not on a paid plan (`paid_plan_required`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "auth_unavailable", "paid_plan_required"]
                }
              }
            }
          },
          "404": {
            "description": "Nothing can be fetched for the identifier: it is unknown (`identifier_unknown`), its brand was removed (`brand_removed`), it is not a domain we can crawl (`domain_invalid`), or nothing is held for it (`brand_not_found`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["identifier_unknown", "brand_removed", "domain_invalid", "brand_not_found"]
                }
              }
            }
          },
          "429": {
            "description": "Request throughput limit exceeded. The check never consumes your quota, so this is the platform rate limit rather than your allowance."
          },
          "503": {
            "description": "The crawl request could not be queued. Retry later.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["temporarily_unavailable"]
                }
              }
            }
          }
        }
      }
    },
    "/v2/brands/domain/{domain}": {
      "get": {
        "summary": "Get brand data by domain",
        "description": "Get brand data using a domain name. Authenticate with an API key sent as `Authorization: Bearer <key>`, or pay for the single request with x402 or MPP: https://docs.brandfetch.com/agents/pay-per-request.",
        "operationId": "getBrandDataByDomain",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            }
          ],
          "offers": [
            {
              "amount": "100000",
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Brand API request",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "description": "Domain name (e.g., `nike.com`)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "domain": {
                "summary": "Domain",
                "value": "nike.com"
              }
            }
          },
          {
            "name": "allowNsfw",
            "in": "query",
            "required": false,
            "description": "Brandfetch evaluates brands for NSFW content and reserves the right to not return inappropriate brands. Depending on the severity, a brand may either not be returned at all (`404`), or be returned with its `isNsfw` property set to `true`. The `allowNsfw` query parameter lets you control this behavior:\n\n- **Not set** (default) \u2014 Some NSFW brands are not returned (`404`), others are returned with `isNsfw: true`.\n- **`true`** \u2014 Returns the brand regardless of its NSFW status.\n- **`false`** \u2014 Filters out all brands flagged as NSFW (returns `404`).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "cachedOnly",
            "in": "query",
            "description": "When `true`, the Brand API answers from its store alone. A brand that is already indexed is returned as usual, and a brand that is not is answered with `204 No Content` instead of being indexed live, which can take several seconds. Nothing is crawled, and a ticker, ISIN, or crypto symbol that is not yet indexed is not resolved either. A `204` does not count towards your quota. Any value other than `true`, including omitting the parameter, keeps the default behaviour of indexing the brand live on a miss. Defaults to `false`.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "examples": {
              "cachedOnly": {
                "summary": "Cached only (skip crawling)",
                "value": true
              }
            }
          },
          {
            "name": "palette",
            "in": "query",
            "required": false,
            "description": "Opt in to the brand's color palette. Set `true` or `1` to add a `palette` object to the response. If you omit the parameter, or set another value, the response does not change and has no `palette` key.\n\nIf the brand has no palette yet, this request builds one from the brand's last crawl and can take some seconds longer.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "PAYMENT-RESPONSE": {
                "description": "Present on responses paid with x402: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`).",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "Present on responses paid with MPP: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). Such responses also carry `Cache-Control: private`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Successful request. A request paid with MPP whose response was lost can be retried with the same credential for two minutes: it is served from the payment already taken and not charged again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandResponse"
                }
              }
            }
          },
          "204": {
            "description": "Returned when `cachedOnly=true` and the brand is not yet indexed. The response body is empty. Because live indexing is disabled there is nothing to return, and the request does not count towards your quota. Retry without `cachedOnly` to index the brand live."
          },
          "400": {
            "description": "The request could not be read. `error` says which part: the identifier, the route, the lookup kind, or an email address or URL used as the identifier. A `400` consumes no API credit.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_invalid",
                    "route_invalid",
                    "lookup_kind_invalid",
                    "email_invalid",
                    "url_invalid",
                    "identifier_ambiguous"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "The `Authorization` header is present but carries no usable token (`authorization_required`). A request with no credential at all receives a `402` with a payment challenge instead.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Returned when the request carries no credential: no API key, no x402 payment, no MPP credential. The `PAYMENT-REQUIRED` header prices this request at $0.10 in USDC on Base, and each `WWW-Authenticate: Payment` challenge quotes the same price over MPP. Pay either way, or send an API key. Also returned, with a `reason`, when a `PAYMENT-SIGNATURE` or an `Authorization: Payment …` credential was presented but the payment was not accepted or could not be settled. Nothing is charged in that case. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "The MPP challenge: one `Payment` challenge for USDC.e on Tempo, which settles from a cent. Answer it with an `Authorization: Payment …` credential. Cards start at $0.50, above this price, so no card challenge is issued here; a card can pay for standing access on `POST /v2/agents/access`.",
                "schema": {
                  "type": "string"
                }
              },
              "x-bf-error": {
                "description": "Only the header names this refusal: the body is the payment protocols' own.",
                "schema": {
                  "type": "string",
                  "enum": ["payment_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), the plan includes no Brand API credits (`no_api_credits`), or the key could not be checked just now (`auth_unavailable`, worth a retry).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "no_api_credits", "auth_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Nothing can be served for the domain. `error` says why: no brand and the crawl found nothing (`brand_not_found`), the brand was removed or withheld (`brand_removed`, `brand_withheld_nsfw`), the domain is invalid, does not resolve or redirects elsewhere (`domain_invalid`, `domain_unresolvable`, `domain_redirected`), the site could not be read just now (`site_unavailable`), or we are still collecting the brand (`crawl_queued`). Every `404` consumes an API credit. A payment presented with a `404` is settled, except when the response carries `x-bf-error: crawl_queued`: that payment is not charged, the body carries a `payment` object saying so, and the same payment can be presented again for the retry while it is still valid.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "brand_not_found",
                    "brand_removed",
                    "brand_withheld_nsfw",
                    "crawl_queued",
                    "domain_invalid",
                    "domain_unresolvable",
                    "domain_redirected",
                    "site_unavailable"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "payment": {
                          "type": "object",
                          "description": "Present on a paid request answered with `x-bf-error: crawl_queued`.",
                          "properties": {
                            "charged": {
                              "type": "boolean",
                              "enum": [false]
                            },
                            "documentation": {
                              "type": "string",
                              "format": "uri"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "The key's monthly quota is used up (`quota_exceeded`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["quota_exceeded"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "A failure on our side (`internal_error`). Retry; nothing in the request caused it.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["internal_error"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "head": {
        "summary": "Check availability and prefetch a brand",
        "description": "Tells you whether Brandfetch already holds the brand for a domain and, when it does not, queues a crawl so that the `GET` which follows is answered from our store instead of waiting on a live crawl. Available on paid plans. A `HEAD` request carries no body and never consumes a credit.\n\n- `200` \u2014 the brand is held. A `GET` answers from the store.\n- `202` \u2014 the brand is not held and a crawl has been queued. A `GET` made before the crawl finishes still crawls live.\n- `404` \u2014 nothing can be fetched: the domain has no public suffix, or its brand has been removed.\n\nThis route accepts a domain only; like the other explicit type routes it refuses an email address with a `400`. Prefetch requests may be throttled to prevent abuse and ensure quality of service.",
        "operationId": "prefetchBrandByDomain",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "description": "Domain name (e.g., `nike.com`)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "domain": {
                "summary": "Domain",
                "value": "nike.com"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The brand is held. A `GET` answers from the store.",
            "headers": {
              "x-api-key-quota": {
                "description": "Your organization's API credit quota for the current period. The check itself consumes no credit.",
                "schema": {
                  "type": "integer"
                }
              },
              "x-api-key-approximate-usage": {
                "description": "Credits used so far this period. Usage is counted asynchronously, so the figure trails your latest requests slightly.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "202": {
            "description": "The brand is not held; a crawl has been queued.",
            "headers": {
              "x-api-key-quota": {
                "description": "Your organization's API credit quota for the current period. The check itself consumes no credit.",
                "schema": {
                  "type": "integer"
                }
              },
              "x-api-key-approximate-usage": {
                "description": "Credits used so far this period. Usage is counted asynchronously, so the figure trails your latest requests slightly.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read. `error` says which part: the identifier, the route, the lookup kind, or an email address or URL used as the identifier. A `400` consumes no API credit.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_invalid",
                    "route_invalid",
                    "lookup_kind_invalid",
                    "email_invalid",
                    "url_invalid",
                    "identifier_ambiguous"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "No credential was sent, or the `Authorization` header carries no usable token (`authorization_required`). Send `Authorization: Bearer <api key>`.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), it could not be checked just now (`auth_unavailable`, worth a retry), or your organization is not on a paid plan (`paid_plan_required`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "auth_unavailable", "paid_plan_required"]
                }
              }
            }
          },
          "404": {
            "description": "Nothing can be fetched for the identifier: it is unknown (`identifier_unknown`), its brand was removed (`brand_removed`), it is not a domain we can crawl (`domain_invalid`), or nothing is held for it (`brand_not_found`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["identifier_unknown", "brand_removed", "domain_invalid", "brand_not_found"]
                }
              }
            }
          },
          "429": {
            "description": "Request throughput limit exceeded. The check never consumes your quota, so this is the platform rate limit rather than your allowance."
          },
          "503": {
            "description": "The crawl request could not be queued. Retry later.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. A `HEAD` has no body, so the header is the only place the code appears.",
                "schema": {
                  "type": "string",
                  "enum": ["temporarily_unavailable"]
                }
              }
            }
          }
        }
      }
    },
    "/v2/brands/ticker/{ticker}": {
      "get": {
        "summary": "Get brand data by Stock or ETF ticker",
        "description": "Get brand data using a Stock or ETF ticker. Authenticate with an API key sent as `Authorization: Bearer <key>`, or pay for the single request with x402 or MPP: https://docs.brandfetch.com/agents/pay-per-request.",
        "operationId": "getBrandDataByTicker",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            }
          ],
          "offers": [
            {
              "amount": "100000",
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Brand API request",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "parameters": [
          {
            "name": "ticker",
            "in": "path",
            "description": "Stock or ETF ticker (e.g., `NKE`, `QQQ`)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "ticker": {
                "summary": "Stock or ETF ticker",
                "value": "NKE"
              }
            }
          },
          {
            "name": "allowNsfw",
            "in": "query",
            "required": false,
            "description": "Brandfetch evaluates brands for NSFW content and reserves the right to not return inappropriate brands. Depending on the severity, a brand may either not be returned at all (`404`), or be returned with its `isNsfw` property set to `true`. The `allowNsfw` query parameter lets you control this behavior:\n\n- **Not set** (default) \u2014 Some NSFW brands are not returned (`404`), others are returned with `isNsfw: true`.\n- **`true`** \u2014 Returns the brand regardless of its NSFW status.\n- **`false`** \u2014 Filters out all brands flagged as NSFW (returns `404`).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "cachedOnly",
            "in": "query",
            "description": "When `true`, the Brand API answers from its store alone. A brand that is already indexed is returned as usual, and a brand that is not is answered with `204 No Content` instead of being indexed live, which can take several seconds. Nothing is crawled, and a ticker, ISIN, or crypto symbol that is not yet indexed is not resolved either. A `204` does not count towards your quota. Any value other than `true`, including omitting the parameter, keeps the default behaviour of indexing the brand live on a miss. Defaults to `false`.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "examples": {
              "cachedOnly": {
                "summary": "Cached only (skip crawling)",
                "value": true
              }
            }
          },
          {
            "name": "palette",
            "in": "query",
            "required": false,
            "description": "Opt in to the brand's color palette. Set `true` or `1` to add a `palette` object to the response. If you omit the parameter, or set another value, the response does not change and has no `palette` key.\n\nIf the brand has no palette yet, this request builds one from the brand's last crawl and can take some seconds longer.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "PAYMENT-RESPONSE": {
                "description": "Present on responses paid with x402: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`).",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "Present on responses paid with MPP: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). Such responses also carry `Cache-Control: private`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Successful request. A request paid with MPP whose response was lost can be retried with the same credential for two minutes: it is served from the payment already taken and not charged again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandResponse"
                }
              }
            }
          },
          "204": {
            "description": "Returned when `cachedOnly=true` and the brand is not yet indexed. The response body is empty. Because live indexing is disabled there is nothing to return, and the request does not count towards your quota. Retry without `cachedOnly` to index the brand live."
          },
          "400": {
            "description": "The request could not be read. `error` says which part: the identifier, the route, the lookup kind, or an email address or URL used as the identifier. A `400` consumes no API credit.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_invalid",
                    "route_invalid",
                    "lookup_kind_invalid",
                    "email_invalid",
                    "url_invalid",
                    "identifier_ambiguous"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "The `Authorization` header is present but carries no usable token (`authorization_required`). A request with no credential at all receives a `402` with a payment challenge instead.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Returned when the request carries no credential: no API key, no x402 payment, no MPP credential. The `PAYMENT-REQUIRED` header prices this request at $0.10 in USDC on Base, and each `WWW-Authenticate: Payment` challenge quotes the same price over MPP. Pay either way, or send an API key. Also returned, with a `reason`, when a `PAYMENT-SIGNATURE` or an `Authorization: Payment …` credential was presented but the payment was not accepted or could not be settled. Nothing is charged in that case. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "The MPP challenge: one `Payment` challenge for USDC.e on Tempo, which settles from a cent. Answer it with an `Authorization: Payment …` credential. Cards start at $0.50, above this price, so no card challenge is issued here; a card can pay for standing access on `POST /v2/agents/access`.",
                "schema": {
                  "type": "string"
                }
              },
              "x-bf-error": {
                "description": "Only the header names this refusal: the body is the payment protocols' own.",
                "schema": {
                  "type": "string",
                  "enum": ["payment_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), the plan includes no Brand API credits (`no_api_credits`), or the key could not be checked just now (`auth_unavailable`, worth a retry).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "no_api_credits", "auth_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Nothing can be served for the identifier. `error` says why: the identifier is unknown (`identifier_unknown`), the brand was removed or withheld (`brand_removed`, `brand_withheld_nsfw`), the domain it resolves to is invalid, does not resolve or redirects elsewhere (`domain_invalid`, `domain_unresolvable`, `domain_redirected`), the site could not be read just now (`site_unavailable`), or we are still collecting the brand (`crawl_queued`). Every `404` consumes an API credit. A payment presented with a `404` is settled, except when the response carries `x-bf-error: crawl_queued`: that payment is not charged, the body carries a `payment` object saying so, and the same payment can be presented again for the retry while it is still valid.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_unknown",
                    "brand_not_found",
                    "brand_removed",
                    "brand_withheld_nsfw",
                    "crawl_queued",
                    "domain_invalid",
                    "domain_unresolvable",
                    "domain_redirected",
                    "site_unavailable"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "payment": {
                          "type": "object",
                          "description": "Present on a paid request answered with `x-bf-error: crawl_queued`.",
                          "properties": {
                            "charged": {
                              "type": "boolean",
                              "enum": [false]
                            },
                            "documentation": {
                              "type": "string",
                              "format": "uri"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "The key's monthly quota is used up (`quota_exceeded`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["quota_exceeded"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "A failure on our side (`internal_error`). Retry; nothing in the request caused it.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["internal_error"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v2/brands/isin/{isin}": {
      "get": {
        "summary": "Get brand data by ISIN",
        "description": "Get brand data using an ISIN code. Authenticate with an API key sent as `Authorization: Bearer <key>`, or pay for the single request with x402 or MPP: https://docs.brandfetch.com/agents/pay-per-request.",
        "operationId": "getBrandDataByIsin",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            }
          ],
          "offers": [
            {
              "amount": "100000",
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Brand API request",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "parameters": [
          {
            "name": "isin",
            "in": "path",
            "description": "ISIN code (e.g., `US6541061031`)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "isin": {
                "summary": "ISIN",
                "value": "US6541061031"
              }
            }
          },
          {
            "name": "allowNsfw",
            "in": "query",
            "required": false,
            "description": "Brandfetch evaluates brands for NSFW content and reserves the right to not return inappropriate brands. Depending on the severity, a brand may either not be returned at all (`404`), or be returned with its `isNsfw` property set to `true`. The `allowNsfw` query parameter lets you control this behavior:\n\n- **Not set** (default) \u2014 Some NSFW brands are not returned (`404`), others are returned with `isNsfw: true`.\n- **`true`** \u2014 Returns the brand regardless of its NSFW status.\n- **`false`** \u2014 Filters out all brands flagged as NSFW (returns `404`).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "cachedOnly",
            "in": "query",
            "description": "When `true`, the Brand API answers from its store alone. A brand that is already indexed is returned as usual, and a brand that is not is answered with `204 No Content` instead of being indexed live, which can take several seconds. Nothing is crawled, and a ticker, ISIN, or crypto symbol that is not yet indexed is not resolved either. A `204` does not count towards your quota. Any value other than `true`, including omitting the parameter, keeps the default behaviour of indexing the brand live on a miss. Defaults to `false`.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "examples": {
              "cachedOnly": {
                "summary": "Cached only (skip crawling)",
                "value": true
              }
            }
          },
          {
            "name": "palette",
            "in": "query",
            "required": false,
            "description": "Opt in to the brand's color palette. Set `true` or `1` to add a `palette` object to the response. If you omit the parameter, or set another value, the response does not change and has no `palette` key.\n\nIf the brand has no palette yet, this request builds one from the brand's last crawl and can take some seconds longer.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "PAYMENT-RESPONSE": {
                "description": "Present on responses paid with x402: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`).",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "Present on responses paid with MPP: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). Such responses also carry `Cache-Control: private`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Successful request. A request paid with MPP whose response was lost can be retried with the same credential for two minutes: it is served from the payment already taken and not charged again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandResponse"
                }
              }
            }
          },
          "204": {
            "description": "Returned when `cachedOnly=true` and the brand is not yet indexed. The response body is empty. Because live indexing is disabled there is nothing to return, and the request does not count towards your quota. Retry without `cachedOnly` to index the brand live."
          },
          "400": {
            "description": "The request could not be read. `error` says which part: the identifier, the route, the lookup kind, or an email address or URL used as the identifier. A `400` consumes no API credit.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_invalid",
                    "route_invalid",
                    "lookup_kind_invalid",
                    "email_invalid",
                    "url_invalid",
                    "identifier_ambiguous"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "The `Authorization` header is present but carries no usable token (`authorization_required`). A request with no credential at all receives a `402` with a payment challenge instead.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Returned when the request carries no credential: no API key, no x402 payment, no MPP credential. The `PAYMENT-REQUIRED` header prices this request at $0.10 in USDC on Base, and each `WWW-Authenticate: Payment` challenge quotes the same price over MPP. Pay either way, or send an API key. Also returned, with a `reason`, when a `PAYMENT-SIGNATURE` or an `Authorization: Payment …` credential was presented but the payment was not accepted or could not be settled. Nothing is charged in that case. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "The MPP challenge: one `Payment` challenge for USDC.e on Tempo, which settles from a cent. Answer it with an `Authorization: Payment …` credential. Cards start at $0.50, above this price, so no card challenge is issued here; a card can pay for standing access on `POST /v2/agents/access`.",
                "schema": {
                  "type": "string"
                }
              },
              "x-bf-error": {
                "description": "Only the header names this refusal: the body is the payment protocols' own.",
                "schema": {
                  "type": "string",
                  "enum": ["payment_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), the plan includes no Brand API credits (`no_api_credits`), or the key could not be checked just now (`auth_unavailable`, worth a retry).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "no_api_credits", "auth_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Nothing can be served for the identifier. `error` says why: the identifier is unknown (`identifier_unknown`), the brand was removed or withheld (`brand_removed`, `brand_withheld_nsfw`), the domain it resolves to is invalid, does not resolve or redirects elsewhere (`domain_invalid`, `domain_unresolvable`, `domain_redirected`), the site could not be read just now (`site_unavailable`), or we are still collecting the brand (`crawl_queued`). Every `404` consumes an API credit. A payment presented with a `404` is settled, except when the response carries `x-bf-error: crawl_queued`: that payment is not charged, the body carries a `payment` object saying so, and the same payment can be presented again for the retry while it is still valid.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_unknown",
                    "brand_not_found",
                    "brand_removed",
                    "brand_withheld_nsfw",
                    "crawl_queued",
                    "domain_invalid",
                    "domain_unresolvable",
                    "domain_redirected",
                    "site_unavailable"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "payment": {
                          "type": "object",
                          "description": "Present on a paid request answered with `x-bf-error: crawl_queued`.",
                          "properties": {
                            "charged": {
                              "type": "boolean",
                              "enum": [false]
                            },
                            "documentation": {
                              "type": "string",
                              "format": "uri"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "The key's monthly quota is used up (`quota_exceeded`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["quota_exceeded"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "A failure on our side (`internal_error`). Retry; nothing in the request caused it.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["internal_error"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v2/brands/crypto/{symbol}": {
      "get": {
        "summary": "Get brand data by crypto symbol",
        "description": "Get brand data using a crypto symbol. Authenticate with an API key sent as `Authorization: Bearer <key>`, or pay for the single request with x402 or MPP: https://docs.brandfetch.com/agents/pay-per-request.",
        "operationId": "getBrandDataByCrypto",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            }
          ],
          "offers": [
            {
              "amount": "100000",
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Brand API request",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "parameters": [
          {
            "name": "symbol",
            "in": "path",
            "description": "Crypto symbol (e.g., `BTC`, `ETH`). Uppercase preferred.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "crypto": {
                "summary": "Crypto symbol",
                "value": "BTC"
              }
            }
          },
          {
            "name": "allowNsfw",
            "in": "query",
            "required": false,
            "description": "Brandfetch evaluates brands for NSFW content and reserves the right to not return inappropriate brands. Depending on the severity, a brand may either not be returned at all (`404`), or be returned with its `isNsfw` property set to `true`. The `allowNsfw` query parameter lets you control this behavior:\n\n- **Not set** (default) \u2014 Some NSFW brands are not returned (`404`), others are returned with `isNsfw: true`.\n- **`true`** \u2014 Returns the brand regardless of its NSFW status.\n- **`false`** \u2014 Filters out all brands flagged as NSFW (returns `404`).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "cachedOnly",
            "in": "query",
            "description": "When `true`, the Brand API answers from its store alone. A brand that is already indexed is returned as usual, and a brand that is not is answered with `204 No Content` instead of being indexed live, which can take several seconds. Nothing is crawled, and a ticker, ISIN, or crypto symbol that is not yet indexed is not resolved either. A `204` does not count towards your quota. Any value other than `true`, including omitting the parameter, keeps the default behaviour of indexing the brand live on a miss. Defaults to `false`.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "examples": {
              "cachedOnly": {
                "summary": "Cached only (skip crawling)",
                "value": true
              }
            }
          },
          {
            "name": "palette",
            "in": "query",
            "required": false,
            "description": "Opt in to the brand's color palette. Set `true` or `1` to add a `palette` object to the response. If you omit the parameter, or set another value, the response does not change and has no `palette` key.\n\nIf the brand has no palette yet, this request builds one from the brand's last crawl and can take some seconds longer.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "PAYMENT-RESPONSE": {
                "description": "Present on responses paid with x402: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`).",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "Present on responses paid with MPP: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). Such responses also carry `Cache-Control: private`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Successful request. A request paid with MPP whose response was lost can be retried with the same credential for two minutes: it is served from the payment already taken and not charged again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandResponse"
                }
              }
            }
          },
          "204": {
            "description": "Returned when `cachedOnly=true` and the brand is not yet indexed. The response body is empty. Because live indexing is disabled there is nothing to return, and the request does not count towards your quota. Retry without `cachedOnly` to index the brand live."
          },
          "400": {
            "description": "The request could not be read. `error` says which part: the identifier, the route, the lookup kind, or an email address or URL used as the identifier. A `400` consumes no API credit.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_invalid",
                    "route_invalid",
                    "lookup_kind_invalid",
                    "email_invalid",
                    "url_invalid",
                    "identifier_ambiguous"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "The `Authorization` header is present but carries no usable token (`authorization_required`). A request with no credential at all receives a `402` with a payment challenge instead.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Returned when the request carries no credential: no API key, no x402 payment, no MPP credential. The `PAYMENT-REQUIRED` header prices this request at $0.10 in USDC on Base, and each `WWW-Authenticate: Payment` challenge quotes the same price over MPP. Pay either way, or send an API key. Also returned, with a `reason`, when a `PAYMENT-SIGNATURE` or an `Authorization: Payment …` credential was presented but the payment was not accepted or could not be settled. Nothing is charged in that case. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "The MPP challenge: one `Payment` challenge for USDC.e on Tempo, which settles from a cent. Answer it with an `Authorization: Payment …` credential. Cards start at $0.50, above this price, so no card challenge is issued here; a card can pay for standing access on `POST /v2/agents/access`.",
                "schema": {
                  "type": "string"
                }
              },
              "x-bf-error": {
                "description": "Only the header names this refusal: the body is the payment protocols' own.",
                "schema": {
                  "type": "string",
                  "enum": ["payment_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), the plan includes no Brand API credits (`no_api_credits`), or the key could not be checked just now (`auth_unavailable`, worth a retry).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "no_api_credits", "auth_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Nothing can be served for the identifier. `error` says why: the identifier is unknown (`identifier_unknown`), the brand was removed or withheld (`brand_removed`, `brand_withheld_nsfw`), the domain it resolves to is invalid, does not resolve or redirects elsewhere (`domain_invalid`, `domain_unresolvable`, `domain_redirected`), the site could not be read just now (`site_unavailable`), or we are still collecting the brand (`crawl_queued`). Every `404` consumes an API credit. A payment presented with a `404` is settled, except when the response carries `x-bf-error: crawl_queued`: that payment is not charged, the body carries a `payment` object saying so, and the same payment can be presented again for the retry while it is still valid.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "identifier_unknown",
                    "brand_not_found",
                    "brand_removed",
                    "brand_withheld_nsfw",
                    "crawl_queued",
                    "domain_invalid",
                    "domain_unresolvable",
                    "domain_redirected",
                    "site_unavailable"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "payment": {
                          "type": "object",
                          "description": "Present on a paid request answered with `x-bf-error: crawl_queued`.",
                          "properties": {
                            "charged": {
                              "type": "boolean",
                              "enum": [false]
                            },
                            "documentation": {
                              "type": "string",
                              "format": "uri"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "The key's monthly quota is used up (`quota_exceeded`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["quota_exceeded"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "A failure on our side (`internal_error`). Retry; nothing in the request caused it.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["internal_error"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v2/search/{name}?c={clientId}": {
      "get": {
        "summary": "Search brands",
        "description": "Search for brands by name. Log in to get a clientId",
        "operationId": "searchBrands",
        "security": [
          {
            "clientId": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "The name of the company you are searching for.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "c",
            "in": "query",
            "description": "A clientId is a unique identifier assigned to your application that allows it to authenticate and interact with our service. [Get your client ID here](https://developers.brandfetch.com)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "429": {
            "description": "Refused. The organization behind the client ID has searched far beyond its monthly Brand Search allowance, the client ID went over its throughput limit of 6,000 requests per 5 minutes, or the per-IP throughput limit of 200 requests per 5 minutes was exceeded. All three carry a JSON body with a `message`. The first two also carry `x-bf-error` naming the reason (`quota_exceeded` or `rate_limited`), the same code in `error`, and a `docs` link; the allowance refusal lifts when the allowance is raised or the billing period rolls over, the client ID throughput refusal once the rate falls back under the limit. The per-IP refusal carries neither the header nor `error`. See [rate limits](/brand-search-api/overview#rate-limits).",
            "headers": {
              "x-bf-error": {
                "description": "Present when the edge refused the request for exceeding the monthly allowance or the client ID throughput limit. Absent on a per-IP throughput refusal.",
                "schema": {
                  "type": "string",
                  "enum": ["quota_exceeded", "rate_limited"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["message"],
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "Present on the allowance and client ID throughput refusals, matching the `x-bf-error` header.",
                      "enum": ["quota_exceeded", "rate_limited"]
                    },
                    "message": {
                      "type": "string",
                      "example": "Slow down."
                    },
                    "docs": {
                      "type": "string",
                      "format": "uri",
                      "description": "Present on the allowance and client ID throughput refusals.",
                      "example": "https://docs.brandfetch.com/brand-search-api/overview#errors"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The search could not be answered. Retry after about 10 seconds: an identical request made sooner can get the same response. A `503` does not count towards your Brand Search allowance. See [errors](/brand-search-api/overview#errors).",
            "headers": {
              "x-bf-error": {
                "description": "`temporarily_unavailable` when the search itself failed.",
                "schema": {
                  "type": "string",
                  "enum": ["temporarily_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["message"],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Brand Search is temporarily unavailable. Please retry."
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Returns brand data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "icon": {
                        "type": "string",
                        "description": "Brand icon URL",
                        "nullable": true
                      },
                      "name": {
                        "type": "string",
                        "description": "Brand name",
                        "nullable": true
                      },
                      "domain": {
                        "type": "string",
                        "description": "Brand website URL",
                        "nullable": false
                      },
                      "claimed": {
                        "type": "boolean",
                        "description": "Set to true if the owner of the brand claimed its brand profile on [Brandfetch](https://brandfetch.com)"
                      },
                      "brandId": {
                        "type": "string",
                        "description": "Unique identifier for the brand"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/context/{domain}": {
      "get": {
        "summary": "Get brand context by domain",
        "description": "Get a structured, narrative-rich brand context for a domain \u2014 including identity, positioning, products and services, voice, visual style, and competitors. Authenticate with an API key sent as `Authorization: Bearer <key>`, or pay for the single request with x402 or MPP: https://docs.brandfetch.com/agents/pay-per-request.",
        "operationId": "getBrandContext",
        "tags": ["context"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            }
          ],
          "offers": [
            {
              "amount": "100000",
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Brand Context API request",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "description": "Domain name (`brandfetch.com`), a website URL on the domain (`https://www.brandfetch.com/developers/pricing`), or an email address on the domain (`john@example.brandfetch.com`). The API resolves a website URL or an email address to its registrable domain before the lookup. It does not store the URL or the address. Your request logs show only the domain. A URL whose host is not a domain name returns `400`. A malformed address also returns `400`. The API does not bill these requests.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "domain": {
                "summary": "Domain",
                "value": "brandfetch.com"
              },
              "email": {
                "summary": "Email address",
                "value": "john@example.brandfetch.com"
              },
              "url": {
                "summary": "Website URL",
                "value": "https://www.brandfetch.com/developers/pricing"
              }
            }
          },
          {
            "name": "cachedOnly",
            "in": "query",
            "description": "When `true`, return a brand context only if one is already cached, responding instantly without crawling the domain. If no cached context exists, the API responds with `204 No Content` instead of resolving the domain live (which can take several seconds). Useful for latency-sensitive use cases. Any value other than `true` (including omitting the parameter) keeps the default behaviour of resolving the domain live on a cache miss. Defaults to `false`.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "examples": {
              "cachedOnly": {
                "summary": "Cached only (skip crawling)",
                "value": true
              }
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "PAYMENT-RESPONSE": {
                "description": "Present on responses paid with x402: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`).",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "Present on responses paid with MPP: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). Such responses also carry `Cache-Control: private`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Successful request. The response format is determined by the `Accept` header: `application/json` returns a structured JSON object, while `text/markdown` returns the brand context as Markdown. A request paid with MPP whose response was lost can be retried with the same credential for two minutes: it is served from the payment already taken and not charged again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandContextResponse"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string",
                  "description": "The brand context rendered as Markdown."
                }
              }
            }
          },
          "204": {
            "description": "Returned when `cachedOnly=true` and no brand context is currently cached for the domain. The response body is empty. Because crawling is disabled there is nothing to return. Retry without `cachedOnly` to resolve the domain live."
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "enum": ["Bad Request"]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized. Returned when the `Authorization` header is present but malformed. A request with no credential at all receives a `402` with a payment challenge instead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "enum": ["Unauthorized"]
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Returned when the request carries no credential: no API key, no x402 payment, no MPP credential. The `PAYMENT-REQUIRED` header prices this request at $0.10 in USDC on Base, and each `WWW-Authenticate: Payment` challenge quotes the same price over MPP. Pay either way, or send an API key. Also returned, with a `reason`, when a `PAYMENT-SIGNATURE` or an `Authorization: Payment …` credential was presented but the payment was not accepted or could not be settled. Nothing is charged in that case. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "The MPP challenge: one `Payment` challenge for USDC.e on Tempo, which settles from a cent. Answer it with an `Authorization: Payment …` credential. Cards start at $0.50, above this price, so no card challenge is issued here; a card can pay for standing access on `POST /v2/agents/access`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Returned when no brand context could be generated for the domain, for example because the domain does not resolve or its site has no usable content. A `404` is not charged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "enum": ["<Not Found> or <Invalid Domain Name>"]
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The domain's site blocks automated requests, so no brand context can be generated for it. Retrying is unlikely to help. A `422` is not charged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["message"],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "We couldn't read this domain (the site appears to block automated requests)."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "API key quota exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "enum": ["API key quota exceeded"]
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The brand context is not ready yet, or the Brand Context API could not answer. The `x-bf-error` header says which, and neither is charged. With `generation_in_progress`, the domain is still being resolved live: retry the request after the number of seconds in `Retry-After`. The retry returns the context once it is ready, or the error if generation failed. With `temporarily_unavailable`, retry shortly. A `503` without an `x-bf-error` header on a paid request comes from the payment service instead: retry after the `Retry-After` interval; after an MPP credential, retry the exact request with the same credential, and a payment that went through is not charged twice. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "x-bf-error": {
                "description": "`generation_in_progress` when the context is still being generated, `temporarily_unavailable` when the Brand Context API could not answer.",
                "schema": {
                  "type": "string",
                  "enum": ["generation_in_progress", "temporarily_unavailable"]
                }
              },
              "Retry-After": {
                "description": "The number of seconds to wait before retrying. Present with `generation_in_progress` and on a payment service `503`.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["message"],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "The brand context for this domain is still being generated. Retry in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/brands/transaction": {
      "post": {
        "summary": "Get brand data from a transaction",
        "description": "Turn payment transactions into merchant data. Authenticate with an API key sent as `Authorization: Bearer <key>`, or pay for the single request with x402 or MPP: https://docs.brandfetch.com/agents/pay-per-request.",
        "operationId": "getBrandFromTransaction",
        "tags": ["brands"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            }
          ],
          "offers": [
            {
              "amount": "100000",
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Transaction API request",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "transactionLabel": {
                    "type": "string",
                    "description": "The raw transaction text.",
                    "example": "STARBUCKS 1523 OMAHA NE"
                  },
                  "countryCode": {
                    "type": "string",
                    "description": "An ISO 3166-1 alpha-2 country code indicating the country where the transaction took place.",
                    "example": "US"
                  }
                },
                "required": ["transactionLabel", "countryCode"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "PAYMENT-RESPONSE": {
                "description": "Present on responses paid with x402: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`).",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "Present on responses paid with MPP: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). Such responses also carry `Cache-Control: private`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Successful request. A request paid with MPP whose response was lost can be retried with the same credential and the same body for two minutes: it is served from the payment already taken and not charged again. The credential pays for that transaction only: presented with another `transactionLabel` or `countryCode`, it is refused with a `402` whose `reason` is `credential_spent`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandResponse"
                }
              }
            }
          },
          "400": {
            "description": "Either the request was malformed, or the descriptor could not be confidently matched to a merchant. A malformed request is a missing or empty `transactionLabel` or `countryCode`, or a `countryCode` that names no country; the message names the offending field. A descriptor that could not be matched carries `reason: low_confidence` and the message `We couldn't match this transaction to a brand with enough confidence. Retrying won't change the result; a more complete merchant descriptor may.` A `countryCode` that names no country carries `reason: invalid_country`. Retrying does not change either case, so fall back to showing the raw descriptor. For a temporary failure on our side, which is worth retrying, see `503`. Neither case is charged: it consumes no API credit, and a payment presented with it is not settled. A malformed body is answered `400` whatever credential the request carries, and a request without a credential is quoted a price only once its body is complete. `error` names the case: `body_invalid` for a malformed body, a `countryCode` that names no country included, and `transaction_unmatched` for a descriptor that could not be matched.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["body_invalid", "transaction_unmatched"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "reason": {
                          "type": "string",
                          "enum": ["low_confidence", "invalid_country"],
                          "description": "Why the request was refused, when it was not for a missing or empty field: `low_confidence` when the descriptor could not be confidently matched to a merchant, `invalid_country` when `countryCode` names no country.",
                          "example": "low_confidence"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The `Authorization` header is present but carries no usable token (`authorization_required`). A request with no credential at all receives a `402` with a payment challenge instead.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["authorization_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Returned when the request carries no credential: no API key, no x402 payment, no MPP credential. The `PAYMENT-REQUIRED` header prices this request at $0.10 in USDC on Base, and each `WWW-Authenticate: Payment` challenge quotes the same price over MPP. Pay either way, or send an API key. Also returned, with a `reason`, when a `PAYMENT-SIGNATURE` or an `Authorization: Payment …` credential was presented but the payment was not accepted or could not be settled. Nothing is charged in that case. See https://docs.brandfetch.com/agents/pay-per-request.",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "The MPP challenge: one `Payment` challenge for USDC.e on Tempo, which settles from a cent. It is issued for the transaction the request body names, so answer it with an `Authorization: Payment …` credential and send the same body again. Cards start at $0.50, above this price, so no card challenge is issued here; a card can pay for standing access on `POST /v2/agents/access`.",
                "schema": {
                  "type": "string"
                }
              },
              "x-bf-error": {
                "description": "Only the header names this refusal: the body is the payment protocols' own.",
                "schema": {
                  "type": "string",
                  "enum": ["payment_required"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The credential was refused: the key is unknown or revoked (`api_key_invalid`), the plan includes no Brand API credits (`no_api_credits`), or the key could not be checked just now (`auth_unavailable`, worth a retry).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["api_key_invalid", "no_api_credits", "auth_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found. The transaction label was matched to a domain, but there is no brand data to return for it. Like a `200`, it consumes an API credit. A payment presented with it is settled, except when the response carries `x-bf-error: crawl_queued`. That header means we did not hold the brand yet and have started collecting it: retry the same request in a minute or two; if the brand could be collected, the retry is served it, and otherwise it answers an ordinary `404`, which a payment is charged for. A paid request answered this way is not charged, and its body carries a `payment` object saying so; the same payment can be presented again for the retry while it is still valid. `error` says why, with the same codes as `GET /v2/brands/{identifier}`.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "brand_not_found",
                    "brand_removed",
                    "brand_withheld_nsfw",
                    "crawl_queued",
                    "domain_invalid",
                    "domain_unresolvable",
                    "domain_redirected",
                    "site_unavailable"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "payment": {
                          "type": "object",
                          "description": "Present on a paid request answered with `x-bf-error: crawl_queued`.",
                          "properties": {
                            "charged": {
                              "type": "boolean",
                              "enum": [false]
                            },
                            "documentation": {
                              "type": "string",
                              "format": "uri"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "The key's monthly quota is used up (`quota_exceeded`).",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["quota_exceeded"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "A failure on our side (`internal_error`). Retry; nothing in the request caused it.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["internal_error"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Brandfetch was temporarily unable to process the request. The request itself was valid, so retrying it is safe and may succeed. An enrichment `503` never consumes an API credit, and a payment presented with it is not settled. A `503` with `Retry-After` on a paid request comes from the payment service instead: it could not be reached, or, after an MPP credential, whether the payment went through is not known yet. Retry after the interval; after an MPP credential, retry the exact request with the same credential, and a payment that went through is not charged twice. See https://docs.brandfetch.com/agents/pay-per-request. This is distinct from a `400` saying the transaction could not be matched to a brand with enough confidence: retrying that returns the same answer. A `503` from the payment service carries the `x-bf-error` header only; its body says what to retry with.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused. The same value as `error` in the body.",
                "schema": {
                  "type": "string",
                  "enum": ["temporarily_unavailable"]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "type": "object",
                      "description": "The payment service's own answer, with the `x-bf-error` header but without `error` and `docs` in the body.",
                      "required": ["message"],
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v2/brands/batch": {
      "post": {
        "summary": "Get up to 100 brands in one request",
        "description": "Send up to 100 identifiers. Get one result per identifier, in the order you sent them. Each identifier is answered the way `GET /v2/brands/{identifier}` answers it.\n\nOne difference: a batch never crawls while you wait. A brand that is not indexed yet is queued for indexing and answered `202`. Request it again later.\n\nEach identifier answered `200` uses one API credit. Every other result is free, `404` included. An identifier repeated in one request is charged once.\n\nAvailable on paid plans and with prepaid credits. Authenticate with an API key sent as `Authorization: Bearer <key>`.",
        "operationId": "getBrandBatch",
        "tags": [
          "brands"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "identifiers"
                ],
                "properties": {
                  "identifiers": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "description": "The brands to look up. A string is read as the `identifier` of `GET /v2/brands/{identifier}`: a domain, website URL, email address, brand ID, ticker or ISIN. An object names the identifier's type, as `GET /v2/brands/{type}/{identifier}` does. An exchange-suffixed ticker sent as a string, such as `bhp.ax`, is read as a domain: send it as `{ \"type\": \"ticker\", \"value\": \"BHP.AX\" }`.",
                    "items": {
                      "oneOf": [
                        {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 2048,
                          "example": "nike.com"
                        },
                        {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "type",
                            "value"
                          ],
                          "properties": {
                            "type": {
                              "type": "string",
                              "enum": [
                                "domain",
                                "ticker",
                                "isin",
                                "crypto",
                                "brandId"
                              ]
                            },
                            "value": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 2048
                            }
                          },
                          "example": {
                            "type": "ticker",
                            "value": "NKE"
                          }
                        }
                      ]
                    },
                    "example": [
                      "nike.com",
                      "https://www.spotify.com/about",
                      {
                        "type": "ticker",
                        "value": "NKE"
                      }
                    ]
                  },
                  "cachedOnly": {
                    "type": "boolean",
                    "default": false,
                    "description": "Answer from the index alone. A brand that is not indexed is answered `204` and is not queued, and a ticker, ISIN or crypto symbol that is not indexed is not resolved. A `204` is free."
                  },
                  "allowNsfw": {
                    "type": "boolean",
                    "description": "As `allowNsfw` on `GET /v2/brands/{identifier}`. Not set by default."
                  },
                  "palette": {
                    "type": "boolean",
                    "default": false,
                    "description": "As `palette` on `GET /v2/brands/{identifier}`: add each brand's `palette`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One result per identifier, in the order you sent them.",
            "headers": {
              "x-api-key-quota": {
                "description": "Your organization's API credit quota for the current period.",
                "schema": {
                  "type": "integer"
                }
              },
              "x-api-key-approximate-usage": {
                "description": "Credits used this period, including the ones this request uses. Usage is counted asynchronously, so the figure trails your latest requests slightly.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "identifier",
                          "status"
                        ],
                        "properties": {
                          "identifier": {
                            "description": "The identifier you sent, with surrounding whitespace removed.",
                            "oneOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "object"
                              }
                            ]
                          },
                          "status": {
                            "type": "integer",
                            "enum": [
                              200,
                              202,
                              204,
                              400,
                              404,
                              413,
                              500,
                              504
                            ],
                            "description": "- `200` — `brand` holds the brand.\n- `202` — the brand is not indexed yet and is queued for indexing (`code`: `crawl_queued`). Request it again later. Free.\n- `204` — with `cachedOnly`, the brand is not indexed. Nothing is queued. Free.\n- `400` — not a valid identifier. `message` says why. Free.\n- `404` — no brand can be returned for the identifier. `message` gives the reason. Free.\n- `413` — the brand did not fit in this response (`code`: `response_too_large`). Request it again in a smaller batch. Free.\n- `500` — the identifier could not be looked up. Request it again. Free.\n- `504` — the identifier could not be looked up in time (`code`: `timeout`). Request it again. Free."
                          },
                          "brand": {
                            "$ref": "#/components/schemas/BrandResponse"
                          },
                          "code": {
                            "type": "string",
                            "enum": [
                              "crawl_queued",
                              "response_too_large",
                              "timeout"
                            ]
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request body is malformed: `identifiers` is missing, empty or longer than 100, an item is neither a string nor a `{ type, value }` object, or the body has a property the API does not take. `message` names the problem. Nothing is charged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "No API key was sent, or the `Authorization` header is malformed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The API key is unknown or revoked, or your organization has no API credits. With `x-bf-error: paid_plan_required`, your organization is on the free plan and holds no prepaid credits.",
            "headers": {
              "x-bf-error": {
                "description": "Why the request was refused.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "paid_plan_required"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Your organization has fewer API credits left than this request could use. `required` is the number of identifiers that could be charged. `remaining` is what is left. Send fewer identifiers, or add credits. Nothing is charged. The same status is returned when the request throughput limit is exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Not enough API credits remain for this batch."
                    },
                    "quota": {
                      "type": "integer"
                    },
                    "used": {
                      "type": "integer"
                    },
                    "remaining": {
                      "type": "integer"
                    },
                    "required": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/viewer": {
      "get": {
        "summary": "Get the authenticated viewer",
        "description": "Returns the identity of the credential used to authenticate the request: an API key or a user session token (JWT). Use it to verify a credential during integration setup (a `200` response means the credential is valid; `401`/`403` means it is missing, unknown, or revoked) and to display which API key and organization are connected. A key an [agent bought](/agents/overview) also says how it was paid for and how to add credits. Requests to this endpoint are free: they never consume API credits.",
        "operationId": "getViewer",
        "tags": [
          "viewer"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The presented credential is valid. The `type` property indicates which kind of credential authenticated the request and determines the response shape.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ViewerApiKeyResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ViewerUserResponse"
                    }
                  ],
                  "discriminator": {
                    "propertyName": "type",
                    "mapping": {
                      "api-key": "#/components/schemas/ViewerApiKeyResponse",
                      "user": "#/components/schemas/ViewerUserResponse"
                    }
                  }
                },
                "examples": {
                  "apiKey": {
                    "summary": "Authenticated with an API key",
                    "value": {
                      "type": "api-key",
                      "id": "id5ZQvmz9A",
                      "urn": "urn:brandfetch:organization:cl5s9fps1275071ol9h7gs072m:api-key:id5ZQvmz9A",
                      "name": "Production key",
                      "createdAt": "2026-05-12T09:14:07.000Z",
                      "usage": {
                        "used": 1234,
                        "quota": 250000
                      },
                      "organization": {
                        "id": "cl5s9fps1275071ol9h7gs072m",
                        "urn": "urn:brandfetch:organization:cl5s9fps1275071ol9h7gs072m",
                        "name": "Acme Inc."
                      }
                    }
                  },
                  "agentKey": {
                    "summary": "Authenticated with an API key an agent bought",
                    "value": {
                      "type": "api-key",
                      "id": "idA9kR2mXw",
                      "urn": "urn:brandfetch:organization:cm1q8x0b2000308l4f9ae2k7d:api-key:idA9kR2mXw",
                      "name": "Agent Key",
                      "createdAt": "2026-09-24T18:02:51.000Z",
                      "usage": {
                        "used": 37,
                        "quota": 2000
                      },
                      "organization": {
                        "id": "cm1q8x0b2000308l4f9ae2k7d",
                        "urn": "urn:brandfetch:organization:cm1q8x0b2000308l4f9ae2k7d",
                        "name": "Agent 0x0000…0a11"
                      },
                      "agent": {
                        "payer": {
                          "type": "wallet",
                          "network": "eip155:8453",
                          "address": "0x0000000000000000000000000000000000000a11"
                        },
                        "topUp": {
                          "method": "POST",
                          "url": "https://api.brandfetch.io/v2/agents/access",
                          "note": "Pay again from the same wallet to add credits to this key. Add rotateKey=true to replace the key while doing so, which is also how to recover a lost key."
                        }
                      }
                    }
                  },
                  "user": {
                    "summary": "Authenticated with a user session token",
                    "value": {
                      "type": "user",
                      "id": "cl2xkl6h90007w135197r5abc",
                      "urn": "urn:brandfetch:user:cl2xkl6h90007w135197r5abc",
                      "name": "Jane Doe",
                      "email": "jane@acme.com",
                      "createdAt": "2025-11-02T16:41:12.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized. The request carries no Authorization header. The body points an agent without a key at how to get access.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "agentAccess"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "enum": [
                        "Unauthorized"
                      ]
                    },
                    "agentAccess": {
                      "type": "object",
                      "description": "Where an agent without an API key can get access: buy a key with an x402 or MPP payment, or pay for each request individually.",
                      "required": [
                        "description",
                        "documentation",
                        "offer"
                      ],
                      "properties": {
                        "description": {
                          "type": "string",
                          "description": "The two ways in, in prose."
                        },
                        "documentation": {
                          "type": "string",
                          "format": "uri",
                          "description": "The agent access guide."
                        },
                        "offer": {
                          "type": "string",
                          "format": "uri",
                          "description": "The agent access endpoint. `GET` it to read the offer: the price, how to pay with each protocol, and the per-request alternative."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "Unauthorized",
                  "agentAccess": {
                    "description": "An agent without an API key can buy one with an x402 or MPP payment, or pay for each Brand API, Brand Context API and Transaction API request individually. The offer describes both.",
                    "documentation": "https://docs.brandfetch.com/agents/overview",
                    "offer": "https://api.brandfetch.io/v2/agents/access"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The credential was rejected, e.g. an empty or unknown credential, a revoked API key or an expired session token."
          }
        }
      }
    },
    "/v2/agents/access": {
      "get": {
        "summary": "Describe the agent access offer",
        "description": "What an agent can buy and how to pay for it: standing API access — an organization, an API key preloaded with prepaid credits and an MCP token — sold for one x402 or MPP payment. Needs no credential. Written for an agent that will act on it. See https://docs.brandfetch.com/agents/overview.",
        "operationId": "getAgentAccessOffer",
        "security": [],
        "tags": [
          "agents"
        ],
        "responses": {
          "200": {
            "description": "The offer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentAccessOffer"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Buy standing access with an x402 or MPP payment",
        "description": "Pay a whole number of US dollars to receive a Brandfetch organization, an API key holding 20 prepaid API credits per dollar, and an MCP bearer token. One credit is one Brand API, Brand Context API or Transaction API request. Call once without a payment to receive the 402: its `PAYMENT-REQUIRED` header is the x402 challenge (USDC on Base), its `WWW-Authenticate` header the MPP challenges (USDC.e on Tempo, or a card through a Stripe shared payment token). Pay one and repeat the request with the result — `PAYMENT-SIGNATURE` for x402, `Authorization: Payment …` for MPP. A wallet owns the organization it buys: paying again from the same wallet adds credits to the same key, and `rotateKey=true` replaces the key while doing so. A card names no wallet, so each card payment buys its own organization and key. The API key and MCP token are returned once, in the response that completes the purchase, and a payment is never charged twice. A later request carrying the same payment is answered `409` without them: a settled payment is public (an x402 signature is on-chain), so presenting it proves nothing about who sent it. If the purchase is answered with a `500` that says to retry, or with no response at all, retry the exact request at once: the first retry to succeed within three minutes of the payment receives the credential, unless it was already returned in a response the client lost, which is answered `409` `credential_already_delivered`. The credits are granted whether or not the credential is returned. See https://docs.brandfetch.com/agents/overview.",
        "operationId": "purchaseAgentAccess",
        "tags": [
          "agents"
        ],
        "security": [
          {
            "x402Payment": []
          },
          {
            "mppPayment": []
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "dynamic",
            "currency": "USD",
            "min": "1",
            "max": "500"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "tempo",
                "intent": "charge",
                "currency": "0x20C000000000000000000000b9537d11c60E8b50"
              }
            },
            {
              "mpp": {
                "method": "stripe",
                "intent": "charge",
                "currency": "usd"
              }
            }
          ],
          "offers": [
            {
              "amount": null,
              "currency": "0x20C000000000000000000000b9537d11c60E8b50",
              "description": "Standing Brandfetch API access: prepaid credits for the whole dollars named by ?usd=",
              "intent": "charge",
              "method": "tempo"
            },
            {
              "amount": null,
              "currency": "usd",
              "description": "Standing Brandfetch API access: prepaid credits for the whole dollars named by ?usd=",
              "intent": "charge",
              "method": "stripe"
            }
          ]
        },
        "parameters": [
          {
            "name": "usd",
            "in": "query",
            "required": true,
            "description": "Whole US dollars to pay, between 1 and 500. Buys `usd × 20` credits.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            },
            "examples": {
              "usd": {
                "summary": "Five dollars",
                "value": 5
              }
            }
          },
          {
            "name": "rotateKey",
            "in": "query",
            "required": false,
            "description": "When `true` on a top-up, issues a new key holding the combined balance, returned once like any other. The wallet's earlier keys stop working once the new key has been returned, even if the client never receives that response. If the rotation is answered with an error instead of the new key, they keep working. A retry answered `409` `credential_already_delivered` means the rotation completed: pay again with `rotateKey=true` for a new key.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Topped up: the wallet already owned an organization. The credential is returned once, in this response.",
            "headers": {
              "Cache-Control": {
                "description": "`private` — the response carries a credential, so no shared cache may store it.",
                "schema": {
                  "type": "string"
                }
              },
              "PAYMENT-RESPONSE": {
                "description": "On the response to the request that settled an x402 payment: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`). A retry that delivers the credential after a failed response does not carry it.",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "On the response to the request that settled an MPP payment: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). A retry that delivers the credential after a failed response does not carry it.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentAccessCredential"
                }
              }
            }
          },
          "201": {
            "description": "Provisioned: this wallet's first purchase, or a card purchase, created its organization and key. The credential is returned once, in this response.",
            "headers": {
              "Cache-Control": {
                "description": "`private` — the response carries a credential, so no shared cache may store it.",
                "schema": {
                  "type": "string"
                }
              },
              "PAYMENT-RESPONSE": {
                "description": "On the response to the request that settled an x402 payment: the base64-encoded settlement receipt (`success`, `transaction`, `network`, `payer`). A retry that delivers the credential after a failed response does not carry it.",
                "schema": {
                  "type": "string"
                }
              },
              "Payment-Receipt": {
                "description": "On the response to the request that settled an MPP payment: the base64url-encoded receipt (`method`, `reference`, `status`, `timestamp`). A retry that delivers the credential after a failed response does not carry it.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentAccessCredential"
                }
              }
            }
          },
          "400": {
            "description": "The `usd` parameter is missing, not a whole number, or outside the bounds; or the payment does not name the paying wallet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "enum": [
                        "usd must be a whole number of US dollars between 1 and 500."
                      ]
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Without a credential, the quote for `usd` dollars: the `PAYMENT-REQUIRED` header describes the x402 payment (USDC on Base) and `WWW-Authenticate` the MPP challenges. A settlement that was refused says so in the `message`: retry the exact request once before signing a new payment, since the retry is answered from the payment if another attempt settled it; refused again, request a fresh challenge and pay afresh. Otherwise, with a credential that was not accepted, the `reason` — nothing was charged; pay afresh and retry (a `credential_in_use` reason means another request of yours is settling the same credential: retry the exact request in a moment instead; a `challenge_invalid` reason means the MPP credential does not answer a challenge this API issued: answer one of the fresh challenges, unless this retries an MPP purchase already paid for: that purchase is complete and its credits are on the organization, so a Tempo wallet pays again with `rotateKey=true` for a working key and a card purchase contacts support).",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "The x402 v2 payment challenge: base64-encoded JSON whose `accepts` array lists how to pay (scheme `exact`, network `eip155:8453`, the USDC asset, the `amount` in USDC's six decimals and the receiving `payTo` address). Sign the payment with an x402 client and retry with the result in a `PAYMENT-SIGNATURE` header. See https://docs.brandfetch.com/agents/pay-per-request.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`no-store` — a challenge is issued for one request and must not be cached.",
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "description": "One `Payment` challenge per payment method Stripe offers for the amount (USDC.e on Tempo from a cent; cards via shared payment tokens from $0.50), comma-separated. Answer one with an `Authorization: Payment …` credential.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PaymentChallenge"
                    },
                    {
                      "$ref": "#/components/schemas/PaymentRejected"
                    }
                  ]
                }
              }
            }
          },
          "409": {
            "description": "The request carries a payment that is already being completed, or whose purchase is complete; it carries no credential and no challenge, and the payment is not charged again. `payment_in_progress`: another request carrying the same payment is completing the purchase and its response carries the credential; retry the exact request after `Retry-After` if it does not arrive, and never pay again. `credential_already_delivered`: the credential was returned with the response that completed the purchase and is not returned again; the credits are on the organization named in the body. To replace a lost key, pay again from the same wallet with `rotateKey=true`; a card purchase cannot be recovered, so make a new one. `credential_replaced`: a later rotation replaced the key this payment bought; the organization's credits, these included, are intact. Pay again from the same wallet with `rotateKey=true` for a working key; for a card purchase, contact support with the `paymentReference`.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, on `payment_in_progress`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "What happened and what to do next, for whoever is reading."
                    },
                    "reason": {
                      "type": "string",
                      "enum": [
                        "payment_in_progress",
                        "credential_already_delivered",
                        "credential_replaced"
                      ]
                    },
                    "paymentReference": {
                      "type": "string",
                      "description": "Identifies the payment; quote it to support."
                    },
                    "organization": {
                      "type": "object",
                      "description": "The organization the purchase credited. Present on `credential_already_delivered` and `credential_replaced`.",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "urn": {
                          "type": "string",
                          "example": "urn:brandfetch:organization:xig9b54wddtihs0dktyhau0i"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "The purchase did not finish, and the payment may have been taken. With a `paymentReference`, the `message` says which of two cases applies. If it says to retry, retry this exact request (same `PAYMENT-SIGNATURE` or `Authorization: Payment` header) at once: the first retry to succeed within three minutes of the payment receives the credential, and no later request does. If it says not to pay again, the credential can no longer be delivered automatically: do not pay again, and contact support with the `paymentReference`. Without a `paymentReference`, an unexpected error: retry the exact request, which never charges the payment twice, and do not pay again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Says whether to retry this exact request or not to pay again, for instance: This payment may already have been taken, but what it bought could not be delivered automatically. Do not pay again for it: contact support with the payment reference.",
                      "example": "Provisioning failed after your payment was accepted. Retry this exact request to receive your credential, or contact support with the payment reference."
                    },
                    "paymentReference": {
                      "type": "string",
                      "description": "Identifies the payment; quote it to support."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The request was not served. Without a `reason`, the payment service could not be reached and nothing was charged: retry after the `Retry-After` interval. With `reason: payment_outcome_unknown`, whether the payment went through is not known yet: retry the exact request after the interval, and do not sign a new payment for it.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "reason": {
                      "type": "string",
                      "enum": [
                        "payment_outcome_unknown"
                      ]
                    },
                    "paymentReference": {
                      "type": "string",
                      "description": "Present with `reason: payment_outcome_unknown`."
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ViewerApiKeyResponse": {
        "type": "object",
        "title": "API key",
        "description": "The authenticated API key.",
        "required": ["type", "id", "urn", "name", "createdAt", "usage", "organization"],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "api-key"
            ],
            "description": "The kind of credential that authenticated the request."
          },
          "id": {
            "type": "string",
            "description": "Id of the API key."
          },
          "urn": {
            "type": "string",
            "description": "URN of the API key, e.g. `urn:brandfetch:organization:{organization.id}:api-key:{id}`."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Display name of the API key, as set in the dashboard."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the API key was created."
          },
          "usage": {
            "type": "object",
            "description": "API credit consumption for the current billing period, mirroring the `x-api-key-quota` and `x-api-key-approximate-usage` response headers of billable endpoints. Because this endpoint is free, `used` is the exact count, not approximated one ahead like the header.",
            "required": ["used", "quota"],
            "properties": {
              "used": {
                "type": "integer",
                "description": "API credits consumed so far in the current billing period."
              },
              "quota": {
                "type": "integer",
                "description": "API credit allowance for the current billing period."
              }
            }
          },
          "organization": {
            "type": "object",
            "description": "The organization the API key belongs to.",
            "required": ["id", "urn", "name"],
            "properties": {
              "id": {
                "type": "string",
                "description": "Id of the organization."
              },
              "urn": {
                "type": "string",
                "description": "URN of the organization, e.g. `urn:brandfetch:organization:{id}`."
              },
              "name": {
                "type": "string",
                "nullable": true,
                "description": "Display name of the organization."
              }
            }
          },
          "agent": {
            "type": "object",
            "description": "Present only on a key an agent bought through `POST /v2/agents/access`: how it was paid for, and how to add credits.",
            "required": [
              "payer",
              "topUp"
            ],
            "properties": {
              "payer": {
                "description": "What paid for the key: an x402 or Tempo wallet, which can pay again to add credits to this key, or a card, which buys a new key with every payment.",
                "oneOf": [
                  {
                    "type": "object",
                    "title": "Wallet",
                    "required": [
                      "type",
                      "network",
                      "address"
                    ],
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "wallet"
                        ]
                      },
                      "network": {
                        "type": "string",
                        "description": "CAIP-2 network the wallet paid on, e.g. `eip155:8453` for x402 on Base."
                      },
                      "address": {
                        "type": "string",
                        "description": "The wallet's address, in lowercase."
                      }
                    }
                  },
                  {
                    "type": "object",
                    "title": "Card",
                    "required": [
                      "type"
                    ],
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "card"
                        ]
                      }
                    }
                  }
                ],
                "discriminator": {
                  "propertyName": "type"
                }
              },
              "topUp": {
                "type": "object",
                "description": "How to add credits.",
                "required": [
                  "method",
                  "url",
                  "note"
                ],
                "properties": {
                  "method": {
                    "type": "string",
                    "enum": [
                      "POST"
                    ]
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "The agent access endpoint."
                  },
                  "note": {
                    "type": "string",
                    "description": "What paying again does for this key."
                  }
                }
              }
            }
          }
        }
      },
      "ViewerUserResponse": {
        "type": "object",
        "title": "User",
        "description": "The authenticated user (dashboard session token).",
        "required": ["type", "id", "urn", "name", "email", "createdAt"],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "user"
            ],
            "description": "The kind of credential that authenticated the request."
          },
          "id": {
            "type": "string",
            "description": "Id of the user."
          },
          "urn": {
            "type": "string",
            "description": "URN of the user, e.g. `urn:brandfetch:user:{id}`."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Full name of the user."
          },
          "email": {
            "type": "string",
            "nullable": true,
            "description": "Email address of the user."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the user account was created."
          }
        }
      },
      "Location": {
        "type": "object",
        "description": "Company's headquarter information",
        "properties": {
          "city": {
            "type": "string",
            "description": "Headquarter city",
            "nullable": true
          },
          "country": {
            "type": "string",
            "description": "Headquarter country",
            "nullable": true
          },
          "countryCode": {
            "type": "string",
            "description": "Headquarter country code (ISO 3166-1 alpha-2)",
            "nullable": true
          },
          "region": {
            "type": "string",
            "description": "Headquarter region",
            "nullable": true
          },
          "state": {
            "type": "string",
            "description": "Headquarter state",
            "nullable": true
          },
          "subregion": {
            "type": "string",
            "description": "Headquarter subregion",
            "nullable": true
          }
        }
      },
      "Industry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the industry"
          },
          "score": {
            "type": "number",
            "format": "float",
            "description": "Probability, between 0 and 1, that the brand belongs to this industry. A value of 1 marks an industry that was set rather than predicted, for example by a curator, an import or a content rule."
          },
          "slug": {
            "type": "string",
            "description": "URL friendly identifier"
          },
          "name": {
            "type": "string",
            "description": "Name of the industry"
          },
          "emoji": {
            "type": "string",
            "description": "An emoji for the industry"
          },
          "parent": {
            "description": "If the object is a sub-category, the parent industry",
            "items": {
              "$ref": "#/components/schemas/IndustryParent"
            },
            "nullable": true
          }
        }
      },
      "IndustryParent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the industry"
          },
          "slug": {
            "type": "string",
            "description": "URL friendly identifier"
          },
          "name": {
            "type": "string",
            "description": "Name of the industry"
          },
          "emoji": {
            "type": "string",
            "description": "An emoji for the industry"
          }
        }
      },
      "Format": {
        "type": "object",
        "properties": {
          "src": {
            "type": "string",
            "description": "File source"
          },
          "format": {
            "type": "string",
            "enum": ["svg", "webp", "png", "jpeg"],
            "description": "File format"
          },
          "height": {
            "type": "integer",
            "nullable": true,
            "description": "File height in pixels"
          },
          "width": {
            "type": "integer",
            "nullable": true,
            "description": "File width in pixels"
          },
          "size": {
            "type": "integer",
            "description": "File size in bytes"
          },
          "background": {
            "type": "string",
            "enum": ["transparent"],
            "nullable": true,
            "description": "Indicates if the file has a transparent background"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Every refusal the Brand API writes itself. `message` is the text for a person; `error` is the code for your code, and the same value travels in the `x-bf-error` header; `docs` links the table of codes. A `402` is the exception: its body is the payment protocols' own, and only the header carries the code.",
        "required": ["message", "error", "docs"],
        "properties": {
          "message": {
            "type": "string",
            "description": "What happened, written for a person. Do not branch on it."
          },
          "error": {
            "type": "string",
            "description": "Why the request was refused. Stable; branch on it. Also in the `x-bf-error` header."
          },
          "docs": {
            "type": "string",
            "format": "uri",
            "enum": ["https://docs.brandfetch.com/brand-api/overview#errors"]
          }
        }
      },
      "BrandResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the brand",
            "nullable": false
          },
          "name": {
            "type": "string",
            "description": "Brand name",
            "nullable": true
          },
          "domain": {
            "type": "string",
            "description": "Brand website URL",
            "nullable": false
          },
          "claimed": {
            "type": "boolean",
            "description": "Set to true if the owner of the brand claimed its brand profile on [Brandfetch](https://brandfetch.com)",
            "nullable": false
          },
          "description": {
            "type": "string",
            "description": "Brand description",
            "nullable": true
          },
          "longDescription": {
            "type": "string",
            "description": "Brand long description",
            "nullable": true
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Name of the social media platform",
                  "nullable": false,
                  "enum": [
                    "twitter",
                    "facebook",
                    "instagram",
                    "github",
                    "youtube",
                    "linkedin",
                    "crunchbase"
                  ]
                },
                "url": {
                  "type": "string",
                  "description": "URL of the social media profile",
                  "nullable": false
                }
              }
            },
            "description": "Social media links of the brand",
            "nullable": false
          },
          "logo": {
            "type": "string",
            "nullable": true,
            "description": "Shortcut field for the brand's logo: the address of the best match from `logos`. The image is a WebP up to 512 px on its longer side. A dark logo is picked over a light one, for light backgrounds; the address names the theme it serves. `null` when the brand has no logo, and for brands with `isNsfw: true`.\n\nFetch the address as it is given. Its `c` parameter is a client ID signed for your API key. The client ID is required, and a request without it is refused. Its `t` parameter changes when the image does, so you can cache the image for as long as you like. The image does not count towards your quota. If the logo is gone when you fetch it, the address returns `404`."
          },
          "symbol": {
            "type": "string",
            "nullable": true,
            "description": "Shortcut field for the brand's symbol: the address of the best match from `logos`. The image is a WebP up to 512 px on its longer side. A dark symbol is picked over a light one, for light backgrounds; the address names the theme it serves. `null` when the brand has no symbol, and for brands with `isNsfw: true`.\n\nFetch the address as it is given. Its `c` parameter is a client ID signed for your API key. The client ID is required, and a request without it is refused. Its `t` parameter changes when the image does, so you can cache the image for as long as you like. The image does not count towards your quota. If the symbol is gone when you fetch it, the address returns `404`."
          },
          "icon": {
            "type": "string",
            "nullable": true,
            "description": "Shortcut field for the brand's icon: the address of the best match from `logos`. The image is a square WebP up to 128 px. A brand without an icon gets one made from its symbol or logo. When no icon can be made, the address returns a lettermark: the brand's initial on a plain square. `null` when the brand has no icon, symbol or logo, and for brands with `isNsfw: true`.\n\nFetch the address as it is given. Its `c` parameter is a client ID signed for your API key. The client ID is required, and a request without it is refused. Its `t` parameter changes when the image does, so you can cache the image for as long as you like. The image does not count towards your quota."
          },
          "banner": {
            "type": "string",
            "nullable": true,
            "description": "Shortcut field for the brand's banner: the address of the best match from `images`. The image is a WebP up to 1500 px wide. `null` when the brand has no banner, and for brands with `isNsfw: true`.\n\nFetch the address as it is given. Its `c` parameter is a client ID signed for your API key. The client ID is required, and a request without it is refused. Its `t` parameter changes when the image does, so you can cache the image for as long as you like. The image does not count towards your quota. If the banner is gone when you fetch it, the address returns `404`."
          },
          "logos": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "theme": {
                  "type": "string",
                  "description": "See logo theme. Possible values:\n- **dark**: A dark logo should be displayed on a light background (e.g. #ffffff)\n- **light**: A light logo should be displayed on a dark background (e.g. #000000)",
                  "nullable": true,
                  "enum": ["dark", "light", null]
                },
                "formats": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Format"
                  },
                  "description": "A list of format objects containing files in different formats",
                  "nullable": false
                },
                "tags": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "What the image is. Brandfetch tags a brand's icon and logo; one that is no longer the brand's main icon or logo keeps its tags and is listed with type `other`. Possible values:\n- **photographic**: The image is a photograph, or a logo shown on one, such as a sign or a vehicle.\n- **portrait**: The image is a photograph mainly of one or more people. An image tagged `portrait` is also tagged `photographic`.\n- **illustration**: The image is a drawing, painting, cartoon or 3D render that is not a logo.\n- **screenshot**: The image is a screenshot or mockup of software, a website, an app or a device screen. Logos only.\n- **text**: The image is a flyer, poster, advert, social media post, infographic, document or menu.\n- **placeholder**: The image is a default avatar, a blank or single-colour image, or a \"no image\" graphic.\n- **wordmark**: The logo is the brand's name set in type, with no separate symbol.\n- **lettermark**: The logo is initials, a monogram or a single letter. Icons only.\n- **symbol**: The logo is a symbol alone, without text. Icons only.\n- **combination**: The logo pairs a symbol with the name.\n- **emblem**: The logo's text sits inside a badge, seal or crest.\n\nThe mark types, `wordmark` to `emblem`, go only on an image that is mainly a logo, one at most. A tag is assigned only when the image clearly is one, so an image without a tag can still be any of these. Logos and icons that Brandfetch has not refreshed since October 2026 may carry fewer tags, or none. Brandfetch may add values.",
                  "nullable": false
                },
                "type": {
                  "type": "string",
                  "description": "See logo type. Possible values:\n- **icon**: The icon that is used on social profiles (e.g. [Tesla's social icon](https://cdn.brandfetch.io/tesla.com/icon))\n- **logo**: The horizontal logo, seen on large surfaces (e.g. [Tesla's logo](https://asset.brandfetch.io/id2S-kXbuK/idAJ5NMLPG.svg))\n- **symbol**: The universal mark that abstractly represents the brand (e.g. [Tesla's T symbol](https://asset.brandfetch.io/id2S-kXbuK/idM-t614MT.svg))\n- **other**: Other is used to refer to any type of logo that is not the primary one. (e.g. Amazon Kindle Logo)",
                  "nullable": false,
                  "enum": ["icon", "logo", "symbol", "other"]
                }
              }
            },
            "description": "Logos, symbols & icons of the brand",
            "nullable": false
          },
          "colors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "hex": {
                  "type": "string",
                  "description": "Color HEX code",
                  "nullable": false
                },
                "type": {
                  "type": "string",
                  "description": "Type of the color. Possible values:\n- **accent**: The main color that represents the brand (used to draw attention e.g. call to action button)\n- **dark**: The darker color of the brand (used for surfaces or backgrounds)\n- **light**: The lighter color of the brand (used for surfaces or backgrounds)\n- **brand**: The full-color scheme of the brand (used to create color palettes users can pick from)",
                  "nullable": false,
                  "enum": ["accent", "dark", "light", "brand"]
                },
                "brightness": {
                  "type": "number",
                  "description": "Color brightness. Calculated based on the standard formula 0.2126*R + 0.7152*G + 0.0722*B",
                  "nullable": false,
                  "format": "float"
                }
              }
            },
            "description": "Accent, dark, light & palette colors of the brand",
            "nullable": false
          },
          "fonts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Font family",
                  "nullable": true
                },
                "type": {
                  "type": "string",
                  "description": "Font type",
                  "nullable": false,
                  "enum": ["title", "body"]
                },
                "origin": {
                  "type": "string",
                  "description": "See font origin. Possible values:\n- **google**: The font that's hosted on Google Font\n- **custom**: The font that has been uploaded by the brand itself\n- **system**: The font that's already installed on the user's operating system (see example)",
                  "enum": ["google", "custom", "system"]
                },
                "originId": {
                  "type": "string",
                  "description": "Font origin ID",
                  "nullable": true
                },
                "weights": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {}
                  }
                }
              }
            },
            "description": "Title & body fonts of the brand",
            "nullable": false
          },
          "images": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "formats": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Format"
                  },
                  "description": "Available formats of the image",
                  "nullable": false
                },
                "tags": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "What the image is. A banner that is no longer the brand's main one keeps its tags and is listed with type `other`. Possible values:\n- **photographic**: The image is a photograph, or a logo shown on one. Banners and pictures.\n- **portrait**: The image is a photograph mainly of one or more people. Banners and pictures. An image tagged `portrait` is also tagged `photographic`.\n- **illustration**: The image is a drawing, painting, cartoon or 3D render that is not a logo. Banners and pictures.\n- **screenshot**: The image is a screenshot or mockup of software, a website, an app or a device screen. Pictures.\n- **text**: The image is a flyer, poster, advert, social media post, infographic, document or menu. Banners and pictures.\n- **pattern**: The image is an abstract background, texture, gradient or pattern with no subject. Pictures.\n- **placeholder**: The image is blank, a single colour, or a \"no image\" graphic. Banners.\n\nA tag is assigned only when the image clearly is one, so an image without a tag can still be any of these. Images that Brandfetch has not refreshed since October 2026 have no tags. Brandfetch may add values.",
                  "nullable": false
                },
                "type": {
                  "type": "string",
                  "description": "Image type. `picture` entries are images published on the brand's own site and carry `pictureMetadata`. Their `tags` say what each one is, such as a photograph, a screenshot or a flyer.",
                  "nullable": false,
                  "enum": ["banner", "other", "picture"]
                },
                "pictureMetadata": {
                  "type": "object",
                  "description": "Present on `picture` entries only. Lets you choose between a brand's pictures without fetching the files first.",
                  "properties": {
                    "score": {
                      "type": "number",
                      "description": "How representative of the brand we consider this picture",
                      "nullable": false
                    },
                    "rank": {
                      "type": "integer",
                      "description": "Position of this picture among the brand's pictures, by descending score",
                      "nullable": false
                    },
                    "naturalWidth": {
                      "type": "integer",
                      "description": "Intrinsic width of the image in pixels",
                      "nullable": false
                    },
                    "naturalHeight": {
                      "type": "integer",
                      "description": "Intrinsic height of the image in pixels",
                      "nullable": false
                    },
                    "alt": {
                      "type": "string",
                      "description": "Alt text published with the image on the brand's site",
                      "nullable": false
                    },
                    "sourceUrl": {
                      "type": "string",
                      "description": "URL of the image on the brand's own site. A `picture` can arrive with an empty `formats` array, in which case this is how you reach the image.",
                      "nullable": false
                    },
                    "imageCategory": {
                      "type": "string",
                      "description": "Category we classified the image into",
                      "nullable": true
                    },
                    "categoryConfidence": {
                      "type": "number",
                      "description": "Confidence in the assigned `imageCategory`",
                      "nullable": true
                    }
                  },
                  "nullable": false
                }
              }
            },
            "description": "Banner, picture & other images of the brand",
            "nullable": false
          },
          "qualityScore": {
            "type": "number",
            "description": "Score between 0-1 which indicates the quality of the data for the given brand. Useful when you don't want to show lower quality brands to your users.\n\nLower 3rd is poor quality, middle 3rd is OK quality, upper 3rd is high quality. Lower scores indicate that a brand is less likely to be \"real\". For example, where google.com will score high, my-random-blog.com will score between 0.3-0.4. The score factors in things like data-recency, whether the brand has been claimed, if it has been manually verified by our team, the brand's domain ranking on the web, as well as other factors.\n\nDon't rely on a fixed score for any given brand. The way we calculate this score may change over time as we add new factors, or tweak the weights of existing ones such that a score for a given brand may change. However, they will remain aligned such that scores divide quality into thirds: low, medium, high.",
            "nullable": false
          },
          "company": {
            "type": "object",
            "properties": {
              "employees": {
                "type": "integer",
                "description": "1 employee, 2-10 employees, 11-50 employees, 51-200 employees, 201-500 employees, 501-1,000 employees, 1,001-5,000 employees, 5,001-10,000 employees, 10,001+ employees",
                "enum": [1, 2, 11, 51, 201, 501, 1001, 5001, 10001],
                "nullable": true
              },
              "financialIdentifiers": {
                "type": "object",
                "description": "Object holding financial identifiers",
                "properties": {
                  "isin": {
                    "type": "array",
                    "description": "List of ISIN codes",
                    "items": {
                      "type": "string"
                    }
                  },
                  "ticker": {
                    "type": "array",
                    "description": "List of Stock or ETF ticker",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "nullable": true
              },
              "foundedYear": {
                "type": "integer",
                "description": "The year the brand was founded",
                "nullable": true
              },
              "industries": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Industry"
                },
                "description": "An array of industries, sorted by descending `score`. A sub-industry carries its top-level industry in `parent`. See the full list of industries [here](https://docs.google.com/spreadsheets/d/1N44nMfVtPCFM4ebTcmRlqbyxjFtDAGVuqd0mh0dcOU0/edit?usp=sharing)"
              },
              "kind": {
                "type": "string",
                "description": "Organizational Structure",
                "enum": [
                  "EDUCATIONAL",
                  "GOVERNMENT_AGENCY",
                  "NON_PROFIT",
                  "PARTNERSHIP",
                  "PRIVATELY_HELD",
                  "PUBLIC_COMPANY",
                  "SELF_EMPLOYED",
                  "SELF_OWNED"
                ],
                "nullable": true
              },
              "location": {
                "$ref": "#/components/schemas/Location"
              }
            },
            "description": "The company object returns firmographic data related to the brand",
            "nullable": false
          },
          "isNsfw": {
            "type": "boolean",
            "description": "true when the brand is for adult content, e.g. is not safe for work",
            "nullable": false
          },
          "urn": {
            "type": "string",
            "description": "Uniform Resource Name for the brand",
            "nullable": false
          },
          "screenshot": {
            "type": "object",
            "nullable": true,
            "description": "The brand's homepage screenshot. `null` when Brandfetch holds no screenshot of the homepage yet, and for brands with `isNsfw: true`.\n\nThe screenshot shows the top of the homepage at a desktop viewport, as Brandfetch saw it on its last visit. It is not a full-page capture. Fetch `url` as it is given: its `c` parameter is a client ID signed for your API key, and the image does not count towards your quota. A request that drops the client ID is refused. `t` is the time of capture, so the address changes when Brandfetch takes a new screenshot.",
            "properties": {
              "url": {
                "type": "string",
                "description": "The address of the PNG, signed for your API key. Fetch it as it is given, with its `c` and `t` parameters.",
                "nullable": false
              },
              "capturedAt": {
                "type": "string",
                "format": "date-time",
                "description": "When Brandfetch took the screenshot.",
                "nullable": false
              }
            }
          },
          "palette": {
            "type": "object",
            "nullable": true,
            "description": "The brand's color palette. Present only when the request sets `palette=true` or `palette=1`. When a brand has no palette yet, the first request builds one from the brand's last crawl without a new render. Then `themes` and `onPairs` can be empty until the next crawl. When Brandfetch finds no color that it can defend as the brand's color, no color has the role `primary`.",
            "properties": {
              "colors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "hex": {
                      "type": "string",
                      "description": "Color HEX code.",
                      "nullable": false
                    },
                    "name": {
                      "type": "string",
                      "description": "Name of the closest named color. Uses the same list as `colors[].name`, so the same HEX code has the same name everywhere.",
                      "nullable": true
                    },
                    "role": {
                      "type": "string",
                      "description": "What the color does for the brand. Possible values: `primary`, `secondary`, `accent`, `background`, `surface`, `text`, `muted`, `border`, `other`.",
                      "nullable": false
                    },
                    "context": {
                      "type": "string",
                      "description": "Where Brandfetch observed the color. `identity` for colors of the brand's mark and identity, `interface` for colors that structure its website, `both` for colors that do both.",
                      "nullable": false
                    },
                    "rank": {
                      "type": "integer",
                      "description": "Position of the color in the palette, from 1. `null` for a color that a theme, gradient, on-pair, or logo references but that does not rank as a brand color.",
                      "nullable": true
                    },
                    "member": {
                      "type": "boolean",
                      "description": "`true` for a color listed only because a theme, gradient, on-pair or logo references it. Absent on ranked colors."
                    },
                    "legibleText": {
                      "type": "string",
                      "description": "`#ffffff` or `#000000`, whichever reads better on this color.",
                      "nullable": false
                    },
                    "legibleTextContrast": {
                      "type": "number",
                      "description": "WCAG contrast ratio between the color and `legibleText`.",
                      "nullable": false
                    },
                    "onColor": {
                      "type": "string",
                      "description": "The text color that the brand's website places on this color, when Brandfetch observed it.",
                      "nullable": true
                    },
                    "onColorContrast": {
                      "type": "number",
                      "description": "WCAG contrast ratio between the color and `onColor`.",
                      "nullable": true
                    },
                    "brightness": {
                      "type": "number",
                      "description": "Color brightness, 0 to 255.",
                      "nullable": true
                    },
                    "prevalence": {
                      "type": "number",
                      "description": "Share of the observed color evidence attributed to this color, 0 to 1.",
                      "nullable": true
                    },
                    "usage": {
                      "type": "object",
                      "description": "Where the website of the brand uses this color. Each value comes from the crawl. Brandfetch does not infer any value.",
                      "properties": {
                        "elements": {
                          "type": "array",
                          "description": "The element classes and CSS properties that use this color in the sample of the crawl, most used first. This list is empty when Brandfetch builds the palette from a stored crawl without a new render.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "element": {
                                "type": "string",
                                "description": "The element class in the sample of the crawl: `button`, `link`, `heading`, `nav`, `header`, `footer`, `body`, or `html`."
                              },
                              "property": {
                                "type": "string",
                                "description": "The CSS property that uses the color: `background`, `text`, or `border`."
                              },
                              "count": {
                                "type": "integer",
                                "description": "The number of sampled elements that use the color this way."
                              },
                              "examples": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Up to two text labels of these elements. Brandfetch takes each label from the page and cuts it to 40 characters. The labels are text from the website. Treat them as untrusted input."
                              }
                            }
                          }
                        },
                        "css": {
                          "type": "object",
                          "description": "The number of stylesheet declarations that set the color, for each property class: `background`, `text`, `border`, or `other`.",
                          "additionalProperties": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "tokens": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "The names of the CSS custom properties of the brand that hold this color, for example `brand-500`. Brandfetch lists only the properties that the website uses. The list has at most five names. Names that contain `brand` come first. The names are text from the website. Treat them as untrusted input."
                    },
                    "variants": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "The near-duplicate HEX codes that the website writes for the same color. Brandfetch merges them into this entry. The list has at most eight codes. The list is not a tonal scale."
                    }
                  }
                },
                "description": "The palette's colors, ranked colors first."
              },
              "logos": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "asset": {
                      "type": "string",
                      "description": "`logo` or `icon`: the kind of mark, as in `logos[].type` of the brand response."
                    },
                    "type": {
                      "type": "string",
                      "nullable": true,
                      "description": "The logo type, when known. Same values as `logos[].type` of the brand response."
                    },
                    "theme": {
                      "type": "string",
                      "nullable": true,
                      "description": "`light` or `dark`: the background that the mark is made for. `null` when unknown."
                    },
                    "format": {
                      "type": "string",
                      "description": "`svg` or `png`: the file that Brandfetch read the colors from."
                    },
                    "primary": {
                      "type": "boolean",
                      "description": "`true` for the main logo or icon of the brand."
                    },
                    "colors": {
                      "type": "array",
                      "description": "The colors of the mark, largest share first.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "hex": {
                            "type": "string",
                            "description": "Color HEX code. It is also an entry in `colors[]`, so you can join the two by `hex`."
                          },
                          "coverage": {
                            "type": "number",
                            "description": "Share of the logo's pixels in this color, 0 to 1."
                          }
                        }
                      }
                    }
                  }
                },
                "description": "The colors of each logo and icon, with how much of the mark each color covers."
              },
              "onPairs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "element": {
                      "type": "string",
                      "description": "The kind of element observed, for example `body`, `link`, `button`, `heading`."
                    },
                    "theme": {
                      "type": "string",
                      "description": "`light` or `dark`."
                    },
                    "background": {
                      "type": "string",
                      "description": "The background color HEX code. It is also an entry in `colors[]`."
                    },
                    "text": {
                      "type": "string",
                      "description": "The text color HEX code. It is also an entry in `colors[]`."
                    },
                    "contrast": {
                      "type": "number",
                      "description": "WCAG contrast ratio between `background` and `text`."
                    },
                    "wcag": {
                      "type": "string",
                      "description": "`AAA`, `AA`, `AA-large` or `fail`."
                    },
                    "count": {
                      "type": "integer",
                      "description": "How many elements showed this pair."
                    }
                  }
                },
                "description": "The background and text color pairs that Brandfetch observed on the brand's website, with their contrast. Empty for a palette built from a stored crawl without a new render."
              },
              "gradients": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "rank": {
                      "type": "integer",
                      "description": "Position of the gradient, from 1."
                    },
                    "type": {
                      "type": "string",
                      "description": "`linear`, `radial`, or `conic`."
                    },
                    "angle": {
                      "type": "number",
                      "nullable": true,
                      "description": "The angle of a linear gradient, in degrees. `null` when the stylesheet gives none."
                    },
                    "stops": {
                      "type": "array",
                      "description": "The color stops, in order.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "hex": {
                            "type": "string",
                            "description": "Color HEX code. It is also an entry in `colors[]`."
                          },
                          "position": {
                            "type": "number",
                            "nullable": true,
                            "description": "Position of the stop, 0 to 1. `null` when the stylesheet gives none."
                          }
                        }
                      }
                    },
                    "css": {
                      "type": "string",
                      "description": "The gradient as a CSS value, for example `linear-gradient(90deg, #ff0000 0%, #0000ff 100%)`."
                    }
                  }
                },
                "description": "Gradients from the brand's stylesheets that use a brand color, at most four. Every stop color is also an entry in `colors[]`, with `rank: null` when it is not a brand color."
              },
              "themes": {
                "type": "object",
                "description": "The `light` and `dark` themes that the website showed. A theme that Brandfetch did not observe is absent. A palette built from a stored crawl without a new render often has no themes.",
                "properties": {
                  "light": {
                    "$ref": "#/components/schemas/PaletteTheme"
                  },
                  "dark": {
                    "$ref": "#/components/schemas/PaletteTheme"
                  }
                }
              }
            }
          }
        }
      },
      "PaletteTheme": {
        "type": "object",
        "description": "One theme of the brand's website. Each slot holds a color that the render of this theme showed. A slot that the render did not show is `null`. Every color is also an entry in `colors[]`.",
        "properties": {
          "background": {
            "type": "string",
            "description": "The page background color HEX code."
          },
          "surface": {
            "type": "string",
            "nullable": true,
            "description": "The color HEX code of cards and panels on the page background."
          },
          "text": {
            "type": "string",
            "description": "The body text color HEX code."
          },
          "muted": {
            "type": "string",
            "nullable": true,
            "description": "The color HEX code of secondary text."
          },
          "border": {
            "type": "string",
            "nullable": true,
            "description": "The color HEX code of borders and dividers."
          },
          "accent": {
            "type": "string",
            "nullable": true,
            "description": "The color HEX code of links and buttons in this theme."
          },
          "contrast": {
            "type": "number",
            "description": "WCAG contrast ratio between `background` and `text`."
          }
        }
      },
      "BrandContextMeta": {
        "type": "object",
        "description": "Metadata about the resolved brand context.",
        "required": ["domain", "canonical_name", "resolved_at"],
        "properties": {
          "domain": {
            "type": "string",
            "description": "The resolved domain name.",
            "example": "brandfetch.com",
            "nullable": false
          },
          "canonical_name": {
            "type": "string",
            "description": "The canonical brand name.",
            "example": "Brandfetch",
            "nullable": false
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp (ISO 8601) at which the context was resolved.",
            "example": "2026-05-25T08:48:36.843440+00:00",
            "nullable": false
          }
        }
      },
      "BrandContextIdentity": {
        "type": "object",
        "description": "Core identity of the brand.",
        "properties": {
          "tagline": {
            "type": "string",
            "description": "A short tagline summarizing the brand.",
            "nullable": true
          },
          "mission": {
            "type": "string",
            "description": "The brand's mission statement.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "A descriptive paragraph about the brand, its products, and how it differentiates.",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "A list of tags that characterize the brand.",
            "nullable": true
          }
        }
      },
      "BrandContextTargetAudience": {
        "type": "object",
        "description": "A single target audience segment for the brand.",
        "properties": {
          "segment": {
            "type": "string",
            "description": "Short label describing the audience segment.",
            "nullable": false
          },
          "description": {
            "type": "string",
            "description": "What this segment needs from the brand and how the brand serves them.",
            "nullable": false
          }
        }
      },
      "BrandContextProductOrService": {
        "type": "object",
        "description": "A product or service offered by the brand. Every key is present on every product; the optional fields are `null` when the brand's site does not state them.",
        "required": ["name", "type", "description", "category", "features", "tags", "url", "pricing"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the product or service.",
            "nullable": false
          },
          "type": {
            "type": "string",
            "description": "Whether the offering is a `product` or a `service`.",
            "enum": ["product", "service"],
            "example": "product",
            "nullable": false
          },
          "description": {
            "type": "string",
            "description": "Description of the product or service.",
            "nullable": false
          },
          "category": {
            "type": "string",
            "description": "What kind of offering it is, as a short noun phrase (e.g., `CRM`, `running shoe`, `savings account`). `null` when the brand's site does not make it clear.",
            "example": "Brand data API",
            "nullable": true
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 5,
            "description": "Up to five concrete things a customer can do with the offering, each starting with a verb (e.g., `Manage inventory`, `Process accounts payable`), as stated on or supported by the brand's site. `null` or an empty array when the site does not enumerate any; treat both the same way.",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 5,
            "description": "Up to five short keywords for classifying the offering. `null` or an empty array when there are none.",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "The offering's own page, only when the brand's site links to it.",
            "example": "https://brandfetch.com/developers",
            "nullable": true
          },
          "pricing": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BrandContextPricing"
              }
            ],
            "description": "Published pricing for the offering. `null` unless the brand publishes prices; never estimated."
          }
        }
      },
      "BrandContextPricing": {
        "type": "object",
        "nullable": true,
        "description": "Published pricing for a product or service. Every key is present; each is `null` when the brand's site does not state it.",
        "required": ["model", "free_tier", "starting_price", "currency", "unit", "plans", "url"],
        "properties": {
          "model": {
            "type": "string",
            "description": "How the offering is charged, as a lowercase snake_case token. Usually one of `per_seat`, `per_user`, `usage_based`, `subscription`, `one_time`, `freemium`, `commission` or `quote_only`, but it is an open set: other values such as `per_night` or `per_session` occur where the site states them.",
            "example": "subscription",
            "nullable": true
          },
          "free_tier": {
            "type": "boolean",
            "description": "Whether a free plan or tier is offered.",
            "nullable": true
          },
          "starting_price": {
            "type": "number",
            "description": "The lowest published price, in `currency`, for what `unit` describes.",
            "example": 99,
            "nullable": true
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code of `starting_price`.",
            "example": "USD",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "description": "What `starting_price` buys, as the site states it (e.g., `per user/month`, `per 1,000 requests`).",
            "example": "per month",
            "nullable": true
          },
          "plans": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 6,
            "description": "Names of the published plans or tiers. `null` or an empty array when the site names none.",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "The pricing page, only when the brand's site links to it.",
            "nullable": true
          }
        }
      },
      "BrandContextPositioning": {
        "type": "object",
        "description": "How the brand positions itself in the market.",
        "properties": {
          "value_proposition": {
            "type": "string",
            "description": "The brand's value proposition.",
            "nullable": true
          },
          "target_audience": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BrandContextTargetAudience"
            },
            "description": "Target audience segments for the brand.",
            "nullable": true
          },
          "products_and_services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BrandContextProductOrService"
            },
            "description": "Products and services offered by the brand.",
            "nullable": true
          }
        }
      },
      "BrandContextVoice": {
        "type": "object",
        "description": "The brand's voice \u2014 how it communicates.",
        "properties": {
          "summary": {
            "type": "string",
            "description": "A narrative summary of the brand's voice.",
            "nullable": true
          },
          "attributes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Short adjectives describing the voice (e.g., `confident`, `reassuring`).",
            "nullable": true
          },
          "avoid": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Things the brand should avoid in its voice.",
            "nullable": true
          }
        }
      },
      "BrandContextStyle": {
        "type": "object",
        "description": "The brand's visual style.",
        "properties": {
          "summary": {
            "type": "string",
            "description": "A narrative summary of the brand's visual identity.",
            "nullable": true
          },
          "attributes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Short adjectives describing the visual style (e.g., `minimal`, `high-contrast`).",
            "nullable": true
          }
        }
      },
      "BrandContextBrand": {
        "type": "object",
        "description": "The brand's voice and visual style.",
        "properties": {
          "voice": {
            "$ref": "#/components/schemas/BrandContextVoice"
          },
          "style": {
            "$ref": "#/components/schemas/BrandContextStyle"
          }
        }
      },
      "BrandContextCompetitor": {
        "type": "object",
        "description": "A company the brand competes with. Every key is present; `name` and `domain` are never `null`.",
        "required": ["name", "domain", "type", "category", "positioning", "overlap"],
        "properties": {
          "name": {
            "type": "string",
            "description": "The competitor's name.",
            "nullable": false
          },
          "domain": {
            "type": "string",
            "description": "The competitor's domain. Pass it to the Brand API for the competitor's logos and colors.",
            "nullable": false
          },
          "type": {
            "type": "string",
            "description": "`direct` for a company selling a substitute to the same buyers; `indirect` for one meeting the same need another way.",
            "enum": ["direct", "indirect"],
            "nullable": true
          },
          "category": {
            "type": "string",
            "description": "The competitor's category, as a short noun phrase.",
            "nullable": true
          },
          "positioning": {
            "type": "string",
            "description": "How the competitor positions itself relative to the brand.",
            "nullable": true
          },
          "overlap": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 3,
            "description": "Where the two compete (e.g., a product line, a buyer segment, a region).",
            "nullable": false
          }
        }
      },
      "BrandContextCompetition": {
        "type": "object",
        "nullable": true,
        "description": "The brand's competitors.",
        "required": ["competitors"],
        "properties": {
          "competitors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BrandContextCompetitor"
            },
            "maxItems": 5,
            "description": "Up to five competitors, most direct first. Empty when none can be identified, which is common for small and local businesses.",
            "nullable": false
          }
        }
      },
      "BrandContextResponse": {
        "type": "object",
        "description": "Full brand context returned by the Brand Context API. Note: unlike other endpoints in this API which use camelCase, the Brand Context endpoint intentionally returns field names in `snake_case` (e.g., `canonical_name`, `resolved_at`, `value_proposition`, `target_audience`, `products_and_services`) to align with conventions commonly used by LLM tooling that consumes this data.",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/BrandContextMeta"
          },
          "identity": {
            "$ref": "#/components/schemas/BrandContextIdentity"
          },
          "positioning": {
            "$ref": "#/components/schemas/BrandContextPositioning"
          },
          "brand": {
            "$ref": "#/components/schemas/BrandContextBrand"
          },
          "competition": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BrandContextCompetition"
              }
            ],
            "description": "The brand's competitors. `null` for a context generated before competitors were added to the Brand Context API; such contexts are regenerated over time."
          }
        }
      },
      "PaymentChallenge": {
        "type": "object",
        "description": "Body of the 402 an unauthenticated request receives when the route can be paid for per request. The machine-readable challenges are in the `PAYMENT-REQUIRED` header for x402 and the `WWW-Authenticate: Payment` header for MPP; this body says the same in prose.",
        "properties": {
          "message": {
            "type": "string",
            "example": "Payment required. Either authenticate with a Brandfetch API key (Authorization: Bearer <key>) or pay for this request with x402: sign the payment described in the PAYMENT-REQUIRED header and retry with a PAYMENT-SIGNATURE header."
          },
          "documentation": {
            "type": "string",
            "example": "https://docs.brandfetch.com/agents/pay-per-request"
          },
          "pricing": {
            "type": "object",
            "properties": {
              "route": {
                "type": "string",
                "example": "GET /v2/brands/*"
              },
              "price": {
                "type": "string",
                "example": "$0.10"
              }
            }
          },
          "resource": {
            "type": "string",
            "description": "The URL the payment is for.",
            "example": "https://api.brandfetch.io/v2/brands/nike.com"
          },
          "standingAccess": {
            "type": "string",
            "example": "For many requests, POST /v2/agents/access (paid the same way) provisions an API key preloaded with prepaid credits."
          }
        }
      },
      "PaymentRejected": {
        "type": "object",
        "description": "Body of the 402 a request carrying a `PAYMENT-SIGNATURE`, or an `Authorization: Payment …` credential, receives when the payment was not accepted or could not be settled. The resource was not served. Nothing was charged, so pay afresh and retry, unless the `message` says to retry the exact request first (a refused settlement of a standing-access purchase).",
        "properties": {
          "message": {
            "type": "string",
            "example": "The payment was not accepted, so the request was not served and nothing was charged. Sign a new payment for the PAYMENT-REQUIRED header and retry."
          },
          "reason": {
            "type": "string",
            "description": "The payment service's reason code, e.g. `insufficient_funds`. An MPP credential adds `credential_spent` (it already paid for a request), `credential_in_use` (another request is settling it; retry this exact request in a moment) `credential_malformed` (it could not be read) and `challenge_invalid` (it answers a challenge this API did not issue; answer a fresh one). A Tempo transaction that cannot complete adds `nonce_already_used`, `transaction_rejected`, `transaction_reverted` and `transaction_expired`: the transfer did not happen, so answer a fresh challenge.",
            "example": "insufficient_funds"
          },
          "documentation": {
            "type": "string",
            "example": "https://docs.brandfetch.com/agents/pay-per-request"
          }
        }
      },
      "AgentAccessOffer": {
        "type": "object",
        "properties": {
          "documentation": {
            "type": "string",
            "example": "https://docs.brandfetch.com/agents/overview"
          },
          "mcp": {
            "type": "string",
            "example": "https://mcp.brandfetch.io/mcp"
          },
          "offer": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "example": "POST"
              },
              "endpoint": {
                "type": "string",
                "example": "https://api.brandfetch.io/v2/agents/access"
              },
              "minUsd": {
                "type": "integer",
                "example": 1
              },
              "maxUsd": {
                "type": "integer",
                "example": 500
              },
              "creditsPerUsd": {
                "type": "integer",
                "example": 20
              },
              "description": {
                "type": "string"
              }
            }
          },
          "payment": {
            "type": "object",
            "description": "How to pay, per protocol. x402 is always on offer; `mpp` is listed, and described, exactly where the deployment's billing can take it — production does.",
            "properties": {
              "protocols": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "example": [
                  "x402",
                  "mpp"
                ]
              },
              "x402": {
                "type": "object",
                "properties": {
                  "protocol": {
                    "type": "string",
                    "example": "x402"
                  },
                  "network": {
                    "type": "string",
                    "description": "CAIP-2 network identifier.",
                    "example": "eip155:8453"
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "mpp": {
                "type": "object",
                "properties": {
                  "protocol": {
                    "type": "string",
                    "example": "mpp"
                  },
                  "methods": {
                    "type": "array",
                    "description": "The MPP payment methods on offer: `tempo` (USDC.e on Tempo) and `stripe` (a card via a shared payment token).",
                    "items": {
                      "type": "string"
                    },
                    "example": [
                      "tempo",
                      "stripe"
                    ]
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "perRequestAlternative": {
            "type": "object",
            "properties": {
              "description": {
                "type": "string"
              },
              "protocols": {
                "type": "array",
                "description": "The per-request payment protocols on offer: `x402`, plus `mpp` where billing takes it.",
                "items": {
                  "type": "string"
                },
                "example": [
                  "x402",
                  "mpp"
                ]
              },
              "prices": {
                "type": "object",
                "properties": {
                  "brandApi": {
                    "type": "string",
                    "example": "$0.10"
                  },
                  "brandContextApi": {
                    "type": "string",
                    "example": "$0.10"
                  },
                  "transactionApi": {
                    "type": "string",
                    "example": "$0.10"
                  }
                }
              }
            }
          }
        }
      },
      "AgentAccessCredential": {
        "type": "object",
        "properties": {
          "organization": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "urn": {
                "type": "string",
                "example": "urn:brandfetch:organization:xig9b54wddtihs0dktyhau0i"
              }
            }
          },
          "apiKey": {
            "type": "object",
            "description": "The API key. Returned once, in the response that completes the purchase: store it.",
            "properties": {
              "id": {
                "type": "string"
              },
              "key": {
                "type": "string",
                "description": "Send as `Authorization: Bearer <key>`."
              },
              "name": {
                "type": "string",
                "example": "Agent Key"
              }
            }
          },
          "apiClient": {
            "type": "object",
            "nullable": true,
            "description": "The Logo API client, for `cdn.brandfetch.io` URLs.",
            "properties": {
              "clientId": {
                "type": "string"
              }
            }
          },
          "mcp": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "example": "https://mcp.brandfetch.io/mcp"
              },
              "token": {
                "type": "string",
                "description": "Bearer token for the Brandfetch MCP server; starts with `bf1.`."
              }
            }
          },
          "credits": {
            "type": "object",
            "properties": {
              "granted": {
                "type": "integer",
                "description": "Credits this payment bought.",
                "example": 20
              },
              "balance": {
                "type": "integer",
                "description": "Credits the key holds now.",
                "example": 20
              },
              "creditsPerUsd": {
                "type": "integer",
                "example": 20
              },
              "usdPaid": {
                "type": "number",
                "example": 1
              },
              "deduplicated": {
                "type": "boolean",
                "description": "`false` when this request granted the credits. `true` when an earlier attempt at the same purchase had already granted them, before its response failed: they are granted once either way."
              }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "authorization": {
                "type": "string",
                "example": "Bearer <key>"
              },
              "note": {
                "type": "string"
              }
            }
          },
          "topUp": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "example": "POST"
              },
              "url": {
                "type": "string"
              },
              "note": {
                "type": "string"
              }
            }
          },
          "documentation": {
            "type": "string",
            "example": "https://docs.brandfetch.com/agents/overview"
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      },
      "clientId": {
        "type": "apiKey",
        "in": "query",
        "name": "c",
        "description": "Your Brand Search client ID, sent as the `c` query parameter. Get one at https://developers.brandfetch.com."
      },
      "x402Payment": {
        "type": "apiKey",
        "in": "header",
        "name": "PAYMENT-SIGNATURE",
        "description": "An x402 payment for this one request: the signed payment for the challenge a bare request receives in its `PAYMENT-REQUIRED` header. Alternative to the bearer API key. See https://docs.brandfetch.com/agents/pay-per-request."
      },
      "mppPayment": {
        "type": "http",
        "scheme": "Payment",
        "description": "An MPP (Machine Payments Protocol) payment, settled through Stripe: the credential answering one of the `WWW-Authenticate: Payment` challenges a bare request receives. Alternative to the bearer API key. See https://docs.brandfetch.com/agents/pay-per-request#paying-with-mpp."
      }
    }
  }
}
