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

# Get a brand

> Brand detail.

Competitors (own brands only), scan freshness, and the next date a scheduled scan is due (`null` for tiers with no cadence, on-demand or non-customer organisations, competitor rows, archived brands, and an organisation whose first scan has not completed yet).



## OpenAPI

````yaml /api-reference/openapi.json get /orgs/{orgId}/brands/{brandId}
openapi: 3.1.0
info:
  title: Surfais API
  version: 1.0.0
  description: >-
    The Surfais API gives programmatic access to the AI-visibility data Surfais
    measures for your brands: organisations, brands and competitors, tracked
    prompts, per-run results and mentions, scores, share of voice and cited
    sources. It can also provision brands, manage prompts and competitors,
    request on-demand scans, and deliver signed webhooks when a scan completes
    or a score or sentiment threshold is crossed.


    Base URL: `https://api.surfais.com/v1`. Send your API key as a Bearer token
    (`Authorization: Bearer sfs_live_…`). Test keys (`sfs_test_…`) are rejected
    by the production API. Requests and responses are JSON: a success is `{
    "data": … }`, an error is `{ "error": { "code", "message" }, "request_id"
    }`.


    Guides for authentication, pagination, errors, rate limits, idempotency and
    webhooks are at https://docs.surfais.com/api/introduction.
  contact:
    name: Surfais support
    email: support@surfais.com
    url: https://docs.surfais.com/api/support
servers:
  - url: https://api.surfais.com/v1
    description: >-
      Production (the `/v1` prefix is part of the server URL; paths below are
      relative to it).
security:
  - bearerKey: []
tags:
  - name: orgs
    description: Organisations reachable by the key, their usage, and the partner link.
  - name: brands
    description: Own brands (properties) and competitor rows.
  - name: prompts
    description: 'Tracked prompts: reads, CRUD and the declarative sync.'
  - name: results
    description: Finalised run-level data.
  - name: scores
    description: Persisted scores, per-market history and share of voice.
  - name: sources
    description: Cited domains.
  - name: scans
    description: On-demand scan requests.
  - name: webhooks
    description: >-
      Outbound event delivery: endpoints, subscriptions, deliveries (partner
      keys).
externalDocs:
  description: Guides, concepts and webhooks
  url: https://docs.surfais.com/api/introduction
