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

# Rank assets

> Score and rank a batch of ad creative assets against one audience.



## OpenAPI

````yaml openapi/rank-api.json POST /api/v1/rank
openapi: 3.1.0
info:
  title: Kettio Rank API
  version: 1.1.0
  description: >-
    Score and rank batches of ad creative assets with Kettio's SSR pipeline,
    then validate selected matchups with a five-voter Haiku Bradley-Terry panel.
servers:
  - url: https://kettio.com
    description: Production
security:
  - bearerAuth: []
paths:
  /api/v1/rank:
    post:
      summary: Rank ad creative assets
      description: >-
        Ranks 1 to 20 image assets against an inline or saved audience. Assets
        with copy_context are scored as the full ad package and also receive an
        image-only ablation for copy lift.
      operationId: rankAssets
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RankRequest'
            examples:
              imageOnlyBatch:
                summary: Image-only batch rank
                value:
                  assets:
                    - url: https://cdn.example.com/ad-a.png
                      id: ad-a
                    - url: https://cdn.example.com/ad-b.png
                      id: ad-b
                  audience:
                    name: Budget-conscious parents
                    description: Parents aged 30-44 who compare prices before buying
                    demographics:
                      ageRange: 35-44
                      priceSensitivity: high
                      shoppingIntent: comparing
                  goal: purchase-intent
                  platform: meta
              fullAdPackage:
                summary: Full ad package with copy context
                value:
                  assets:
                    - url: https://cdn.example.com/ad-a.png
                      id: ad-a
                      asset_type: Advertisement
                      copy_context:
                        pageName: Pawbox
                        adBody: >-
                          First box free for new subscribers. Fresh treats
                          picked for picky dogs.
                        adHeadline: Healthy treats your dog will actually want
                        adCaption: Cancel anytime
                  audience:
                    name: Millennial pet owners
                    description: Dog owners aged 25-34, mid-income, active on Instagram
                  goal: purchase-intent
                  campaign_type: meta-feed
                  refine_close_pairs: true
      responses:
        '200':
          description: Ranked assets and any per-asset errors.
          headers:
            X-Request-Id:
              schema:
                type: string
                format: uuid
            X-RateLimit-Remaining:
              schema:
                type: string
              description: Remaining scoring evaluations in the current rate-limit window.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RankResponse'
              example:
                request_id: 1f4d884c-f9ef-4f36-a8e9-f7b6a5b63291
                ranked:
                  - rank: 1
                    asset_url: https://cdn.example.com/ad-a.png
                    asset_id: ad-a
                    score: 4.24
                    score_before_refine: 4.23
                    score_layer: full-ad-package
                    asset_type: Advertisement
                    copy_context_included: true
                    image_only_score: 3.81
                    copy_lift: 0.42
                    rationale: >-
                      The creative quickly communicates the offer and the copy
                      removes purchase friction.
                    product_read: >-
                      A product-focused social ad with subscription-box imagery
                      and a clear first-box-free offer.
                    confidence: high
                    panel_outcome: null
                    confidence_details:
                      entropy: 0.38
                      top_margin: 0.35
                      sample_std_dev: 0.06
                      repetition_count: 3
                      generator_sample_count: 6
                    details:
                      probabilities:
                        - 0.02
                        - 0.06
                        - 0.18
                        - 0.46
                        - 0.28
                      similarities:
                        - 0.12
                        - 0.21
                        - 0.35
                        - 0.47
                        - 0.41
                      repetitionCount: 3
                      generatorSampleCount: 6
                      repetitionScores:
                        - 4.18
                        - 4.24
                        - 4.3
                      repetitionScoreRange: 0.12
                errors: []
                summary:
                  goal: purchase-intent
                  asset_type: Social Media Post
                  platform: meta
                  audience: Millennial pet owners
                  assets_ranked: 1
                  assets_failed: 0
                  scoring_evaluations: 2
                  repetitions_per_evaluation: 3
                  generator_samples_per_evaluation: 6
                  close_pair_refinement:
                    enabled: true
                    pairs_evaluated: 0
                    results: []
                  credits_used: 2
                  credits_remaining: 48
        '400':
          $ref: '#/components/responses/Error'
        '401':
          $ref: '#/components/responses/Error'
        '402':
          $ref: '#/components/responses/Error'
        '404':
          $ref: '#/components/responses/Error'
        '422':
          $ref: '#/components/responses/Error'
        '429':
          $ref: '#/components/responses/RateLimitError'
        '500':
          $ref: '#/components/responses/Error'
      security:
        - bearerAuth: []
