{
  "openapi": "3.1.0",
  "info": {
    "title": "Brandmarks API",
    "version": "1.0.0",
    "description": "Read-only v1 API for company data and brand images. The API is currently invite-only beta."
  },
  "servers": [{ "url": "https://brandmarks-api.brandmarks-web.workers.dev" }],
  "tags": [
    { "name": "Logos", "description": "Company logo and mark image delivery." },
    { "name": "Companies", "description": "Company metadata and search. These routes require a secret key." }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getApiInfo",
        "summary": "Get API version and catalog count",
        "responses": {
          "200": { "description": "Public API information.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiInfo" }, "example": { "name": "brandmarks API", "version": "v1", "companies": 2520, "docs": "https://brandmarks.dev/docs/" } } } },
          "405": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        },
        "x-code-samples": [{ "lang": "curl", "label": "API information", "source": "curl 'https://brandmarks-api.brandmarks-web.workers.dev/'" }]
      },
      "head": {
        "operationId": "headApiInfo",
        "summary": "Check API information headers without a body",
        "responses": { "200": { "description": "Response headers; no response body." }, "500": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/v1/logo/{identifier}": {
      "get": {
        "operationId": "getLogo",
        "tags": ["Logos"],
        "summary": "Get a company logo or mark",
        "description": "Identifiers may be a Brandmarks company ID, ticker, former ticker, or domain. A publishable key is recommended. Use `fallback=monogram` to return a placeholder for an unknown identifier.",
        "parameters": [
          { "$ref": "#/components/parameters/Identifier" },
          { "name": "variant", "in": "query", "schema": { "type": "string", "enum": ["auto", "logo", "mark"], "default": "auto" }, "description": "`auto` selects the mark when available, otherwise the full logo." },
          { "name": "theme", "in": "query", "schema": { "type": "string", "enum": ["color", "white", "black", "brand"], "default": "color" }, "description": "Black and brand themes are SVG-only." },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["svg", "png"], "default": "svg" } },
          { "name": "size", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 4000 }, "description": "Requested PNG size in pixels; the service selects a stored rendition." },
          { "name": "fallback", "in": "query", "schema": { "type": "string", "enum": ["monogram"] }, "description": "Return a lettered SVG when no company matches." },
          { "$ref": "#/components/parameters/QueryToken" },
          { "$ref": "#/components/parameters/IfNoneMatch" }
        ],
        "security": [{ "BearerKey": [] }, { "QueryToken": [] }],
        "responses": {
          "200": {
            "description": "Logo image or requested monogram.",
            "content": {
              "image/svg+xml": { "schema": { "type": "string", "contentMediaType": "image/svg+xml" }, "example": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1080 1080\">…</svg>" },
              "image/png": { "schema": { "type": "string", "contentEncoding": "binary" } }
            },
            "headers": {
              "Cache-Control": { "schema": { "type": "string" }, "description": "Image cache policy." },
              "ETag": { "schema": { "type": "string" }, "description": "May contain the stored source object's ETag." },
              "X-Brandmarks-Company": { "schema": { "type": "string" } },
              "X-Brandmarks-Variant": { "schema": { "type": "string", "enum": ["logo", "mark"] } },
              "X-Brandmarks-Theme": { "schema": { "type": "string", "enum": ["color", "white", "black", "brand"] } },
              "X-Brandmarks-Fallback": { "schema": { "type": "string", "enum": ["monogram"] }, "description": "Present for a monogram response." }
            }
          },
          "304": { "$ref": "#/components/responses/NotModified" },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "405": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        },
        "x-code-samples": [{ "lang": "curl", "label": "Apple mark (publishable key)", "source": "curl 'https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/AAPL?token=pk_YOUR_PUBLISHABLE_KEY'" }]
      },
      "head": {
        "operationId": "headLogo",
        "tags": ["Logos"],
        "summary": "Get logo response headers without a body",
        "description": "Supports the same image query options as GET. If-None-Match can return 304. A HEAD request still requires and checks a key.",
        "parameters": [
          { "$ref": "#/components/parameters/Identifier" },
          { "name": "variant", "in": "query", "schema": { "type": "string", "enum": ["auto", "logo", "mark"], "default": "auto" } },
          { "name": "theme", "in": "query", "schema": { "type": "string", "enum": ["color", "white", "black", "brand"], "default": "color" } },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["svg", "png"], "default": "svg" } },
          { "name": "size", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 4000 } },
          { "name": "fallback", "in": "query", "schema": { "type": "string", "enum": ["monogram"] } },
          { "$ref": "#/components/parameters/QueryToken" },
          { "$ref": "#/components/parameters/IfNoneMatch" }
        ],
        "security": [{ "BearerKey": [] }, { "QueryToken": [] }],
        "responses": {
          "200": { "description": "Image response headers; no response body.", "headers": { "ETag": { "schema": { "type": "string" } }, "Cache-Control": { "schema": { "type": "string" } }, "X-Brandmarks-Company": { "schema": { "type": "string" } }, "X-Brandmarks-Variant": { "schema": { "type": "string" } }, "X-Brandmarks-Theme": { "schema": { "type": "string" } } } },
          "304": { "$ref": "#/components/responses/NotModified" },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/companies/{identifier}": {
      "get": {
        "operationId": "getCompany",
        "tags": ["Companies"],
        "summary": "Get company data",
        "parameters": [{ "$ref": "#/components/parameters/Identifier" }],
        "security": [{ "BearerKey": [] }],
        "responses": {
          "200": { "description": "Company data.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Company" }, "examples": { "apple": { "$ref": "#/components/examples/Company" } } } } },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "405": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        },
        "x-code-samples": [{ "lang": "curl", "label": "Apple company data (secret key)", "source": "curl -H 'Authorization: Bearer sk_YOUR_SECRET_KEY' 'https://brandmarks-api.brandmarks-web.workers.dev/v1/companies/AAPL'" }]
      },
      "head": {
        "operationId": "headCompany",
        "tags": ["Companies"],
        "summary": "Check company endpoint headers without a body",
        "parameters": [{ "$ref": "#/components/parameters/Identifier" }],
        "security": [{ "BearerKey": [] }],
        "responses": {
          "200": { "description": "JSON response headers; no response body." },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/search": {
      "get": {
        "operationId": "searchCompanies",
        "tags": ["Companies"],
        "summary": "Search companies",
        "parameters": [
          { "name": "q", "in": "query", "required": true, "description": "Company name, ticker, or domain.", "schema": { "type": "string", "minLength": 1 }, "example": "Apple" },
          { "name": "limit", "in": "query", "description": "Maximum results. Defaults to 10. Values outside 1–50 or non-integers return 400.", "schema": { "type": "integer", "default": 10, "minimum": 1, "maximum": 50 } }
        ],
        "security": [{ "BearerKey": [] }],
        "responses": {
          "200": { "description": "Matching companies, ranked with the strongest match first.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResponse" }, "examples": { "search": { "$ref": "#/components/examples/Search" } } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "405": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        },
        "x-code-samples": [{ "lang": "curl", "label": "Search with a secret key", "source": "curl -H 'Authorization: Bearer sk_YOUR_SECRET_KEY' 'https://brandmarks-api.brandmarks-web.workers.dev/v1/search?q=Apple&limit=5'" }]
      },
      "head": {
        "operationId": "headSearch",
        "tags": ["Companies"],
        "summary": "Check search endpoint headers without a body",
        "parameters": [
          { "name": "q", "in": "query", "required": true, "schema": { "type": "string", "minLength": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 10, "minimum": 1, "maximum": 50 } }
        ],
        "security": [{ "BearerKey": [] }],
        "responses": {
          "200": { "description": "JSON response headers; no response body." },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerKey": { "type": "http", "scheme": "bearer", "bearerFormat": "Brandmarks API key", "description": "Use a publishable pk_ key for logos or a secret sk_ key for company/search data." },
      "QueryToken": { "type": "apiKey", "in": "query", "name": "token", "description": "Publishable key for image URLs. Bearer authorization takes precedence." }
    },
    "parameters": {
      "Identifier": { "name": "identifier", "in": "path", "required": true, "description": "Company ID, ticker (including exchange suffixes), former ticker, or domain. Domain lookup checks exact hosts and then the registrable domain using the Public Suffix List.", "schema": { "type": "string", "minLength": 1 }, "example": "AAPL" },
      "IfNoneMatch": { "name": "If-None-Match", "in": "header", "description": "A matching image validator returns 304 Not Modified.", "schema": { "type": "string" } },
      "QueryToken": { "name": "token", "in": "query", "description": "Publishable key for image URLs. Prefer Authorization headers when possible.", "schema": { "type": "string", "pattern": "^pk_" } }
    },
    "schemas": {
      "Error": {
        "type": "object", "required": ["error"], "additionalProperties": false,
        "properties": { "error": { "type": "object", "required": ["code", "message"], "additionalProperties": false, "properties": { "code": { "type": "string", "enum": ["missing_key", "invalid_key", "secret_key_required", "domain_not_allowed", "rate_limited", "quota_exceeded", "not_found", "bad_request", "method_not_allowed", "unauthorized", "internal"] }, "message": { "type": "string" } } } }
      },
      "Reference": { "type": "object", "required": ["id", "name"], "properties": { "id": { "type": "string" }, "name": { "type": ["string", "null"] } } },
      "ApiInfo": { "type": "object", "required": ["name", "version", "companies", "docs"], "properties": { "name": { "type": "string" }, "version": { "type": "string", "const": "v1" }, "companies": { "type": "integer", "minimum": 0 }, "docs": { "type": "string", "format": "uri" } } },
      "Ticker": { "type": "object", "required": ["ticker", "symbol"], "properties": { "ticker": { "type": "string" }, "symbol": { "type": "string" } } },
      "LogoThemes": { "type": "object", "required": ["color", "white", "black", "brand"], "properties": { "color": { "type": "string", "format": "uri" }, "white": { "type": "string", "format": "uri" }, "black": { "type": "string", "format": "uri" }, "brand": { "type": "string", "format": "uri" } } },
      "LogoVariants": { "type": "object", "required": ["logo", "mark"], "properties": { "logo": { "$ref": "#/components/schemas/LogoThemes" }, "mark": { "$ref": "#/components/schemas/LogoThemes" } } },
      "MarkInfo": { "type": "object", "required": ["method", "legible_small", "recommended_variant"], "properties": { "method": { "type": "string" }, "legible_small": { "type": "boolean" }, "recommended_variant": { "type": "string", "enum": ["logo", "mark"] } } },
      "Company": {
        "type": "object", "required": ["id", "name", "tickers", "former_tickers", "parent", "brands", "description", "sector", "industry", "category", "country", "wikidata", "domain", "mark", "colors", "primary", "on_primary", "logos"],
        "properties": {
          "id": { "type": "string" }, "name": { "type": ["string", "null"] }, "tickers": { "type": "array", "items": { "$ref": "#/components/schemas/Ticker" } }, "former_tickers": { "type": "array", "items": { "type": "string" } },
          "parent": { "anyOf": [{ "$ref": "#/components/schemas/Reference" }, { "type": "null" }] }, "brands": { "type": "array", "items": { "$ref": "#/components/schemas/Reference" } },
          "description": { "type": ["string", "null"] }, "sector": { "type": ["string", "null"] }, "industry": { "type": ["string", "null"] }, "category": { "type": ["string", "null"] }, "country": { "type": ["string", "null"] }, "wikidata": { "type": ["string", "null"] }, "domain": { "type": ["string", "null"] },
          "mark": { "$ref": "#/components/schemas/MarkInfo" }, "colors": { "type": "array", "items": { "type": "string" } }, "primary": { "type": ["string", "null"] }, "on_primary": { "type": ["string", "null"] }, "logos": { "$ref": "#/components/schemas/LogoVariants" }
        }
      },
      "SearchResponse": { "type": "object", "required": ["query", "results"], "properties": { "query": { "type": "string" }, "results": { "type": "array", "items": { "$ref": "#/components/schemas/Company" } } } }
    },
    "responses": {
      "NotModified": { "description": "The cached representation is current.", "headers": { "ETag": { "schema": { "type": "string" } }, "Cache-Control": { "schema": { "type": "string" } } } },
      "Error": { "description": "API error. For HTTP 429, branch on `error.code`: `rate_limited` is the per-key burst limit and `quota_exceeded` is the account monthly limit. Quota errors include Retry-After and X-Quota-Limit, X-Quota-Used, and X-Quota-Reset headers.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "examples": { "notFound": { "value": { "error": { "code": "not_found", "message": "No company found for 'UNKNOWN'." } } }, "missingKey": { "value": { "error": { "code": "missing_key", "message": "Send a valid Brandmarks API key." } } } } } } }
    },
    "examples": {
      "Company": { "summary": "Selected fields from a company response", "value": { "id": "apple", "name": "Apple", "tickers": [{ "ticker": "AAPL", "symbol": "AAPL" }], "former_tickers": [], "parent": null, "brands": [], "description": null, "sector": null, "industry": null, "category": null, "country": "US", "wikidata": null, "domain": "apple.com", "mark": { "method": "provided", "legible_small": true, "recommended_variant": "mark" }, "colors": [], "primary": null, "on_primary": null, "logos": { "logo": { "color": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=logo&theme=color", "white": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=logo&theme=white", "black": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=logo&theme=black", "brand": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=logo&theme=brand" }, "mark": { "color": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=mark&theme=color", "white": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=mark&theme=white", "black": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=mark&theme=black", "brand": "https://brandmarks-api.brandmarks-web.workers.dev/v1/logo/apple?variant=mark&theme=brand" } } } },
      "Search": { "summary": "Search with no matches", "value": { "query": "example with no matches", "results": [] } }
    }
  }
}
