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

# Campaign creative daily metrics

> One row per day and current Meta ad creative: `spend_media`,
`impressions`, `followers`, and `cpf`. `spend_media` excludes fees.
`cpf` is `spend_media / followers` for that row, and null when
followers is zero. Across days, divide summed spend by summed
followers.

Separate from the lifetime creatives endpoint, which groups by
background video and rejects dates. Each ad is counted once, from its
latest smartlink row.

`startDate` and `endDate` are optional and inclusive. Omit both for
every day that has rows. Ordered by date, then creative id.

Requires the `metrics:read` scope. Accepts API key or OAuth Bearer.




## OpenAPI

````yaml /openapi/soundlink-public-api-v1.yaml get /v1/campaigns/{campaignId}/metrics/creative-daily
openapi: 3.0.3
info:
  title: Soundlink Public API
  version: 0.0.1-draft
  description: >
    Campaign listing, metrics, and write operations for Soundlink partner
    organizations.


    **Base URL:** `https://api.getsoundlink.com`


    ## Authentication


    Send `Authorization: Bearer` with one of:


    1. **API key (recommended)** — a `sk_*` key from the Soundlink app
       (Settings → Developer → API keys):
       ```
       Authorization: Bearer sk_abc123_<token>
       ```

    2. **OAuth Bearer** — an access token from Sign in with Soundlink
       (authorization code or client credentials). Token scopes use the
       same strings as Public API key scopes (for example `campaigns:read`,
       `metrics:read`):
       ```
       Authorization: Bearer <oauth_access_token>
       ```

    `x-api-key` is no longer accepted and is ignored if sent. Requests

    without `Authorization: Bearer` return `401 invalid_api_key` (or

    `401 invalid_token` when a Bearer value is present but neither a

    recognized `sk_*` key nor a valid OAuth access token).


    ### Which operations accept OAuth?


    | Operations | Required scope | Auth |

    | --- | --- | --- |

    | `GET /v1/ping` | any granted Public API scope | API key (Bearer) or OAuth
    Bearer |

    | Campaign reads (`GET /v1/strategies`, `GET /v1/campaigns`, campaign
    detail, tiers) | `campaigns:read` | API key (Bearer) or OAuth Bearer |

    | Metrics reads (overview, breakdown, exports, campaign listening insights,
    campaign retention) | `metrics:read` | API key (Bearer) or OAuth Bearer |

    | Campaign writes (create, stop, budget, tier updates) | `campaigns:write` |
    API key (Bearer) or OAuth Bearer |

    | Video import / import status | `videos:write` | API key (Bearer) or OAuth
    Bearer |

    | Soundlink reads (list, detail, metrics
    overview/breakdown/engagement/retention, listening insights, JSONL exports)
    | `soundlinks:read` | API key (Bearer) or OAuth Bearer |

    | Soundlink writes (create, archive, test events) | `soundlinks:write` | API
    key (Bearer) or OAuth Bearer |

    | Wallet read (`GET /v1/wallet`) | `wallet:read` | API key (Bearer) or OAuth
    Bearer |


    Per-operation scope requirements are also marked with `x-required-scope`

    (except `GET /v1/ping`, which accepts any valid credential with at least

    one Public API scope granted to the key/token).


    All responses are wrapped in a standard envelope:

    ```json

    { "data": <payload>, "meta": { "requestId": "<uuid>" } }

    ```


    Errors follow the same envelope shape with an `error` field instead of
    `data`.
servers:
  - url: https://api.getsoundlink.com
    description: Production
security:
  - apiKeyBearerAuth: []
  - oauthBearer: []
tags:
  - name: System
    description: Connectivity and auth verification
  - name: Wallet
    description: Organization wallet balance
  - name: Campaigns
    description: >-
      Campaign listing, detail, creation, and wallet management (budget, stop,
      tiers)
  - name: Metrics
    description: Campaign performance metrics
  - name: Videos
    description: Partner video library import for Full Control campaigns
  - name: Soundlinks
    description: Soundlink listing, detail, creation, archive, and performance metrics
