Loops Campaigns API

Create, target, schedule and update email campaigns. 4 operation(s) in the Loops REST API v1 (OpenAPI 1.21.6).

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/loops-campaigns-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

loops-campaigns-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Loops OpenAPI Spec Campaigns API
  description: This is the OpenAPI Spec for the [Loops API](https://loops.so/docs/api).
  version: 1.21.6
servers:
- url: https://app.loops.so/api/v1
tags:
- name: Campaigns
  description: Create and manage email campaigns
paths:
  /campaigns:
    get:
      operationId: listCampaigns
      tags:
      - Campaigns
      summary: List campaigns
      description: Retrieve a paginated list of campaigns.
      x-mint:
        href: /api-reference/list-campaigns
      parameters:
      - name: perPage
        in: query
        required: false
        description: How many results to return in each request. Must be between 10 and 50. Default is 20.
        schema:
          type: string
      - name: cursor
        in: query
        required: false
        description: A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.
        schema:
          type: string
      responses:
        '200':
          description: Successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListCampaignsResponse'
        '400':
          description: Invalid `perPage` value.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
        '401':
          description: Invalid API key or content API not enabled for this team.
        '405':
          description: Wrong HTTP request method.
      security:
      - apiKey: []
    post:
      operationId: createCampaign
      tags:
      - Campaigns
      summary: Create a campaign
      description: Create a new draft campaign. An empty email message is created automatically and its `emailMessageId` is returned. Use the `/email-messages/{emailMessageId}` endpoint to set subject, sender, preview text, and LMX content. The audience (mailing list, segment, or filter), group, and scheduling can be set on create or later via update.
      x-mint:
        href: /api-reference/create-campaign
        metadata:
          description: Create a draft marketing campaign and its associated email message.
        content: 'This endpoint creates a draft campaign and an empty email message in one step. Use the returned `emailMessageId` with [Update an email message](/api-reference/update-email-message) to set subject, sender, preview text, and LMX content.


          The audience (mailing list, segment, or filter), group, and scheduling can be set on create or later via [Update a campaign](/api-reference/update-campaign).


          <Tip>To send a test preview of a campaign, use the [Preview email message](/api-reference/preview-email-message) endpoint.</Tip>'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCampaignRequest'
      responses:
        '201':
          description: Campaign created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCampaignResponse'
        '400':
          description: Invalid request body, campaign group not found, or no sending domain configured.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
        '401':
          description: Invalid API key or content API not enabled for this team.
        '404':
          description: Referenced mailing list or audience segment not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
        '405':
          description: Wrong HTTP request method.
      security:
      - apiKey: []
  /campaigns/{campaignId}:
    parameters:
    - name: campaignId
      in: path
      required: true
      description: The ID of the campaign.
      schema:
        type: string
        examples:
        - clc4m6n8p0q2r4s6t8u0v2x4
    get:
      operationId: getCampaign
      tags:
      - Campaigns
      summary: Get a campaign
      description: Retrieve a single campaign by ID.
      x-mint:
        href: /api-reference/get-campaign
      responses:
        '200':
          description: Successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignResponse'
        '400':
          description: Invalid `campaignId`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
        '401':
          description: Invalid API key or content API not enabled for this team.
        '404':
          description: Campaign not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
        '405':
          description: Wrong HTTP request method.
      security:
      - apiKey: []
    post:
      operationId: updateCampaign
      tags:
      - Campaigns
      summary: Update a campaign
      description: Update a draft campaign's name, group, audience (mailing list, segment, or filter), or scheduling. At least one field must be provided. Once a campaign has been sent, only its `name` and `campaignGroupId` can be updated.
      x-mint:
        href: /api-reference/update-campaign
        metadata:
          description: Update a draft campaign's name, group, audience (mailing list, segment, or filter), or scheduling.
        content: <Info>At least one field must be provided. Draft campaigns support every field below. Once a campaign has been sent, only `name` and `campaignGroupId` can be updated.</Info>
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCampaignRequest'
      responses:
        '200':
          description: Campaign updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignResponse'
        '400':
          description: Invalid request body or campaign group not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
        '401':
          description: Invalid API key or content API not enabled for this team.
        '404':
          description: Campaign, mailing list, or audience segment not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '409':
          description: Campaign has been sent and the request updates a field other than `name` or `campaignGroupId`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignFailureResponse'
      security:
      - apiKey: []
components:
  schemas:
    ActivityCondition:
      type: object
      description: Matches contacts by their activity on a campaign or workflow.
      properties:
        type:
          type: string
          enum:
          - activity
        action:
          type: string
          enum:
          - sent
          - opened
          - clicked
        negate:
          type: boolean
        target:
          type: string
          enum:
          - campaign
          - workflow
          - workflowEmail
        id:
          type: string
          description: The ID of the campaign, workflow, or workflow email.
      required:
      - type
      - action
      - negate
      - target
      - id
      examples:
      - type: activity
        action: opened
        negate: false
        target: campaign
        id: clc4m6n8p0q2r4s6t8u0v2x4
    AudienceFilter:
      type:
      - object
      - 'null'
      description: A tree of audience conditions combined with `match`.
      properties:
        match:
          type: string
          enum:
          - all
          - any
        conditions:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/AudienceFilterCondition'
      required:
      - match
      - conditions
      additionalProperties: false
    AudienceFilterCondition:
      oneOf:
      - $ref: '#/components/schemas/PropertyCondition'
      - $ref: '#/components/schemas/OptInCondition'
      - $ref: '#/components/schemas/ActivityCondition'
      discriminator:
        propertyName: type
    AudienceFilterInRequest:
      type:
      - object
      - 'null'
      description: A tree of audience conditions combined with `match`. Setting this without also providing `audienceSegmentId` clears any existing `audienceSegmentId`. When both are provided, this filter is applied on top of the segment's filter.
      properties:
        match:
          type: string
          enum:
          - all
          - any
        conditions:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/AudienceFilterCondition'
      required:
      - match
      - conditions
      additionalProperties: false
    CampaignFailureResponse:
      type: object
      properties:
        message:
          type: string
      required:
      - message
      examples:
      - message: Campaign not found.
    CampaignResponse:
      type: object
      properties:
        id:
          type: string
          description: The ID of the campaign.
          examples:
          - clc4m6n8p0q2r4s6t8u0v2x4
        name:
          type: string
          description: The name of the campaign.
          examples:
          - Spring announcement
        status:
          type: string
          description: The status of the campaign.
          enum:
          - Draft
          - Scheduled
          - Sending
          - Sent
          examples:
          - Draft
        createdAt:
          type: string
          format: date-time
          examples:
          - 2025-06-29 07:47:39.370000+00:00
          description: ISO 8601 timestamp for when the campaign was created.
        updatedAt:
          type: string
          format: date-time
          examples:
          - 2025-06-29 07:47:39.370000+00:00
          description: ISO 8601 timestamp for when the campaign was last updated.
        emailMessageId:
          type:
          - string
          - 'null'
          description: The associated email message ID.
          examples:
          - cle5f7g9h1i3j5k7l9m1n3p5
        campaignGroupId:
          type:
          - string
          - 'null'
          description: The ID of the campaign group this campaign belongs to.
          examples:
          - clg7n5p3q1r9s7t5u3v1w9y7
        mailingListId:
          type:
          - string
          - 'null'
          examples:
          - clm2k8j4h6g0f8d6s4a2b0z8
          description: The ID of the mailing list this campaign sends to, if set.
        audienceSegmentId:
          type:
          - string
          - 'null'
          description: The ID of the audience segment this campaign targets, if set.
          examples:
          - cls6e8g0i2k4m6o8q0s2u4w6
        audienceFilter:
          $ref: '#/components/schemas/AudienceFilter'
          description: The filter rules that define the audience for this campaign, if set.
        scheduling:
          $ref: '#/components/schemas/CampaignScheduling'
      required:
      - id
      - name
      - status
      - createdAt
      - updatedAt
      - emailMessageId
      - campaignGroupId
      - mailingListId
      - audienceSegmentId
      - audienceFilter
      - scheduling
      examples:
      - id: clc4m6n8p0q2r4s6t8u0v2x4
        name: Spring announcement
        status: Draft
        createdAt: 2025-06-29 07:47:39.370000+00:00
        updatedAt: 2025-06-29 07:47:39.370000+00:00
        emailMessageId: cle5f7g9h1i3j5k7l9m1n3p5
        campaignGroupId: clg7n5p3q1r9s7t5u3v1w9y7
        mailingListId: clm2k8j4h6g0f8d6s4a2b0z8
        audienceSegmentId: null
        audienceFilter: null
        scheduling:
          method: now
          timestamp: null
    CampaignScheduling:
      type: object
      description: When the campaign is scheduled to send.
      properties:
        method:
          type: string
          enum:
          - now
          - schedule
        timestamp:
          type:
          - string
          - 'null'
          format: date-time
          description: ISO 8601 send time. Null when the method is `now`.
      required:
      - method
      - timestamp
      examples:
      - method: schedule
        timestamp: 2025-07-15 14:00:00+00:00
    CampaignSchedulingRequest:
      type: object
      description: When the campaign should send. `timestamp` is required and must be in the future when `method` is `schedule`, and must be omitted when `method` is `now`.
      properties:
        method:
          type: string
          enum:
          - now
          - schedule
        timestamp:
          type: string
          format: date-time
      required:
      - method
      additionalProperties: false
      examples:
      - method: schedule
        timestamp: 2025-07-15 14:00:00+00:00
    CreateCampaignRequest:
      type: object
      properties:
        name:
          type: string
          description: The campaign name.
          examples:
          - Spring announcement
        campaignGroupId:
          type: string
          description: The ID of the group to add this campaign to. Defaults to the team's default group when omitted.
          examples:
          - clg7n5p3q1r9s7t5u3v1w9y7
        mailingListId:
          type:
          - string
          - 'null'
          description: The ID of the mailing list to send to.
          examples:
          - clm2k8j4h6g0f8d6s4a2b0z8
        audienceSegmentId:
          type:
          - string
          - 'null'
          description: The ID of an audience segment. Setting this without also providing `audienceFilter` clears any existing `audienceFilter`. If both are provided, the filter is applied on top of the segment's filter.
          examples:
          - cls6e8g0i2k4m6o8q0s2u4w6
        audienceFilter:
          $ref: '#/components/schemas/AudienceFilterInRequest'
        scheduling:
          $ref: '#/components/schemas/CampaignSchedulingRequest'
      required:
      - name
      additionalProperties: false
    CreateCampaignResponse:
      type: object
      properties:
        id:
          type: string
          description: The ID of the campaign.
          examples:
          - clc4m6n8p0q2r4s6t8u0v2x4
        name:
          type: string
          description: The name of the campaign.
          examples:
          - Spring announcement
        status:
          type: string
          examples:
          - Draft
          enum:
          - Draft
          description: The status of the campaign (always `Draft` for new campaigns).
        createdAt:
          type: string
          format: date-time
          examples:
          - 2025-06-29 07:47:39.370000+00:00
          description: ISO 8601 timestamp for when the campaign was created.
        updatedAt:
          type: string
          format: date-time
          examples:
          - 2025-06-29 07:47:39.370000+00:00
          description: ISO 8601 timestamp for when the campaign was last updated.
        emailMessageId:
          type:
          - string
          - 'null'
          description: The ID of the empty email message created for this campaign. Use `POST /v1/email-messages/{emailMessageId}` to set its fields and LMX content.
          examples:
          - cle5f7g9h1i3j5k7l9m1n3p5
        emailMessageContentRevisionId:
          type:
          - string
          - 'null'
          description: The `contentRevisionId` of the newly created email message. Pass this as `expectedRevisionId` on your first update.
          examples:
          - clrev1s10n2i3d4e5f6g7h8
        campaignGroupId:
          type:
          - string
          - 'null'
          description: The ID of the campaign group this campaign belongs to, if set.
          examples:
          - clg7n5p3q1r9s7t5u3v1w9y7
        mailingListId:
          type:
          - string
          - 'null'
          description: The ID of the mailing list this campaign sends to, if set.
          examples:
          - clm2k8j4h6g0f8d6s4a2b0z8
        audienceSegmentId:
          type:
          - string
          - 'null'
          description: The ID of the audience segment this campaign targets, if set.
          examples:
          - cls6e8g0i2k4m6o8q0s2u4w6
        audienceFilter:
          $ref: '#/components/schemas/AudienceFilter'
          description: The filter rules that define the audience for this campaign, if set.
        scheduling:
          $ref: '#/components/schemas/CampaignScheduling'
          description: When the campaign is scheduled to send.
      required:
      - id
      - name
      - status
      - createdAt
      - updatedAt
      - emailMessageId
      - emailMessageContentRevisionId
      - campaignGroupId
      - mailingListId
      - audienceSegmentId
      - audienceFilter
      - scheduling
      examples:
      - id: clc4m6n8p0q2r4s6t8u0v2x4
        name: Spring announcement
        status: Draft
        createdAt: 2025-06-29 07:47:39.370000+00:00
        updatedAt: 2025-06-29 07:47:39.370000+00:00
        emailMessageId: cle5f7g9h1i3j5k7l9m1n3p5
        campaignGroupId: clg7n5p3q1r9s7t5u3v1w9y7
        mailingListId: clm2k8j4h6g0f8d6s4a2b0z8
        audienceSegmentId: null
        audienceFilter: null
        scheduling:
          method: now
          timestamp: null
        emailMessageContentRevisionId: clrev1s10n2i3d4e5f6g7h8
    ListCampaignsResponse:
      type: object
      properties:
        pagination:
          $ref: '#/components/schemas/Pagination'
        data:
          type: array
          items:
            $ref: '#/components/schemas/CampaignResponse'
      required:
      - pagination
      - data
      examples:
      - pagination:
          totalResults: 45
          returnedResults: 20
          perPage: 20
          totalPages: 3
          nextCursor: clp9k2m4n6p8q0r2s4t6u8v0
          nextPage: https://app.loops.so/api/v1/campaign-groups?cursor=clp9k2m4n6p8q0r2s4t6u8v0&perPage=20
        data:
        - id: clc4m6n8p0q2r4s6t8u0v2x4
          name: Spring announcement
          status: Draft
          createdAt: 2025-06-29 07:47:39.370000+00:00
          updatedAt: 2025-06-29 07:47:39.370000+00:00
          emailMessageId: cle5f7g9h1i3j5k7l9m1n3p5
          campaignGroupId: clg7n5p3q1r9s7t5u3v1w9y7
          mailingListId: clm2k8j4h6g0f8d6s4a2b0z8
          audienceSegmentId: null
          audienceFilter: null
          scheduling:
            method: now
            timestamp: null
    OptInCondition:
      type: object
      description: Matches contacts by mailing-list opt-in status.
      properties:
        type:
          type: string
          enum:
          - optIn
        status:
          type:
          - string
          - 'null'
          enum:
          - accepted
          - pending
          - rejected
          - null
      required:
      - type
      - status
      examples:
      - type: optIn
        status: accepted
    Pagination:
      type: object
      properties:
        totalResults:
          type: number
          examples:
          - 2
        returnedResults:
          type: number
          examples:
          - 2
        perPage:
          type: number
          examples:
          - 20
        totalPages:
          type: number
          examples:
          - 1
        nextCursor:
          type:
          - string
          - 'null'
          examples:
          - null
        nextPage:
          type:
          - string
          - 'null'
          examples:
          - null
      required:
      - totalResults
      - returnedResults
      - perPage
      - totalPages
      - nextCursor
      - nextPage
      examples:
      - totalResults: 2
        returnedResults: 2
        perPage: 20
        totalPages: 1
        nextCursor: null
        nextPage: null
    PropertyCondition:
      type: object
      description: Matches contacts by a property value.
      properties:
        type:
          type: string
          enum:
          - property
        key:
          type: string
          description: The contact property name.
        operator:
          type: string
          enum:
          - any
          - contains
          - notContains
          - equals
          - notEquals
          - greaterThan
          - lessThan
          - isTrue
          - isFalse
          - empty
          - notEmpty
          - dateEmpty
          - dateNotEmpty
          - after
          - before
          - between
        value:
          description: The comparison value. Omitted for value-less operators (e.g. `isTrue`, `empty`). A `{ from, to }` object for `between`.
          oneOf:
          - type: string
          - type: number
          - type: object
            properties:
              from:
                type: string
                format: date-time
              to:
                type: string
                format: date-time
            required:
            - from
            - to
      required:
      - type
      - key
      - operator
      examples:
      - type: property
        key: plan
        operator: equals
        value: pro
    UpdateCampaignRequest:
      type: object
      description: At least one field must be provided.
      properties:
        name:
          type: string
          description: The updated campaign name.
          examples:
          - Spring announcement
        campaignGroupId:
          type: string
          description: The ID of the group to move this campaign to.
          examples:
          - clg7n5p3q1r9s7t5u3v1w9y7
        mailingListId:
          type:
          - string
          - 'null'
          description: The ID of the mailing list to send to.
          examples:
          - clm2k8j4h6g0f8d6s4a2b0z8
        audienceSegmentId:
          type:
          - string
          - 'null'
          description: The ID of an audience segment. Setting this without also providing `audienceFilter` clears any existing `audienceFilter`. If both are provided, the filter is applied on top of the segment's filter.
          examples:
          - cls6e8g0i2k4m6o8q0s2u4w6
        audienceFilter:
          $ref: '#/components/schemas/AudienceFilterInRequest'
        scheduling:
          $ref: '#/components/schemas/CampaignSchedulingRequest'
      additionalProperties: false
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer