{
  "openapi": "3.1.0",
  "info": {
    "title": "JupiterFetch API",
    "version": "v1",
    "description": "Give JupiterFetch a domain and get that company's brand profile back as JSON: logos, colors with roles, fonts, images, social links and metadata. Every image is hosted on cdn.jupiterfetch.com for at least 30 days after delivery. Fields are only ever added, so parse permissively; enums are closed, and a new member is a contract change announced in advance, not one to expect silently.",
    "termsOfService": "https://jupiterfetch.com/terms",
    "contact": {
      "name": "JupiterFetch support",
      "url": "https://jupiterfetch.com/contact"
    }
  },
  "externalDocs": {
    "description": "API reference",
    "url": "https://jupiterfetch.com/docs"
  },
  "servers": [
    {
      "url": "https://jupiterfetch.com/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/brands/{domain}": {
      "get": {
        "operationId": "getBrand",
        "summary": "Get a company's brand profile",
        "description": "Blocking. A fresh cached profile comes back at once; a miss runs the fetch within the wait budget. Every 200 spends one credit, cached or not; errors spend none. When the budget runs out the answer is 424 fetch_timeout, and the fetch keeps running and fills the cache, so a retry usually succeeds. Branch on the problem code, not on the status.",
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "A bare domain such as example.com, percent-encoded. A work email address also works: everything before the @ is dropped, and our own records keep only the domain. A personal email address, at a provider such as Gmail, is refused with invalid_url. The full URL still passes through network logs on the way to us, so send the domain when that matters.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "wait",
            "in": "query",
            "required": false,
            "description": "How long to block, in milliseconds. Larger values are clamped to 60000, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 20000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The brand profile. A thin result is still a 200 with a low quality.score, never a 404.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Brand"
                },
                "example": {
                  "domain": "example.com",
                  "url": "https://example.com/",
                  "name": "Example",
                  "description": "An example company, here to show the shape of a profile.",
                  "colorScheme": "both",
                  "logos": [
                    {
                      "id": "wordmark-3k9x2a",
                      "kind": "wordmark",
                      "theme": "light",
                      "source": "https://cdn.jupiterfetch.com/example.com/3f2a9c1e7b4d6a8f0c5e2b9d1a7f3c6e.png",
                      "sourceType": "inline-svg",
                      "confidence": 0.95,
                      "format": "png",
                      "vectorUrl": "https://cdn.jupiterfetch.com/example.com/9b1e4d7a2c6f8e0b3d5a7c9e1f4b6d8a.svg",
                      "originUrl": null,
                      "width": 2048,
                      "height": 512
                    },
                    {
                      "id": "favicon-7p4m1q",
                      "kind": "favicon",
                      "theme": "any",
                      "source": "https://cdn.jupiterfetch.com/example.com/5c8e2a7f1d4b9e3a6c0f8d2b7e5a1c9f.png",
                      "sourceType": "link-icon",
                      "confidence": 0.4,
                      "format": "png",
                      "vectorUrl": null,
                      "originUrl": "https://example.com/favicon.png",
                      "width": 180,
                      "height": 180
                    }
                  ],
                  "colors": {
                    "roles": {
                      "primary": "#4a6cf7",
                      "secondary": "#1e2a3a",
                      "accent": null,
                      "background": "#ffffff",
                      "surface": "#f4f6f8",
                      "textPrimary": null,
                      "textSecondary": null,
                      "link": null
                    },
                    "palette": [
                      {
                        "hex": "#4a6cf7",
                        "type": "brand",
                        "brightness": 45,
                        "usage": 1,
                        "sources": [
                          "css-usage",
                          "logo-pixel"
                        ],
                        "confidence": 0.8
                      },
                      {
                        "hex": "#1e2a3a",
                        "type": "dark",
                        "brightness": 16,
                        "usage": 0.2,
                        "sources": [
                          "css-background"
                        ],
                        "confidence": 0.7
                      }
                    ]
                  },
                  "typography": {
                    "fonts": [
                      {
                        "family": "Inter",
                        "role": "body",
                        "origin": "google",
                        "originId": "Inter",
                        "weights": [
                          "400",
                          "500",
                          "700"
                        ],
                        "sources": [
                          {
                            "url": "https://fonts.gstatic.com/s/inter/v13/example.woff2",
                            "format": "woff2"
                          }
                        ],
                        "fallback": "sans-serif",
                        "confidence": 0.85
                      }
                    ]
                  },
                  "images": {
                    "og": {
                      "source": "https://cdn.jupiterfetch.com/example.com/7a3d9f1c5e8b2a6d0f4c9e7b3a1d5f8c.jpg",
                      "originUrl": "https://example.com/og.jpg",
                      "format": "jpeg",
                      "width": 1200,
                      "height": 630
                    },
                    "twitter": null,
                    "banners": []
                  },
                  "links": {
                    "website": "https://example.com/",
                    "twitter": "https://x.com/example",
                    "linkedin": "https://www.linkedin.com/company/example",
                    "github": null,
                    "youtube": null,
                    "instagram": null,
                    "facebook": null,
                    "tiktok": null,
                    "crunchbase": null,
                    "careers": "https://example.com/careers",
                    "pricing": "https://example.com/pricing",
                    "contact": "https://example.com/contact",
                    "blog": "https://example.com/blog",
                    "docs": null,
                    "privacy": "https://example.com/privacy",
                    "terms": "https://example.com/terms"
                  },
                  "company": {
                    "tagline": null,
                    "legalName": "Example Inc.",
                    "email": null,
                    "phone": null,
                    "address": {
                      "street": "1 Example Street",
                      "locality": "Springfield",
                      "region": null,
                      "postalCode": null,
                      "country": "US"
                    },
                    "foundedYear": 2010
                  },
                  "theme": {
                    "fonts": {
                      "heading": null,
                      "body": null
                    },
                    "radius": null,
                    "shadow": null,
                    "button": {
                      "background": null,
                      "text": null,
                      "border": null,
                      "radius": null
                    },
                    "css": ":root {\n  --brand-primary: #4a6cf7;\n  --brand-secondary: #1e2a3a;\n  --brand-background: #ffffff;\n  --brand-surface: #f4f6f8;\n}\n"
                  },
                  "meta": {
                    "title": "Example",
                    "language": "en",
                    "themeColor": "#4a6cf7",
                    "manifest": null,
                    "schemaOrg": {
                      "type": "Organization",
                      "name": "Example"
                    }
                  },
                  "quality": {
                    "score": 86,
                    "coverage": {
                      "logo": true,
                      "colors": true,
                      "fonts": true,
                      "links": true
                    },
                    "warnings": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_url: The domain could not be parsed, it is a personal email address, or a query parameter is invalid.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://jupiterfetch.com/problems/invalid_url",
                  "title": "Invalid URL",
                  "status": 400,
                  "code": "invalid_url",
                  "detail": "domain is not a parseable host"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: The bearer key is missing, malformed or not recognized.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://jupiterfetch.com/problems/unauthorized",
                  "title": "Unauthorized",
                  "status": 401,
                  "code": "unauthorized",
                  "detail": "a valid `Authorization: Bearer jf_…` header is required"
                }
              }
            }
          },
          "402": {
            "description": "quota_exceeded: The account has no credits left. Every 200 spends a credit, cached or not; errors spend none.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://jupiterfetch.com/problems/quota_exceeded",
                  "title": "Quota exceeded",
                  "status": 402,
                  "code": "quota_exceeded",
                  "detail": "this account has no credits left; buy credits at https://jupiterfetch.com/billing"
                }
              }
            }
          },
          "403": {
            "description": "forbidden_domain: The domain resolves to a private, loopback, link-local or otherwise reserved address, including localhost, or a redirect leads to one.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://jupiterfetch.com/problems/forbidden_domain",
                  "title": "Forbidden domain",
                  "status": 403,
                  "code": "forbidden_domain",
                  "detail": "this domain points at an address that may not be fetched",
                  "fetchId": "ft_4k9mzq2h7wcrd5ta8xyb3nep"
                }
              }
            }
          },
          "404": {
            "description": "domain_unresolvable: DNS returned no address for the domain.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://jupiterfetch.com/problems/domain_unresolvable",
                  "title": "Domain unresolvable",
                  "status": 404,
                  "code": "domain_unresolvable",
                  "detail": "example.invalid does not resolve (ENOTFOUND)",
                  "fetchId": "ft_4k9mzq2h7wcrd5ta8xyb3nep"
                }
              }
            }
          },
          "424": {
            "description": "site_blocked: The site refused the fetch or served a block or challenge page. The problem document may carry a partial profile in brand. A definite block is remembered for ten minutes. fetch_timeout: The site did not answer within the wait budget. The fetch keeps running and fills the cache, so a retry usually succeeds.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "site_blocked": {
                    "summary": "site_blocked",
                    "value": {
                      "type": "https://jupiterfetch.com/problems/site_blocked",
                      "title": "Site blocked the fetch",
                      "status": 424,
                      "code": "site_blocked",
                      "detail": "the site's bot protection refused the request",
                      "fetchId": "ft_4k9mzq2h7wcrd5ta8xyb3nep"
                    }
                  },
                  "fetch_timeout": {
                    "summary": "fetch_timeout",
                    "value": {
                      "type": "https://jupiterfetch.com/problems/fetch_timeout",
                      "title": "Fetch timed out",
                      "status": 424,
                      "code": "fetch_timeout",
                      "detail": "the fetch did not complete within 20000 ms; it is still running and will populate the cache, so a retry should succeed",
                      "fetchId": "ft_4k9mzq2h7wcrd5ta8xyb3nep"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests, or the service is at capacity. Wait the number of seconds in Retry-After, then retry.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://jupiterfetch.com/problems/rate_limited",
                  "title": "Rate limited",
                  "status": 429,
                  "code": "rate_limited",
                  "detail": "too many requests for this account"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something failed on our side, not on the site. No credit is spent. A retry may succeed; if it keeps happening, quote the X-Fetch-Id to support.",
            "headers": {
              "X-Fetch-Id": {
                "$ref": "#/components/headers/FetchId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://jupiterfetch.com/problems/internal_error",
                  "title": "Internal error",
                  "status": 500,
                  "code": "internal_error",
                  "detail": "an internal error stopped this fetch; a retry may succeed",
                  "fetchId": "ft_4k9mzq2h7wcrd5ta8xyb3nep"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A key from https://jupiterfetch.com/api-keys, sent as Authorization: Bearer <key>. Keys start with jf_."
      }
    },
    "headers": {
      "FetchId": {
        "description": "The id of the fetch behind this response. When the profile came from the cache it is the fetch that produced it, the same value as fetch.id. Quote it in a bug report.",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "CacheControl": {
        "description": "Always no-store. Do not put a shared cache in front of the API.",
        "required": true,
        "schema": {
          "type": "string",
          "const": "no-store"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying. Sent with every 429, and with no other status.",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "schemas": {
      "Brand": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "minLength": 1,
            "description": "The domain the profile is for: lowercase, with no scheme."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The URL fetched, after redirects."
          },
          "name": {
            "description": "The brand's name. When the page does not say, it is the first part of the domain, capitalized: Example for example.com.",
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "description": "The site's own description, such as its meta description, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "colorScheme": {
            "description": "The color schemes the page declares; light when it declares none.",
            "$ref": "#/components/schemas/ColorScheme"
          },
          "logos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Logo"
            },
            "description": "The logos, primary first. Can be empty."
          },
          "colors": {
            "description": "Color roles and the full palette.",
            "$ref": "#/components/schemas/Colors"
          },
          "typography": {
            "description": "Typefaces found on the page.",
            "$ref": "#/components/schemas/Typography"
          },
          "images": {
            "description": "Social and banner images.",
            "$ref": "#/components/schemas/Images"
          },
          "links": {
            "description": "Website, social profiles and main site pages.",
            "$ref": "#/components/schemas/Links"
          },
          "company": {
            "description": "Tagline, legal name, contact details, address and founding year.",
            "$ref": "#/components/schemas/Company"
          },
          "theme": {
            "description": "Fonts, radius, shadow and button tokens, and a ready-to-paste CSS block.",
            "$ref": "#/components/schemas/Theme"
          },
          "meta": {
            "description": "Title, language, theme color, manifest and schema.org data.",
            "$ref": "#/components/schemas/Meta"
          },
          "quality": {
            "description": "How much this fetch found.",
            "$ref": "#/components/schemas/Quality"
          }
        },
        "required": [
          "domain",
          "url",
          "name",
          "description",
          "colorScheme",
          "logos",
          "colors",
          "typography",
          "images",
          "links",
          "company",
          "theme",
          "meta",
          "quality"
        ],
        "description": "A company's brand profile. Every field is always present, and fields are only ever added."
      },
      "Logo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "description": "An id for this logo, unique within the profile."
          },
          "kind": {
            "description": "What the image is.",
            "$ref": "#/components/schemas/LogoKind"
          },
          "theme": {
            "description": "The background the logo is designed for.",
            "$ref": "#/components/schemas/LogoTheme"
          },
          "source": {
            "type": "string",
            "format": "uri",
            "description": "The logo as a raster on cdn.jupiterfetch.com. It works for at least 30 days after you receive it; download it if you want to keep it."
          },
          "sourceType": {
            "description": "Where on the page the logo was found.",
            "$ref": "#/components/schemas/LogoSourceType"
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "From 0 to 1, higher for stronger evidence. Not a probability, and not what logos is sorted by."
          },
          "format": {
            "description": "The hosted file's format. Never null and never SVG.",
            "$ref": "#/components/schemas/HostedImageFormat"
          },
          "vectorUrl": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The sanitized SVG on cdn.jupiterfetch.com when the logo was SVG, else null. Safe to use in an img tag."
          },
          "originUrl": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the logo came from, or null when the page embedded it. Informational only: never fetch it and use what comes back."
          },
          "width": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "The hosted file's width in pixels."
          },
          "height": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "The hosted file's height in pixels."
          }
        },
        "required": [
          "id",
          "kind",
          "theme",
          "source",
          "sourceType",
          "confidence",
          "format",
          "vectorUrl",
          "originUrl",
          "width",
          "height"
        ],
        "description": "One logo, hosted by JupiterFetch. logos[0] is the primary; the rest hold at most one entry per slot and are never sorted by confidence."
      },
      "LogoKind": {
        "type": "string",
        "enum": [
          "logo",
          "wordmark",
          "symbol",
          "icon",
          "favicon",
          "app-icon",
          "og"
        ],
        "description": "What a logo image is."
      },
      "LogoTheme": {
        "type": "string",
        "enum": [
          "light",
          "dark",
          "any"
        ],
        "description": "The background a logo is designed to sit on, not the logo's own color: a white wordmark is dark. any when it reads on both, or when nothing says."
      },
      "LogoSourceType": {
        "type": "string",
        "enum": [
          "header-img",
          "inline-svg",
          "link-icon",
          "apple-touch",
          "manifest",
          "og",
          "schema-org",
          "llm"
        ],
        "description": "Where a logo was found: on the page, in its web app manifest or structured data, or a favicon fallback such as a DNS BIMI record or an unlinked favicon.ico guess."
      },
      "HostedImageFormat": {
        "type": "string",
        "enum": [
          "png",
          "jpeg",
          "webp",
          "gif"
        ],
        "description": "The format of a hosted image, read from its bytes. SVG is rasterized to PNG, and AVIF and ICO are converted, so every hosted image is a raster."
      },
      "Image": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "format": "uri",
            "description": "The image on cdn.jupiterfetch.com. It works for at least 30 days after you receive it; download it if you want to keep it."
          },
          "originUrl": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the image came from, or null when the page embedded it. Informational only: never fetch it and use what comes back."
          },
          "format": {
            "description": "The hosted file's format. Serve a stored copy with this Content-Type and X-Content-Type-Options: nosniff.",
            "$ref": "#/components/schemas/HostedImageFormat"
          },
          "width": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "The hosted file's width in pixels."
          },
          "height": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "The hosted file's height in pixels."
          }
        },
        "required": [
          "source",
          "originUrl",
          "format",
          "width",
          "height"
        ],
        "description": "An image hosted by JupiterFetch. The URL works for at least 30 days after you receive it; download what you want to keep."
      },
      "Images": {
        "type": "object",
        "properties": {
          "og": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Image"
              },
              {
                "type": "null"
              }
            ],
            "description": "The page's social image, or null."
          },
          "twitter": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Image"
              },
              {
                "type": "null"
              }
            ],
            "description": "The image the page names for X cards, or null. When it is the same image as og, both carry the same URL; to show what X shows, read twitter, then og."
          },
          "banners": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Image"
            },
            "description": "Banner images. Empty today."
          }
        },
        "required": [
          "og",
          "twitter",
          "banners"
        ],
        "description": "The page's social and banner images."
      },
      "Colors": {
        "type": "object",
        "properties": {
          "roles": {
            "description": "The named color roles.",
            "$ref": "#/components/schemas/ColorRoles"
          },
          "palette": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaletteEntry"
            },
            "description": "The main colors found, most significant first, with near-duplicates merged. Capped, so not every color the page uses."
          }
        },
        "required": [
          "roles",
          "palette"
        ],
        "description": "The brand's colors: named roles, and a ranked palette."
      },
      "ColorRoles": {
        "type": "object",
        "properties": {
          "primary": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The main brand color, or null."
          },
          "secondary": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The second brand color, or null."
          },
          "accent": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "An accent color, or null."
          },
          "background": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The page background the site declares, or null."
          },
          "surface": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "A panel or card background, or null."
          },
          "textPrimary": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The main text color, or null. Only a page rendered in a browser reports it."
          },
          "textSecondary": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The secondary text color, or null. Only a page rendered in a browser reports it."
          },
          "link": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The link color, or null. Only a page rendered in a browser reports it."
          }
        },
        "required": [
          "primary",
          "secondary",
          "accent",
          "background",
          "surface",
          "textPrimary",
          "textSecondary",
          "link"
        ],
        "description": "Named color roles. Every key is always present; a role the page gives no evidence for is null."
      },
      "PaletteEntry": {
        "type": "object",
        "properties": {
          "hex": {
            "description": "The color.",
            "$ref": "#/components/schemas/HexColor"
          },
          "type": {
            "description": "What kind of color it is.",
            "$ref": "#/components/schemas/PaletteType"
          },
          "brightness": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Perceived brightness, from 0 to 100."
          },
          "usage": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "How prominent the color is relative to the other entries in this profile, from 0 to 1. A ranking weight, not a measured share of the page, and not comparable across profiles."
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Where the color was seen, such as css-usage or theme-color. For diagnostics; new values appear over time."
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "From 0 to 1, higher for stronger evidence."
          }
        },
        "required": [
          "hex",
          "type",
          "brightness",
          "usage",
          "sources",
          "confidence"
        ],
        "description": "One color found on the page."
      },
      "PaletteType": {
        "type": "string",
        "enum": [
          "brand",
          "accent",
          "dark",
          "light"
        ],
        "description": "What kind of color a palette entry is."
      },
      "Typography": {
        "type": "object",
        "properties": {
          "fonts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Font"
            },
            "description": "The typefaces, most confident first."
          }
        },
        "required": [
          "fonts"
        ],
        "description": "The typefaces the page uses."
      },
      "Font": {
        "type": "object",
        "properties": {
          "family": {
            "type": "string",
            "minLength": 1,
            "description": "The family name, as the page declares it."
          },
          "role": {
            "description": "What the typeface is used for.",
            "$ref": "#/components/schemas/FontRole"
          },
          "origin": {
            "description": "Who publishes the typeface.",
            "$ref": "#/components/schemas/FontOrigin"
          },
          "originId": {
            "description": "For google, Google's own spelling of the family, ready for a fonts.googleapis.com URL. Null for every other origin.",
            "type": [
              "string",
              "null"
            ]
          },
          "weights": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The weights the page declares, as written: 400, bold, or a range such as 100 900. 400 when it declares none."
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FontSource"
            },
            "description": "The font files the page loads for this family."
          },
          "fallback": {
            "type": "string",
            "description": "The generic family the declared stack ends with, such as sans-serif; sans-serif when it is not known."
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "From 0 to 1, higher for stronger evidence."
          }
        },
        "required": [
          "family",
          "role",
          "origin",
          "originId",
          "weights",
          "sources",
          "fallback",
          "confidence"
        ],
        "description": "One typeface the page uses."
      },
      "FontRole": {
        "type": "string",
        "enum": [
          "heading",
          "body",
          "display",
          "code",
          "ui"
        ],
        "description": "What a typeface is used for."
      },
      "FontOrigin": {
        "type": "string",
        "enum": [
          "google",
          "adobe",
          "custom",
          "system"
        ],
        "description": "Who publishes a typeface. google: Google Fonts publishes it, so you can load it from there. adobe: the page loads Adobe Fonts and the family likely comes from there. custom: the family's files come from the site or another host. system: a stack the reader's device resolves."
      },
      "FontSource": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The font file's URL."
          },
          "format": {
            "description": "The file's format.",
            "$ref": "#/components/schemas/FontFileFormat"
          }
        },
        "required": [
          "url",
          "format"
        ],
        "description": "One font file the page loads."
      },
      "FontFileFormat": {
        "type": "string",
        "enum": [
          "woff2",
          "woff",
          "ttf",
          "otf",
          "eot"
        ],
        "description": "The format of a font file."
      },
      "Links": {
        "type": "object",
        "properties": {
          "website": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The URL fetched, after redirects; the same as url."
          },
          "twitter": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's X (Twitter) profile, or null."
          },
          "linkedin": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's LinkedIn page, or null."
          },
          "github": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's GitHub profile, or null."
          },
          "youtube": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's YouTube channel, or null."
          },
          "instagram": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's Instagram profile, or null."
          },
          "facebook": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's Facebook page, or null."
          },
          "tiktok": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's TikTok profile, or null."
          },
          "crunchbase": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand's Crunchbase profile, or null."
          },
          "careers": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The company's careers or jobs page, on its own site or its job board, or null."
          },
          "pricing": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The company's pricing page on its own site, or null."
          },
          "contact": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The company's contact or support page on its own site, or null."
          },
          "blog": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The company's blog or news page on its own site, or null."
          },
          "docs": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The company's documentation or developer page on its own site, or null."
          },
          "privacy": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The company's privacy policy on its own site, or null."
          },
          "terms": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ],
            "description": "The company's terms of service on its own site, or null."
          }
        },
        "required": [
          "website",
          "twitter",
          "linkedin",
          "github",
          "youtube",
          "instagram",
          "facebook",
          "tiktok",
          "crunchbase",
          "careers",
          "pricing",
          "contact",
          "blog",
          "docs",
          "privacy",
          "terms"
        ],
        "description": "The brand's website, social profiles and main site pages. Every key is always present; a link the page does not have is null. Each social profile is the first link on the page to that network, usually the brand's own; website is always the fetched URL."
      },
      "Company": {
        "type": "object",
        "properties": {
          "tagline": {
            "description": "The company's short slogan, from its structured data or its page title, or null. Null in every profile today; we fill it once it passes our accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          },
          "legalName": {
            "description": "The company's registered name, from its structured data or its footer copyright line, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "description": "A role contact address the company publishes, such as its support or sales address, or null. A person's own address is never returned.",
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "description": "The phone number in the company's structured data, as the page writes it, or null. Null in every profile today; we fill it once it passes our accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CompanyAddress"
              },
              {
                "type": "null"
              }
            ],
            "description": "The postal address in the company's structured data, or null."
          },
          "foundedYear": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991
              },
              {
                "type": "null"
              }
            ],
            "description": "The year the company was founded, from its structured data, or null."
          }
        },
        "required": [
          "tagline",
          "legalName",
          "email",
          "phone",
          "address",
          "foundedYear"
        ],
        "description": "Facts about the company that its homepage publishes: tagline, legal name, contact details, address and founding year. Each is null when the page does not say. Tagline and phone are null in every profile today; we fill them once they pass our accuracy checks."
      },
      "CompanyAddress": {
        "type": "object",
        "properties": {
          "street": {
            "description": "The street address, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "locality": {
            "description": "The city or town, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "description": "The state, province or region, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "postalCode": {
            "description": "The postal or ZIP code, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "description": "The country, as the page writes it, or null.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "street",
          "locality",
          "region",
          "postalCode",
          "country"
        ],
        "description": "The company's postal address, as its structured data writes it."
      },
      "Theme": {
        "type": "object",
        "properties": {
          "fonts": {
            "description": "The heading and body font stacks.",
            "$ref": "#/components/schemas/ThemeFonts"
          },
          "radius": {
            "description": "The base corner radius as a CSS length, such as 8px, or null. Null in every profile today; we fill it once it passes our accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          },
          "shadow": {
            "description": "The most common box-shadow value on cards, inputs and buttons, or null. Null in every profile today; we fill it once it passes our accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          },
          "button": {
            "description": "The site's main button style.",
            "$ref": "#/components/schemas/ThemeButton"
          },
          "css": {
            "description": "CSS custom properties for the brand colors from colors.roles, or null when no color role was found. Font, radius, shadow and button tokens are added when they pass the same accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "fonts",
          "radius",
          "shadow",
          "button",
          "css"
        ],
        "description": "Design tokens from the site's CSS, and a ready-to-paste CSS block. Today the block holds the brand colors from colors.roles, and every token is null; we fill each token once it passes our accuracy checks."
      },
      "ThemeFonts": {
        "type": "object",
        "properties": {
          "heading": {
            "description": "The heading typeface as a CSS font-family stack, with its fallback, or null. Null in every profile today; we fill it once it passes our accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          },
          "body": {
            "description": "The body typeface as a CSS font-family stack, with its fallback, or null. Null in every profile today; we fill it once it passes our accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "heading",
          "body"
        ],
        "description": "The heading and body font stacks, built from typography.fonts. Both are null in every profile today; we fill them once they pass our accuracy checks."
      },
      "ThemeButton": {
        "type": "object",
        "properties": {
          "background": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The button's background color, or null. Null in every profile today; we fill it once it passes our accuracy checks."
          },
          "text": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The button's text color, or null. Null in every profile today; we fill it once it passes our accuracy checks."
          },
          "border": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The button's border color, or null. Null in every profile today; we fill it once it passes our accuracy checks."
          },
          "radius": {
            "description": "The button's corner radius as a CSS length, such as 9999px for a pill, or null. Null in every profile today; we fill it once it passes our accuracy checks.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "background",
          "text",
          "border",
          "radius"
        ],
        "description": "The site's main button style. Each value is null in every profile today; we fill them once they pass our accuracy checks."
      },
      "Meta": {
        "type": "object",
        "properties": {
          "title": {
            "description": "The page title, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "language": {
            "description": "The language tag the page declares, such as en, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "themeColor": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The page's theme-color meta tag, else the manifest's theme color, or null."
          },
          "manifest": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ManifestMeta"
              },
              {
                "type": "null"
              }
            ],
            "description": "The web app manifest, or null when the site has none or its manifest declares no name and no colors."
          },
          "schemaOrg": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SchemaOrgMeta"
              },
              {
                "type": "null"
              }
            ],
            "description": "The page's first top-level schema.org block (see SchemaOrgMeta), or null when it has none. Check type before treating it as the organization."
          }
        },
        "required": [
          "title",
          "language",
          "themeColor",
          "manifest",
          "schemaOrg"
        ],
        "description": "What the page says about itself."
      },
      "ManifestMeta": {
        "type": "object",
        "properties": {
          "name": {
            "description": "The manifest's name, or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "themeColor": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The manifest's theme color, or null."
          },
          "backgroundColor": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HexColor"
              },
              {
                "type": "null"
              }
            ],
            "description": "The manifest's background color, or null."
          }
        },
        "required": [
          "name",
          "themeColor",
          "backgroundColor"
        ],
        "description": "What the site's web app manifest declares."
      },
      "SchemaOrgMeta": {
        "type": "object",
        "properties": {
          "type": {
            "description": "The block's @type as the site wrote it (the first, when it lists several), or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "description": "The block's name, or null.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "type",
          "name"
        ],
        "description": "The first top-level schema.org JSON-LD block on the page with a @type or a name. It can be any type, such as WebSite; blocks inside @graph are not read."
      },
      "Quality": {
        "type": "object",
        "properties": {
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "How complete the profile is, from 0 to 100."
          },
          "coverage": {
            "description": "Which parts of the profile found anything.",
            "$ref": "#/components/schemas/Coverage"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Machine-readable notes, such as no-logo-found. New values appear over time."
          }
        },
        "required": [
          "score",
          "coverage",
          "warnings"
        ],
        "description": "How much this fetch found. A thin result is still a 200 with a low score, so apply your own bar."
      },
      "Coverage": {
        "type": "object",
        "properties": {
          "logo": {
            "type": "boolean",
            "description": "True when a real logo was found, not only a favicon-grade image. A vector icon 128 pixels or more across counts as a real logo."
          },
          "colors": {
            "type": "boolean",
            "description": "True when at least one color was found."
          },
          "fonts": {
            "type": "boolean",
            "description": "True when at least one typeface was found."
          },
          "links": {
            "type": "boolean",
            "description": "True when at least one social profile was found."
          }
        },
        "required": [
          "logo",
          "colors",
          "fonts",
          "links"
        ],
        "description": "Whether each part of the profile found anything."
      },
      "ColorScheme": {
        "type": "string",
        "enum": [
          "light",
          "dark",
          "both"
        ],
        "description": "The color schemes the page declares support for, from its color-scheme meta tag and a dark theme-color: light, dark or both. light when it declares none."
      },
      "HexColor": {
        "type": "string",
        "pattern": "^#[0-9a-f]{6}$",
        "description": "A color as lowercase #rrggbb hex."
      },
      "Timestamp": {
        "type": "string",
        "format": "date-time",
        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$",
        "description": "A time in ISO 8601, in UTC, ending in Z."
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "A URL that documents this code."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "A short summary of the code, the same every time."
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599,
            "description": "The HTTP status."
          },
          "code": {
            "description": "What went wrong. Branch on this, not on the status.",
            "$ref": "#/components/schemas/ProblemCode"
          },
          "detail": {
            "type": "string",
            "description": "What happened this time, in words. Not for branching on."
          },
          "fetchId": {
            "type": "string",
            "minLength": 1,
            "description": "The fetch's id, when a fetch was attempted."
          },
          "brand": {
            "description": "On site_blocked only: a partial profile built from what survived the block, when there was one. It carries no logos or images.",
            "$ref": "#/components/schemas/Brand"
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code",
          "detail"
        ],
        "description": "An RFC 9457 problem document, the body of every error."
      },
      "ProblemCode": {
        "type": "string",
        "enum": [
          "invalid_url",
          "unauthorized",
          "quota_exceeded",
          "forbidden_domain",
          "domain_unresolvable",
          "site_blocked",
          "rate_limited",
          "fetch_timeout",
          "internal_error"
        ],
        "description": "What went wrong. Each code has one HTTP status; branch on the code."
      }
    }
  }
}