paths:
  /v1/campaigns/{campaignId}/metrics/creative-daily:
    get:
      tags:
        - Metrics
      summary: Campaign creative daily metrics
      description: |
        One row per day and current Meta ad creative: `spend_media`,
        `impressions`, `followers`, and `cpf`. `spend_media` excludes fees.
        `cpf` is `spend_media / followers` for that row, and null when
        followers is zero. Across days, divide summed spend by summed
        followers.

        Separate from the lifetime creatives endpoint, which groups by
        background video and rejects dates. Each ad is counted once, from its
        latest smartlink row.

        `startDate` and `endDate` are optional and inclusive. Omit both for
        every day that has rows. Ordered by date, then creative id.

        Requires the `metrics:read` scope. Accepts API key or OAuth Bearer.
      operationId: getCampaignCreativeDailyMetrics
      parameters:
        - $ref: '#/components/parameters/campaignId'
        - name: startDate
          in: query
          schema:
            type: string
            format: date
          description: >-
            Inclusive start date (`YYYY-MM-DD`). Omit to include every day from
            the first row.
        - name: endDate
          in: query
          schema:
            type: string
            format: date
          description: >-
            Inclusive end date (`YYYY-MM-DD`). Omit to include every day through
            the latest row.
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/pageSize500'
      responses:
        '200':
          description: Daily creative rows for the campaign
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreativeDailyMetricsResponse'
              example:
                data:
                  items:
                    - date: '2026-03-01'
                      meta_ad_creative_id: '1234567890'
                      spend_media: 40
                      impressions: 400
                      followers: 4
                      cpf: 10
                    - date: '2026-03-02'
                      meta_ad_creative_id: '1234567890'
                      spend_media: 10.5
                      impressions: 100
                      followers: 0
                      cpf: null
                  pagination:
                    page: 1
                    pageSize: 50
                    totalCount: 2
                    totalPages: 1
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - apiKeyBearerAuth: []
        - oauthBearer: []
