> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spyglass.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Search brands and creators

> Resolve brands by id, by name, or by a natural-language query.
Exactly one shape is valid per mode, and these rules are enforced
by the API but cannot be expressed in JSON Schema, so a generated
client will not catch them for you:
- `mode: "ids"` requires `brandIds`.
- `mode: "brand_name"` requires `brandNames` and `type`.
- `mode: "smart"` requires `query` and `type`, and rejects `sortBy`
  because results are ordered by relevance.

`count` (default 10, max 100) bounds how many rows `brand_name`
and `smart` return, and therefore what the call costs. It is
ignored for `mode: "ids"`, which returns one row per id that
matches a brand. Ids matching nothing are omitted from `brands`
and listed in `unmatchedIds`, which is present only for that mode.

Limited to 60 requests per minute for this endpoint.
Costs 2,500 microdollars ($0.0025) per brand returned, charged against your plan's monthly credits. The count field is what you were charged for.
With `mode: "smart"` the call runs a language model, so it bills a
minimum of one row even when nothing matches. In that case `count`
is 0 but you are charged for one row.



## OpenAPI

````yaml https://app.spyglass.so/api/v1/openapi.json post /brands/search
openapi: 3.1.0
info:
  title: Spyglass API
  version: 1.0.0
  description: |-
    Query Spyglass ad intelligence over HTTP.

    ## Authentication
    Send your key as a bearer token: `Authorization: Bearer sg_live_...`.
    Create and revoke keys in Settings → API. A key is scoped to the
    team it was created for, and stops working if you leave that team.

    ## Billing
    Calls draw on the same monthly credits as the rest of Spyglass. Every
    endpoint charges per row returned. Bound what a call costs with
    `limit` on /brands/{id}/media, /insights and /landing-pages, and with
    `count` on /brands/search. Requests that fail validation, auth, or the
    credit check are never charged.

    Calls that run a language model — /brands/{id}/media in either mode,
    and /brands/search with `mode: "smart"` — are charged a minimum of one
    row even when nothing matches, because the model ran either way.

    ## Rate limits
    Three limits apply: 60 requests per minute per IP address, 120 per
    minute per API key, and a per-endpoint limit listed on each operation.
    Whichever is lowest applies. Exceeding any of them returns 429 with a
    Retry-After header.
servers:
  - url: https://app.spyglass.so/api/v1
security:
  - bearerAuth: []