paths:
  /orgs/{orgId}/brands/{brandId}:
    get:
      tags:
        - brands
      summary: Get a brand
      description: >-
        Brand detail.


        Competitors (own brands only), scan freshness, and the next date a
        scheduled scan is due (`null` for tiers with no cadence, on-demand or
        non-customer organisations, competitor rows, archived brands, and an
        organisation whose first scan has not completed yet).
      operationId: getBrand
      parameters:
        - in: path
          name: orgId
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: >-
              Organisation id. Org keys: the key's own org. Partner keys: any
              org with an active link. Anything else is 404.
          required: true
          description: >-
            Organisation id. Org keys: the key's own org. Partner keys: any org
            with an active link. Anything else is 404.
        - in: path
          name: brandId
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: >-
              Brand id within the org (own brand or competitor row); 404 when
              not in the org. Writes that add tracking need an own (400
              `validation_error` with `details[].code = "own_brand_only"`),
              non-archived (409 `brand_archived`) brand.
          required: true
          description: >-
            Brand id within the org (own brand or competitor row); 404 when not
            in the org. Writes that add tracking need an own (400
            `validation_error` with `details[].code = "own_brand_only"`),
            non-archived (409 `brand_archived`) brand.
      responses:
        '200':
          description: The brand.
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            X-RateLimit-Limit:
              required: true
              description: >-
                Requests allowed per minute for this key. On a 429
                `rate_limited` from the failed-authentication gate: failed
                attempts allowed per minute for the client address.
              schema:
                type: string
                description: >-
                  Requests allowed per minute for this key. On a 429
                  `rate_limited` from the failed-authentication gate: failed
                  attempts allowed per minute for the client address.
            X-RateLimit-Remaining:
              required: true
              description: >-
                Requests left in the current minute window (0 on the
                failed-authentication 429).
              schema:
                type: string
                description: >-
                  Requests left in the current minute window (0 on the
                  failed-authentication 429).
            X-RateLimit-Reset:
              required: true
              description: Unix seconds at which the current minute window ends.
              schema:
                type: string
                description: Unix seconds at which the current minute window ends.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/BrandDetail'
                required:
                  - data
        '400':
          description: >-
            `body_not_allowed` — a GET or HEAD that declared a body, refused by
            the intake guard BEFORE the parser, which is the only 400 a read
            operation reaches by that route — or `validation_error` (with
            `details`), `invalid_cursor`, `invalid_json` or `invalid_body`, the
            last two reachable only where a body is accepted at all. All are
            raised after authentication and the minute charge (the body is
            parsed only for an authenticated, admitted request), so every 400
            carries the `X-RateLimit-*` trio and is metered.
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            X-RateLimit-Limit:
              required: true
              description: >-
                Requests allowed per minute for this key. On a 429
                `rate_limited` from the failed-authentication gate: failed
                attempts allowed per minute for the client address.
              schema:
                type: string
                description: >-
                  Requests allowed per minute for this key. On a 429
                  `rate_limited` from the failed-authentication gate: failed
                  attempts allowed per minute for the client address.
            X-RateLimit-Remaining:
              required: true
              description: >-
                Requests left in the current minute window (0 on the
                failed-authentication 429).
              schema:
                type: string
                description: >-
                  Requests left in the current minute window (0 on the
                  failed-authentication 429).
            X-RateLimit-Reset:
              required: true
              description: Unix seconds at which the current minute window ends.
              schema:
                type: string
                description: Unix seconds at which the current minute window ends.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: '`invalid_api_key` — uniform for every authentication failure.'
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: >-
            `tier_not_entitled` — the org key's organisation left an
            API-entitled tier. The request is charged to the key's minute
            allowance (so it carries the `X-RateLimit-*` trio, and an exhausted
            allowance answers 429 first) and is metered.
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            X-RateLimit-Limit:
              required: true
              description: >-
                Requests allowed per minute for this key. On a 429
                `rate_limited` from the failed-authentication gate: failed
                attempts allowed per minute for the client address.
              schema:
                type: string
                description: >-
                  Requests allowed per minute for this key. On a 429
                  `rate_limited` from the failed-authentication gate: failed
                  attempts allowed per minute for the client address.
            X-RateLimit-Remaining:
              required: true
              description: >-
                Requests left in the current minute window (0 on the
                failed-authentication 429).
              schema:
                type: string
                description: >-
                  Requests left in the current minute window (0 on the
                  failed-authentication 429).
            X-RateLimit-Reset:
              required: true
              description: Unix seconds at which the current minute window ends.
              schema:
                type: string
                description: Unix seconds at which the current minute window ends.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '404':
          description: >-
            `not_found` — the org is not reachable by this key or a nested id is
            not in it. Raised after authentication and the minute charge, so it
            carries the `X-RateLimit-*` trio and is metered.
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            X-RateLimit-Limit:
              required: true
              description: >-
                Requests allowed per minute for this key. On a 429
                `rate_limited` from the failed-authentication gate: failed
                attempts allowed per minute for the client address.
              schema:
                type: string
                description: >-
                  Requests allowed per minute for this key. On a 429
                  `rate_limited` from the failed-authentication gate: failed
                  attempts allowed per minute for the client address.
            X-RateLimit-Remaining:
              required: true
              description: >-
                Requests left in the current minute window (0 on the
                failed-authentication 429).
              schema:
                type: string
                description: >-
                  Requests left in the current minute window (0 on the
                  failed-authentication 429).
            X-RateLimit-Reset:
              required: true
              description: Unix seconds at which the current minute window ends.
              schema:
                type: string
                description: Unix seconds at which the current minute window ends.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '413':
          description: >-
            `payload_too_large` — a JSON body over 1 MB. The body is parsed only
            for an authenticated, admitted request, so this carries the
            `X-RateLimit-*` trio and is metered.
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            X-RateLimit-Limit:
              required: true
              description: >-
                Requests allowed per minute for this key. On a 429
                `rate_limited` from the failed-authentication gate: failed
                attempts allowed per minute for the client address.
              schema:
                type: string
                description: >-
                  Requests allowed per minute for this key. On a 429
                  `rate_limited` from the failed-authentication gate: failed
                  attempts allowed per minute for the client address.
            X-RateLimit-Remaining:
              required: true
              description: >-
                Requests left in the current minute window (0 on the
                failed-authentication 429).
              schema:
                type: string
                description: >-
                  Requests left in the current minute window (0 on the
                  failed-authentication 429).
            X-RateLimit-Reset:
              required: true
              description: Unix seconds at which the current minute window ends.
              schema:
                type: string
                description: Unix seconds at which the current minute window ends.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: >-
            `rate_limited` (per-minute limit, or too many failed authentications
            from this address) or `quota_exceeded`.
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            Retry-After:
              required: true
              description: Seconds to wait before retrying — present on every 429 and 503.
              schema:
                type: string
                description: >-
                  Seconds to wait before retrying — present on every 429 and
                  503.
            X-RateLimit-Limit:
              required: true
              description: >-
                Requests allowed per minute for this key. On a 429
                `rate_limited` from the failed-authentication gate: failed
                attempts allowed per minute for the client address.
              schema:
                type: string
                description: >-
                  Requests allowed per minute for this key. On a 429
                  `rate_limited` from the failed-authentication gate: failed
                  attempts allowed per minute for the client address.
            X-RateLimit-Remaining:
              required: true
              description: >-
                Requests left in the current minute window (0 on the
                failed-authentication 429).
              schema:
                type: string
                description: >-
                  Requests left in the current minute window (0 on the
                  failed-authentication 429).
            X-RateLimit-Reset:
              required: true
              description: Unix seconds at which the current minute window ends.
              schema:
                type: string
                description: Unix seconds at which the current minute window ends.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '500':
          description: >-
            `internal_error` — quote `request_id`. A failure inside a route
            answers after the minute charge and carries the `X-RateLimit-*`
            trio; a failure before the limiter carries only `X-Request-Id`.
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            X-RateLimit-Limit:
              description: >-
                Present when the failure occurred after the minute charge
                (inside a route); absent on a failure before the limiter.
                Requests allowed per minute for this key.
              schema:
                description: >-
                  Present when the failure occurred after the minute charge
                  (inside a route); absent on a failure before the limiter.
                  Requests allowed per minute for this key.
                type: string
            X-RateLimit-Remaining:
              description: >-
                Present when the failure occurred after the minute charge.
                Requests left in the current minute window.
              schema:
                description: >-
                  Present when the failure occurred after the minute charge.
                  Requests left in the current minute window.
                type: string
            X-RateLimit-Reset:
              description: >-
                Present when the failure occurred after the minute charge. Unix
                seconds at which the current minute window ends.
              schema:
                description: >-
                  Present when the failure occurred after the minute charge.
                  Unix seconds at which the current minute window ends.
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: >-
            `api_unavailable` (switched off; `Retry-After` is 60),
            `rate_limit_unavailable` (fail-closed limiter — its store, or a
            saturated failed-authentication gate; before the minute charge, so
            no `X-RateLimit-*` trio), or `store_unavailable` (a tenant-store
            call behind an authenticated request exceeded 15000 ms — raised
            after the minute charge, so it is counted and carries the trio).
          headers:
            X-Request-Id:
              required: true
              description: >-
                Correlation id for this request; equals `request_id` in an error
                envelope.
              schema:
                type: string
                description: >-
                  Correlation id for this request; equals `request_id` in an
                  error envelope.
            Retry-After:
              required: true
              description: Seconds to wait before retrying — present on every 429 and 503.
              schema:
                type: string
                description: >-
                  Seconds to wait before retrying — present on every 429 and
                  503.
            X-RateLimit-Limit:
              description: >-
                Present when the failure occurred after the minute charge
                (inside a route); absent on a failure before the limiter.
                Requests allowed per minute for this key.
              schema:
                description: >-
                  Present when the failure occurred after the minute charge
                  (inside a route); absent on a failure before the limiter.
                  Requests allowed per minute for this key.
                type: string
            X-RateLimit-Remaining:
              description: >-
                Present when the failure occurred after the minute charge.
                Requests left in the current minute window.
              schema:
                description: >-
                  Present when the failure occurred after the minute charge.
                  Requests left in the current minute window.
                type: string
            X-RateLimit-Reset:
              description: >-
                Present when the failure occurred after the minute charge. Unix
                seconds at which the current minute window ends.
              schema:
                description: >-
                  Present when the failure occurred after the minute charge.
                  Unix seconds at which the current minute window ends.
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
components:
  schemas:
    BrandDetail:
      type: object
      properties:
        id:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          description: UUID.
        name:
          type: string
        domain:
          type: string
        is_own:
          type: boolean
          description: true = a property you track; false = a competitor row.
        external_ref:
          anyOf:
            - type: string
            - type: 'null'
          description: Your own id for the property (brands.external_ref).
        geography:
          anyOf:
            - type: string
            - type: 'null'
          description: Primary-market hint (free text, alpha-2 when set by the UI).
        sunset_at:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Set when the brand has been archived; archived brands are omitted
            from lists.
        created_at:
          type: string
          description: RFC 3339 timestamp.
          format: date-time
        updated_at:
          type: string
          description: RFC 3339 timestamp.
          format: date-time
        competitors:
          type: array
          items:
            $ref: '#/components/schemas/CompetitorRef'
          description: Empty for competitor rows.
        last_scan_at:
          anyOf:
            - type: string
              description: RFC 3339 timestamp.
              format: date-time
            - type: 'null'
          description: >-
            When the latest COMPLETED, non-preview run for this brand finalised.
            A preview run, or a run later demoted from completed, is never this
            value. Null until the first such run finalises.
        last_scan_changed_at:
          anyOf:
            - type: string
              description: RFC 3339 timestamp.
              format: date-time
            - type: 'null'
          description: >-
            A change token that moves on finalisation, completion flips,
            deletions, budget aborts, any update of the brand row itself, a
            linked competitor's name or domain change, and a change to this
            org's scheduling inputs. Poll this for 'anything changed' among the
            STORED fields, not last_scan_at. It does NOT cover
            next_scheduled_scan, which is derived from the clock as well — see
            that field.
        next_scheduled_scan:
          anyOf:
            - type: string
              pattern: ^\d{4}-\d{2}-\d{2}$
              description: Calendar date, `YYYY-MM-DD` (UTC).
              format: date
            - type: 'null'
          description: >-
            UTC date the next scheduled scan is due for this organisation's plan
            (Mon+Thu for paid tiers below Enterprise, daily for Enterprise).
            Null for tiers with no cadence, on-demand orgs, non-customer orgs,
            competitor rows, archived brands — and for an org that has not yet
            completed its first (activation) scan, which is not scheduled.
            COMPUTED AT REQUEST TIME and NOT covered by last_scan_changed_at: it
            is derived from the org's scheduling inputs AND the clock, so on a
            cadence day it rolls to the next date as the dispatch hour passes,
            with no write anywhere for a token to version. Read it as an as-of
            value with the response rather than caching it until the token
            moves, and treat it as a plan — a cadence scan can be delayed or
            fail.
      required:
        - id
        - name
        - domain
        - is_own
        - external_ref
        - geography
        - sunset_at
        - created_at
        - updated_at
        - competitors
        - last_scan_at
        - last_scan_changed_at
        - next_scheduled_scan
    ErrorEnvelope:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Stable machine code — see the error list in the description.
            message:
              type: string
            details: {}
          required:
            - code
            - message
        request_id:
          type: string
          description: Echoed in the `X-Request-Id` header.
      required:
        - error
        - request_id
    CompetitorRef:
      type: object
      properties:
        id:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          description: UUID.
        name:
          type: string
        domain:
          type: string
      required:
        - id
        - name
        - domain
  securitySchemes:
    bearerKey:
      type: http
      scheme: bearer
      bearerFormat: sfs_live_… / sfs_test_…
      description: >-
        A Surfais API key — an organisation key or a partner key. Issued by
        Surfais; shown once. Rotate by creating a new key, then revoking the old
        one.

````