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

# Get a campaign

> Retrieve a single message campaign by its identifier. Resolves both
newsletters and flow campaigns — no `type` parameter needed. A flow
campaign names the flow that sends it in `flow`; newsletters omit
that field.

A `/v1/campaigns` row already carries this exact shape, so following up
per campaign adds nothing — reach for this when the id came from
somewhere else, such as a flow node's `data.campaign_id` or a report
row's `campaign_id`. Performance is
`/v1/reports/campaigns/{campaign_id}`.

**Required scope:** `campaigns_read`




## OpenAPI

````yaml openapi/privy-api.yaml GET /campaigns/{id}
openapi: 3.1.0
info:
  title: Privy API
  version: '1.0'
  description: >
    The Privy API lets you programmatically manage your contact list and read
    what you have set up in Privy.

    Create, update, unsubscribe, and remove contacts; report orders;

    and read your campaigns, flows, segments, orders, store products, coupon
    pools,

    performance reports, and account setup.
servers:
  - url: https://api.privy.com/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Account
    description: Retrieve information about the authenticated Privy account.
  - name: Contacts
    description: Manage your contact list.
  - name: Imports
    description: >-
      Read your contact import history — CSV uploads, connected-provider syncs,
      and SMS consent imports.
  - name: Campaigns
    description: >-
      Read your message campaigns — email and SMS newsletters, plus the messages
      your flows send.
  - name: Displays
    description: >-
      Read your on-site displays (popups, flyouts, banners, embedded forms,
      landing pages).
  - name: Coupons
    description: Read your coupon pools, their code inventory, and individual codes.
  - name: Reports
    description: >-
      Read performance reporting — signups, views, conversion rates, and
      attributed revenue — for your business, displays, and flows.
  - name: Flows
    description: Read your automation flows and their configuration.
  - name: Segments
    description: Read your customer segments and their membership.
  - name: Orders
    description: Report orders placed in your store and read your order history.
  - name: Products
    description: Read the product catalog and collections of your connected store.
  - name: Events
    description: Ingest custom events to trigger Flows and other automations.
paths:
  /campaigns/{id}:
    get:
      tags:
        - Campaigns
      summary: Get a campaign
      description: |
        Retrieve a single message campaign by its identifier. Resolves both
        newsletters and flow campaigns — no `type` parameter needed. A flow
        campaign names the flow that sends it in `flow`; newsletters omit
        that field.

        A `/v1/campaigns` row already carries this exact shape, so following up
        per campaign adds nothing — reach for this when the id came from
        somewhere else, such as a flow node's `data.campaign_id` or a report
        row's `campaign_id`. Performance is
        `/v1/reports/campaigns/{campaign_id}`.

        **Required scope:** `campaigns_read`
      operationId: getCampaign
      parameters:
        - $ref: '#/components/parameters/AccountIdParam'
        - name: id
          in: path
          required: true
          description: >-
            The campaign's unique identifier (returned as `id` in campaign
            responses). Ids are opaque public strings — a numeric id from a
            Privy dashboard URL is not a valid API id and will 404; list
            campaigns and match by title instead.
          schema:
            type: string
          example: Nw8K2rT5xY
      responses:
        '200':
          description: The message campaign.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Campaign'
              examples:
                ab_test_newsletter:
                  summary: A decided email A/B test
                  value:
                    data:
                      id: Nw8K2rT5xY
                      type: newsletter
                      title: June Restock Announcement
                      channel: email
                      status: sent
                      subject: The restock you asked for is here
                      send_date: '2026-06-18T15:00:00Z'
                      audience:
                        included_segments:
                          - id: aBc1234
                            name: Engaged 90d
                            prebuilt: false
                          - id: potential_customers
                            name: Potential Customers
                            prebuilt: true
                        excluded_segments:
                          - id: dEf5678
                            name: Recent purchasers
                            prebuilt: false
                      coupon: null
                      ab_test:
                        winning_metric: click_rate
                        test_duration_seconds: 86400
                        versions:
                          - id: cpv_dkyYZmk
                            name: Version A
                            is_control: true
                            is_winner: false
                            audience_share: 0.125
                            subject: The restock you asked for is here
                            preheader: Back in stock and going fast
                            coupon: null
                          - id: cpv_YJGOjpJ
                            name: Version B
                            is_control: false
                            is_winner: true
                            audience_share: 0.125
                            subject: Your size is back, but not for long
                            preheader: We saved you a look
                            coupon:
                              id: 7k2dG6Y
                              title: RESTOCK20
                              kind: master
                              platform: manual
                      created_at: '2026-06-10T09:00:00Z'
                      updated_at: '2026-06-18T15:05:00Z'
                flow_campaign:
                  summary: A flow's email
                  value:
                    data:
                      id: Xp4R7mQ2vB
                      type: flow
                      title: Cart reminder email
                      channel: email
                      status: null
                      subject: You left something behind
                      send_date: null
                      audience: null
                      coupon: null
                      ab_test: null
                      created_at: '2026-04-02T15:00:00Z'
                      updated_at: '2026-04-02T15:00:00Z'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/InsufficientScope'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      security:
        - bearerAuth: []