paths:
  /brands/search:
    post:
      summary: Search brands and creators
      description: >-
        Resolve brands by id, by name, or by a natural-language query.

        Exactly one shape is valid per mode, and these rules are enforced

        by the API but cannot be expressed in JSON Schema, so a generated

        client will not catch them for you:

        - `mode: "ids"` requires `brandIds`.

        - `mode: "brand_name"` requires `brandNames` and `type`.

        - `mode: "smart"` requires `query` and `type`, and rejects `sortBy`
          because results are ordered by relevance.

        `count` (default 10, max 100) bounds how many rows `brand_name`

        and `smart` return, and therefore what the call costs. It is

        ignored for `mode: "ids"`, which returns one row per id that

        matches a brand. Ids matching nothing are omitted from `brands`

        and listed in `unmatchedIds`, which is present only for that mode.


        Limited to 60 requests per minute for this endpoint.

        Costs 2,500 microdollars ($0.0025) per brand returned, charged against
        your plan's monthly credits. The count field is what you were charged
        for.

        With `mode: "smart"` the call runs a language model, so it bills a

        minimum of one row even when nothing matches. In that case `count`

        is 0 but you are charged for one row.
      operationId: searchBrands
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                mode:
                  type: string
                  enum:
                    - ids
                    - brand_name
                    - smart
                brandIds:
                  maxItems: 100
                  type: array
                  items:
                    description: >-
                      Spyglass brand id, either a uuid or a numeric platform id.
                      May be given as a string or a number.
                    anyOf:
                      - type: string
                      - type: number
                brandNames:
                  maxItems: 100
                  type: array
                  items:
                    type: string
                    minLength: 3
                    maxLength: 200
                query:
                  type: string
                  maxLength: 500
                type:
                  type: string
                  enum:
                    - BRAND
                    - CREATOR
                count:
                  type: integer
                  minimum: 1
                  maximum: 100
                minFollowers:
                  type: integer
                  minimum: 0
                  maximum: 2147483647
                maxFollowers:
                  type: integer
                  minimum: 0
                  maximum: 2147483647
                sortBy:
                  type: string
                  enum:
                    - NAME
                    - MOST_FOLLOWERS
                    - LEAST_FOLLOWERS
                    - MOST_VIEWS
                    - HIGHEST_ENGAGEMENT
                    - MOST_ACTIVE_ADS
              required:
                - mode
            example:
              mode: brand_name
              brandNames:
                - Nike
              type: BRAND
              count: 3
      responses:
        '200':
          description: Matching brands.
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  brands:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        summary:
                          anyOf:
                            - type: string
                            - type: 'null'
                        category:
                          anyOf:
                            - type: string
                            - type: 'null'
                        verified:
                          type: boolean
                        pageAlias:
                          anyOf:
                            - type: string
                            - type: 'null'
                        likes:
                          anyOf:
                            - type: number
                            - type: 'null'
                        igUsername:
                          anyOf:
                            - type: string
                            - type: 'null'
                        igFollowers:
                          anyOf:
                            - type: number
                            - type: 'null'
                        igEngagementRate:
                          anyOf:
                            - type: number
                            - type: 'null'
                        tiktokUsername:
                          anyOf:
                            - type: string
                            - type: 'null'
                        tiktokFollowers:
                          anyOf:
                            - type: number
                            - type: 'null'
                        thumbnailUrl:
                          anyOf:
                            - type: string
                            - type: 'null'
                      required:
                        - id
                        - name
                        - summary
                        - category
                        - verified
                        - pageAlias
                        - likes
                        - igUsername
                        - igFollowers
                        - igEngagementRate
                        - tiktokUsername
                        - tiktokFollowers
                        - thumbnailUrl
                  unmatchedIds:
                    type: array
                    items:
                      type: string
                required:
                  - count
                  - brands
        '400':
          $ref: '#/components/responses/InvalidRequest'
        '401':
          $ref: '#/components/responses/InvalidApiKey'
        '402':
          $ref: '#/components/responses/OutOfCredits'
        '403':
          $ref: '#/components/responses/Forbidden'
        '405':
          $ref: '#/components/responses/MethodNotAllowed'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  responses:
    InvalidRequest:
      description: >-
        The request body or query string failed validation. `details` lists the
        offending fields.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InvalidApiKey:
      description: The API key is missing, malformed, unknown, or revoked.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    OutOfCredits:
      description: The team's monthly credits are exhausted.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: The team's subscription is inactive, or your membership of it has ended.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    MethodNotAllowed:
      description: >-
        The HTTP method is not supported on this path. The Allow header lists
        what is. HEAD is refused on metered GET endpoints because it would be
        billed without returning data.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    PayloadTooLarge:
      description: The request body exceeds the 100 KB limit.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: >-
        Too many requests. Carries a Retry-After header. Limits are 60/minute
        per IP, 120/minute per key, plus the per-endpoint limit stated on the
        operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Something went wrong on our side.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - invalid_request
                - invalid_api_key
                - payload_too_large
                - out_of_credits
                - membership_ended
                - subscription_inactive
                - brand_not_found
                - method_not_allowed
                - rate_limited
                - internal_error
            message:
              type: string
            details:
              type: array
              items:
                type: object
                required:
                  - path
                  - message
                properties:
                  path:
                    type: string
                  message:
                    type: string
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An API key from Settings → API, prefixed sg_live_.

````