components:
  parameters:
    campaignId:
      name: campaignId
      in: path
      required: true
      schema:
        type: string
      description: Campaign identifier (UUID)
    page:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1
      description: Page number (1-indexed)
    pageSize500:
      name: pageSize
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 500
        default: 50
      description: Rows per page (max 500; higher default than list endpoints)
  schemas:
    CreativeDailyMetricsResponse:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          $ref: '#/components/schemas/CreativeDailyMetrics'
        meta:
          $ref: '#/components/schemas/Meta'
    CreativeDailyMetrics:
      type: object
      required:
        - items
        - pagination
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/CreativeDailyMetricsRow'
        pagination:
          $ref: '#/components/schemas/Pagination'
    Meta:
      type: object
      required:
        - requestId
      properties:
        requestId:
          type: string
          format: uuid
          description: Server-generated request ID. Include when contacting support.
    ErrorResponse:
      type: object
      required:
        - error
        - meta
      properties:
        error:
          $ref: '#/components/schemas/Error'
        meta:
          $ref: '#/components/schemas/Meta'
    CreativeDailyMetricsRow:
      type: object
      required:
        - date
        - meta_ad_creative_id
        - spend_media
        - impressions
        - followers
        - cpf
      properties:
        date:
          type: string
          format: date
          description: UTC calendar date (`YYYY-MM-DD`).
        meta_ad_creative_id:
          type: string
          description: >-
            Current Meta ad creative. Ads that share this id are summed for the
            day.
        spend_media:
          type: number
          description: Meta media spend for the day. Fees are not included.
        impressions:
          type: number
          description: Meta impressions for the day.
        followers:
          type: number
          description: Follows attributed for the day.
        cpf:
          type: number
          nullable: true
          description: >-
            Cost per follower (`spend_media / followers`) for this row. Null
            when followers is zero.
    Pagination:
      type: object
      required:
        - page
        - pageSize
        - totalCount
        - totalPages
      properties:
        page:
          type: integer
        pageSize:
          type: integer
        totalCount:
          type: integer
        totalPages:
          type: integer
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Stable snake_case error code.
          enum:
            - invalid_api_key
            - api_key_revoked
            - api_key_expired
            - insufficient_scope
            - not_found
            - not_in_listening_graph
            - campaign_not_found
            - invalid_query_parameter
            - invalid_date_range
            - page_size_exceeded
            - invalid_request
            - invalid_genre
            - invalid_duration_or_budget
            - invalid_daily_budget
            - invalid_duration_days
            - invalid_spotify_url
            - invalid_tier_budget_allocation
            - invalid_tier_status
            - tier_update_cooldown
            - wallet_not_enabled
            - insufficient_credit
            - idempotency_key_conflict
            - rate_limit_exceeded
            - invalid_video_url
            - video_import_limit_exceeded
            - video_import_session_not_found
            - internal_error
        message:
          type: string
          description: Human-readable error description. Do not parse programmatically.
        details:
          type: object
          nullable: true
          description: |
            Additive, error-code-specific context (e.g. `available`/`required`
            on `insufficient_credit`). Absent or `null` for error codes that
            carry no extra data.
          additionalProperties: true
  responses:
    BadRequest:
      description: Invalid query parameter or date range
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            invalid_query_parameter:
              value:
                error:
                  code: invalid_query_parameter
                  message: pageSize must be an integer between 1 and 500.
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
            invalid_date_range:
              value:
                error:
                  code: invalid_date_range
                  message: endDate must not be before startDate.
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
    Unauthorized:
      description: |
        Missing or invalid credentials. Covers missing/malformed API keys,
        invalid or expired OAuth access tokens, and revoked API keys.
        `x-api-key` is not accepted and is ignored if sent.
      headers:
        Retry-After:
          schema:
            type: integer
          description: Present only on `rate_limit_exceeded`
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            invalid_api_key:
              value:
                error:
                  code: invalid_api_key
                  message: 'Missing credentials. Send Authorization: Bearer.'
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
            invalid_token:
              value:
                error:
                  code: invalid_token
                  message: OAuth access token is invalid or expired.
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
            api_key_revoked:
              value:
                error:
                  code: api_key_revoked
                  message: >-
                    This API key has been revoked. Create a new key in Settings
                    → Developer → API keys.
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
    Forbidden:
      description: |
        Authenticated but not allowed: missing required scope, or OAuth access
        disabled for the organization (`access_denied`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            insufficient_scope:
              value:
                error:
                  code: insufficient_scope
                  message: This token does not have the metrics:read scope.
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
            access_denied:
              value:
                error:
                  code: access_denied
                  message: OAuth access is not enabled for this organization.
                meta:
                  requestId: 550e8400-e29b-41d4-a716-446655440000
    NotFound:
      description: Campaign not found or belongs to another organization
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: campaign_not_found
              message: Campaign not found.
            meta:
              requestId: 550e8400-e29b-41d4-a716-446655440000
    RateLimited:
      description: Per-key rate limit exceeded (60/min, 600/hr)
      headers:
        Retry-After:
          required: true
          schema:
            type: integer
          description: Seconds until the rate limit resets
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: rate_limit_exceeded
              message: >-
                Rate limit exceeded. Retry after the number of seconds indicated
                in the Retry-After header.
            meta:
              requestId: 550e8400-e29b-41d4-a716-446655440000
    InternalError:
      description: Unexpected server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: internal_error
              message: >-
                An unexpected error occurred. Contact support with the
                requestId.
            meta:
              requestId: 550e8400-e29b-41d4-a716-446655440000
  securitySchemes:
    apiKeyBearerAuth:
      type: http
      scheme: bearer
      description: |
        Pass your Soundlink `sk_*` API key as a Bearer token:
        `Authorization: Bearer sk_<prefix>_<token>` (not an OAuth token; see
        `oauthBearer` for that). Accepted on all Public API operations. Send
        only one `Authorization` header per request.
    oauthBearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        OAuth 2.0 access token from Sign in with Soundlink
        (`Authorization: Bearer <oauth_access_token>`).
        Token scopes must include the operation's required scope
        (see `x-required-scope` and the Authentication section).
        Accepted on all Public API operations (reads and writes).

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.