components:
  parameters:
    AccountIdParam:
      name: Privy-Account-Id
      in: header
      required: false
      description: >
        Target a subaccount instead of the main connected account.

        Pass a subaccount `id` from get_account's `subaccounts` list. Only
        direct subaccounts

        of the connected account are reachable — omit this for the main account
        itself.
      schema:
        type: string
      example: S1U2B3A4C5C6T7
  schemas:
    Campaign:
      type: object
      description: >
        A message campaign — configuration only; send statistics belong to the

        reporting surface. `type` discriminates the two families: `newsletter`

        (email + SMS broadcasts) and `flow` (the email/SMS messages a flow
        sends).

        Newsletter-only fields (`status`, `send_date`, `audience`) are `null`

        for flow campaigns — the flow's trigger decides who receives them and
        when.
      properties:
        id:
          type: string
          description: >-
            Stable, unique identifier for the campaign. Use this value in
            `/v1/campaigns/{id}` and `/v1/reports/campaigns/{campaign_id}`.
          example: Nw8K2rT5xY
        type:
          type: string
          enum:
            - newsletter
            - flow
          description: >-
            `newsletter` — a broadcast send; `flow` — a message sent by an
            automation flow.
          example: newsletter
        title:
          type:
            - string
            - 'null'
          example: June Restock Announcement
        channel:
          type: string
          enum:
            - email
            - sms
          example: email
        status:
          type:
            - string
            - 'null'
          enum:
            - draft
            - scheduled
            - preparing
            - awaiting_winner
            - sending
            - sent
            - partially_sent
            - unsent
            - canceled
            - null
          description: >
            The newsletter's send lifecycle. `null` for flow campaigns.


            Two kinds of send reach beyond the plain draft → scheduled → sending
            →

            sent path, and they share some states.


            A newsletter scheduled to land at a recipient-local wall-clock time

            ("send in recipient's timezone") rolls delivery out over roughly 24

            hours as each timezone reaches that time. `preparing` is audience

            generation, and it is the last point at which the send can be

            unscheduled; after that a merchant can only cancel the remaining

            delivery windows, leaving `partially_sent` when some recipients were

            already sent to and `canceled` when none were.


            An A/B test runs

            `preparing` → `awaiting_winner` → `sending` → `sent`: it generates
            its

            audience, sends to the test cohort, then holds at `awaiting_winner`

            while the decision window runs, and only sends the winning version
            to

            the remaining audience once a winner is committed. A test cancelled

            mid-flight also reports `canceled`. `awaiting_winner` occurs on A/B

            tests only.
          example: sent
        subject:
          type:
            - string
            - 'null'
          description: Email subject line. `null` for SMS campaigns.
          example: The restock you asked for is here
        send_date:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            When the newsletter is scheduled to send (or sent). `null` for flow
            campaigns.
          example: '2026-06-18T15:00:00Z'
        flow:
          oneOf:
            - $ref: '#/components/schemas/CampaignFlowRef'
            - type: 'null'
          description: >
            Flow campaigns only — the flow that sends this message, so naming it
            needs no follow-up request. Newsletters omit the field entirely; a
            flow campaign whose node has since been deleted carries `null`.
        audience:
          type:
            - object
            - 'null'
          description: >
            Audience segment references. `null` for flow campaigns — the flow's

            trigger decides the audience. Each entry is `{id, name, prebuilt}`;

            saved segments carry an id you can look up via `GET
            /v1/segments/{id}`

            for counts and members. `prebuilt: true` marks Privy's

            built-in smart segments (Potential Customers, Engaged Contacts, …) —

            when one hasn't been saved to the account, its `id` is the stable

            slug rather than a segments-API id.
          properties:
            included_segments:
              type: array
              items:
                $ref: '#/components/schemas/AudienceSegmentRef'
            excluded_segments:
              type: array
              items:
                $ref: '#/components/schemas/AudienceSegmentRef'
        coupon:
          oneOf:
            - $ref: '#/components/schemas/CouponRef'
            - type: 'null'
          description: >
            The coupon pool attached to this campaign, `null` when none. A `{{
            coupon_code }}` tag in the message body only renders when a pool is
            attached — a body using the tag with `coupon: null` will not render
            a code.
        ab_test:
          oneOf:
            - $ref: '#/components/schemas/CampaignAbTest'
            - type: 'null'
          description: >
            The A/B test's configuration when this newsletter is a test, `null`
            otherwise (flow campaigns never are). Per-version results live on
            `GET /v1/reports/campaigns/{campaign_id}`, joined by version `id`.
        created_at:
          type: string
          format: date-time
          example: '2026-06-10T09:00:00Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-06-18T15:05:00Z'
    CampaignFlowRef:
      type: object
      description: >
        The automation flow that sends this campaign. Pass `id` to `GET
        /v1/flows/{id}` for the flow's trigger, filters, and node graph.
      properties:
        id:
          type: string
          description: The flow's identifier, as returned by `GET /v1/flows`.
          example: 0Rqw3Z8
        title:
          type:
            - string
            - 'null'
          example: Welcome Series
    AudienceSegmentRef:
      type: object
      properties:
        id:
          type: string
          description: >
            For saved segments, the segment id — pass it to `GET
            /v1/segments/{id}`

            (counts) or `GET /v1/segments/{id}/contacts` (members).

            A smart segment that has not been saved to the account has no

            segment record; its `id` is the built-in segment's stable slug

            (e.g. `potential_customers`), with no segments-API detail read.
          example: aBc1234
        name:
          type: string
          description: Display name of the segment.
          example: Engaged 90d
        prebuilt:
          type: boolean
          description: |
            Whether this is one of Privy's built-in smart segments (Potential
            Customers, Engaged Contacts, …) — the same flag the segments API
            returns, so refs match `GET /v1/segments` rows. `false` for segments
            you created.
          example: false
    CouponRef:
      type: object
      description: >
        The coupon pool attached to a message or display — a `{{ coupon_code }}`
        tag in the content only renders when one is attached. Pass `id` to `GET
        /v1/coupons/{id}` for the pool's inventory and health; `kind` and
        `platform` match that endpoint's rows.
      properties:
        id:
          type: string
          description: The pool's identifier, as returned by `GET /v1/coupons`.
          example: Xk2fW9qLpV
        title:
          type: string
          example: Welcome 10%
        kind:
          type: string
          enum:
            - master
            - unique
          description: >-
            `master` is a single shared code; `unique` is a pool of individually
            generated codes.
        platform:
          type: string
          enum:
            - manual
            - shopify
            - bigcommerce
            - woocommerce
    CampaignAbTest:
      type: object
      description: How the newsletter's A/B test is set up.
      properties:
        winning_metric:
          type:
            - string
            - 'null'
          enum:
            - open_rate
            - click_rate
            - order_rate
            - null
          description: >
            The metric the winner is chosen on. `open_rate` only appears on
            older email tests and never on SMS.
          example: click_rate
        test_duration_seconds:
          type:
            - integer
            - 'null'
          description: How long the test cohort runs before a winner is chosen.
          example: 86400
        versions:
          type: array
          description: The versions in labelled order (A, B, C…); the control is first.
          items:
            $ref: '#/components/schemas/CampaignAbTestVersion'
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - invalid_client
                - invalid_scope
                - unauthorized
                - insufficient_scope
                - paid_plan_required
                - api_access_required
                - not_found
                - no_connected_store
                - conflict
                - contacts_not_ready
                - validation_failed
                - rate_limited
                - store_unavailable
              example: validation_failed
            message:
              type: string
              example: One or more fields are invalid
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    example: email
                  message:
                    type: string
                    example: is required
    CampaignAbTestVersion:
      type: object
      properties:
        id:
          type: string
          description: >
            Opaque, stable version identifier, prefixed `cpv_`. Matches the
            version's results on `GET /v1/reports/campaigns/{campaign_id}`.
          example: cpv_dkyYZmk
        name:
          type: string
          example: Version A
        is_control:
          type: boolean
          example: true
        is_winner:
          type: boolean
          description: >-
            Whether this version won. `false` on every version until a winner is
            committed.
          example: false
        audience_share:
          type:
            - number
            - 'null'
          description: >
            Share of the eligible audience (0–1) this version is sent to during
            the test. `null` until set on a draft. Shares sum to the test size;
            the remainder goes to the winner.
          example: 0.125
        subject:
          type:
            - string
            - 'null'
          description: This version's subject line, or its message body for SMS.
          example: The restock you asked for is here
        preheader:
          type:
            - string
            - 'null'
          description: This version's preheader. `null` for SMS or when none was set.
          example: Back in stock and going fast
        coupon:
          oneOf:
            - $ref: '#/components/schemas/CouponRef'
            - type: 'null'
          description: The coupon pool this version sends with, `null` when none.
  responses:
    Unauthorized:
      description: Missing or invalid bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: unauthorized
              message: Bearer token is missing or invalid
    InsufficientScope:
      description: Token lacks the required scope for this endpoint.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: insufficient_scope
              message: Token does not have the required scope
    NotFound:
      description: >-
        The requested resource does not exist or does not belong to your
        account.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: not_found
              message: Not found
    RateLimited:
      description: Rate limit exceeded. Retry after the specified time.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
          example: 42
        X-RateLimit-Limit-Minute:
          description: Maximum requests allowed per minute.
          schema:
            type: integer
          example: 60
        X-RateLimit-Remaining-Minute:
          description: Requests remaining in the current minute window.
          schema:
            type: integer
          example: 0
        X-RateLimit-Reset-Minute:
          description: Unix timestamp when the minute window resets.
          schema:
            type: integer
          example: 1711929600
        X-RateLimit-Limit-Day:
          description: Maximum requests allowed per day.
          schema:
            type: integer
          example: 10000
        X-RateLimit-Remaining-Day:
          description: Requests remaining in the current day window.
          schema:
            type: integer
          example: 9500
        X-RateLimit-Reset-Day:
          description: Unix timestamp when the day window resets.
          schema:
            type: integer
          example: 1712016000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: rate_limited
              message: Rate limit exceeded
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API token or OAuth access token
      description: >
        Send either an API token or an OAuth access token as

        `Authorization: Bearer <token>`. See the Authentication page for
        details.

````