components:
  schemas:
    RankRequest:
      type: object
      additionalProperties: false
      required:
        - assets
      properties:
        assets:
          type: array
          minItems: 1
          maxItems: 20
          items:
            $ref: '#/components/schemas/AssetInput'
        audience:
          $ref: '#/components/schemas/InlineAudience'
        audience_id:
          type: string
          description: Saved audience ID from the authenticated Kettio account.
        goal:
          type: string
          default: purchase-intent
        asset_type:
          type: string
          default: Social Media Post
          description: >-
            Default asset type for assets that do not provide their own
            asset_type.
        platform:
          type: string
          description: >-
            Optional platform context, for example meta, instagram, facebook,
            tiktok, linkedin, or google.
        campaign_type:
          type: string
          description: >-
            Optional campaign placement/context alias used when platform is
            omitted.
        refine_close_pairs:
          type: boolean
          default: true
          description: >-
            When true, Kettio can run a pairwise panel on near-tied successful
            assets and adjust rank ordering when the panel disagrees.
      oneOf:
        - required:
            - audience
          not:
            required:
              - audience_id
        - required:
            - audience_id
          not:
            required:
              - audience
    RankResponse:
      type: object
      required:
        - request_id
        - ranked
        - errors
        - summary
      properties:
        request_id:
          type: string
          format: uuid
        ranked:
          type: array
          items:
            $ref: '#/components/schemas/RankedAsset'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/RankAssetError'
        summary:
          $ref: '#/components/schemas/RankSummary'
    AssetInput:
      type: object
      additionalProperties: false
      required:
        - url
      properties:
        url:
          type: string
          description: HTTPS image URL or data:image URI.
        id:
          type: string
          description: Optional caller-supplied ID returned as asset_id.
        asset_type:
          type: string
          description: Per-asset override for the request asset_type.
        copy_context:
          $ref: '#/components/schemas/CopyContext'
    InlineAudience:
      type: object
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
        description:
          type: string
        demographics:
          type: object
          additionalProperties: true
          properties:
            ageRange:
              type: string
            incomeLevel:
              type: string
            adSkepticism:
              type: string
            trustBaseline:
              type: string
            priceSensitivity:
              type: string
            categoryFamiliarity:
              type: string
            shoppingIntent:
              type: string
            urgency:
              type: string
            brandFamiliarity:
              type: string
            platformFatigue:
              type: string
    RankedAsset:
      type: object
      required:
        - rank
        - asset_url
        - asset_id
        - score
        - score_before_refine
        - score_layer
        - asset_type
        - copy_context_included
        - image_only_score
        - copy_lift
        - rationale
        - product_read
        - confidence
        - panel_outcome
        - confidence_details
        - details
      properties:
        rank:
          type: integer
          minimum: 1
        asset_url:
          type: string
        asset_id:
          type:
            - string
            - 'null'
        score:
          type: number
          minimum: 1
          maximum: 5
        score_before_refine:
          type: number
          description: SSR score before close-pair refinement adjusted rank ordering.
        score_layer:
          type: string
          enum:
            - image-only
            - copy-only
            - full-ad-package
        asset_type:
          type: string
        copy_context_included:
          type: boolean
        image_only_score:
          type:
            - number
            - 'null'
          description: >-
            Image-only ablation score. For image-only requests this equals
            score.
        copy_lift:
          type:
            - number
            - 'null'
          description: >-
            Full-ad-package score minus image_only_score when copy_context is
            present.
        rationale:
          type: string
        product_read:
          type: string
        confidence:
          type: string
          enum:
            - high
            - medium
            - low
        panel_outcome:
          anyOf:
            - $ref: '#/components/schemas/PanelOutcome'
            - type: 'null'
        confidence_details:
          $ref: '#/components/schemas/ConfidenceDetails'
        details:
          $ref: '#/components/schemas/ScoreDetails'
    RankAssetError:
      type: object
      properties:
        asset_url:
          type: string
        asset_id:
          type:
            - string
            - 'null'
        error:
          type: string
    RankSummary:
      type: object
      properties:
        goal:
          type: string
        asset_type:
          type: string
        platform:
          type:
            - string
            - 'null'
        audience:
          type: string
        assets_ranked:
          type: integer
        assets_failed:
          type: integer
        scoring_evaluations:
          type: integer
          description: >-
            Successful score evaluations billed and counted against rate limits.
            Image-only assets use 1. Assets with copy_context use up to 2.
        repetitions_per_evaluation:
          type: integer
          const: 3
          description: >-
            Independent paired-model repetitions used for every scoring
            evaluation.
        generator_samples_per_evaluation:
          type: integer
          const: 6
          description: >-
            Three Flash samples plus three Haiku samples used for every scoring
            evaluation.
        close_pair_refinement:
          $ref: '#/components/schemas/ClosePairRefinement'
        credits_used:
          type: integer
        credits_remaining:
          type:
            - integer
            - 'null'
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        field:
          type: string
    CopyContext:
      type: object
      additionalProperties: true
      properties:
        pageName:
          type: string
        adBody:
          type: string
        adHeadline:
          type: string
        adCaption:
          type: string
        adDescription:
          type: string
        primaryText:
          type: string
          description: Alias for adBody.
        headline:
          type: string
          description: Alias for adHeadline.
        caption:
          type: string
          description: Alias for adCaption.
        description:
          type: string
          description: Alias for adDescription when used inside copy_context.
      description: >-
        Structured ad copy. When present, the asset is scored as a full ad
        package and Kettio also runs an image-only ablation.
    PanelOutcome:
      type: object
      properties:
        winnerAssetId:
          type: string
        loserAssetId:
          type: string
        flipped:
          type: boolean
        votesFor:
          type: integer
        votesTotal:
          type: integer
        consistency:
          type: number
    ConfidenceDetails:
      type: object
      properties:
        entropy:
          type: number
        top_margin:
          type: number
        sample_std_dev:
          type: number
        repetition_count:
          type: integer
          const: 3
        generator_sample_count:
          type: integer
          const: 6
    ScoreDetails:
      type: object
      properties:
        probabilities:
          type: array
          items:
            type: number
        similarities:
          type: array
          items:
            type: number
        repetitionCount:
          type: integer
          const: 3
        generatorSampleCount:
          type: integer
          const: 6
        repetitionScores:
          type: array
          minItems: 3
          maxItems: 3
          items:
            type: number
        repetitionScoreRange:
          type: number
    ClosePairRefinement:
      type: object
      properties:
        enabled:
          type: boolean
        pairs_evaluated:
          type: integer
        results:
          type: array
          items:
            type: object
            additionalProperties: true
  responses:
    Error:
      description: Error response.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimitError:
      description: Rate limit response.
      headers:
        Retry-After:
          schema:
            type: string
      content:
        application/json:
          schema:
            allOf:
              - $ref: '#/components/schemas/ErrorResponse'
              - type: object
                properties:
                  retryAfter:
                    type: integer
                  resetAt:
                    type: integer
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'Kettio API key, for example Authorization: Bearer agk_live_xxx.'

````