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

# Enroll leads into a campaign

> Queue the campaign's sequence for real sending, respecting the inbox's warmup and daily caps. Up to 1,000 leads per call; ids past the first 1,000 are counted in `skipped_over_limit`.

Skipped rather than failed: leads with no email, leads already enrolled, unsubscribed or suppressed addresses, addresses that bounced, addresses known to be undeliverable, and — when the brand only writes to confirmed addresses — addresses that could not be confirmed. Each cause has its own counter; `summary` explains them in plain language.

When the brand has *validate on enroll* turned on (the default), unchecked addresses are enrolled and checked in the background (`queued_for_validation`). The result is applied at send time, so an address that turns out undeliverable is never sent to.

**Sending cannot be undone.** Requires a paid plan and the `outreach:send` permission.



## OpenAPI

````yaml POST /api/outreach/enroll
openapi: 3.1.0
info:
  title: ManyPI API
  description: >-
    The REST API behind ManyPI — AI lead generation, email validation,
    cold-email outreach, agent runs and web scraping. Every endpoint is
    authenticated with a ManyPI API key (`mpi_...`) or an OAuth 2.1 access
    token, and honours the permissions granted to that credential.
  version: 2.0.0
  contact:
    name: ManyPI Support
    email: support@manypi.com
    url: https://manypi.com
servers:
  - url: https://app.manypi.com
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Leads
    description: Find, store, enrich and manage leads.
  - name: Email validation
    description: Verify that lead addresses can receive mail.
  - name: Outreach
    description: Inboxes, sequences, campaigns, sending and replies.
  - name: Agent
    description: Agent runs, replies and skills.
  - name: Scraping
    description: Scrapers, runs and extracted data.
  - name: Endpoints
    description: Publish scrapers as typed REST endpoints.
  - name: Account
    description: Key validation and account information.
paths:
  /api/outreach/enroll:
    post:
      tags:
        - Outreach
      summary: Enroll leads into a campaign
      description: >-
        Queue the campaign's sequence for real sending, respecting the inbox's
        warmup and daily caps. Up to 1,000 leads per call; ids past the first
        1,000 are counted in `skipped_over_limit`.


        Skipped rather than failed: leads with no email, leads already enrolled,
        unsubscribed or suppressed addresses, addresses that bounced, addresses
        known to be undeliverable, and — when the brand only writes to confirmed
        addresses — addresses that could not be confirmed. Each cause has its
        own counter; `summary` explains them in plain language.


        When the brand has *validate on enroll* turned on (the default),
        unchecked addresses are enrolled and checked in the background
        (`queued_for_validation`). The result is applied at send time, so an
        address that turns out undeliverable is never sent to.


        **Sending cannot be undone.** Requires a paid plan and the
        `outreach:send` permission.
      operationId: enrollLeads
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - campaign_id
                - lead_ids
              properties:
                campaign_id:
                  type: string
                  format: uuid
                lead_ids:
                  type: array
                  minItems: 1
                  maxItems: 1000
                  items:
                    type: string
                    format: uuid
            example:
              campaign_id: …
              lead_ids:
                - 8f1c0e6a-1c3e-4f2a-9a4b-0f7a1e2b3c4d
      responses:
        '200':
          description: Enrollment outcome.
          content:
            application/json:
              schema:
                type: object
                description: >-
                  Skips are reported as one counter per cause rather than a
                  single total. Counters for causes that did not occur may be
                  omitted. For the number of leads that were not enrolled, add
                  up every `skipped_*` counter and `already_enrolled` — or
                  compute `requested - enrolled`.
                properties:
                  enrolled:
                    type: integer
                    description: >-
                      Leads that now have an enrollment they did not have
                      before. Includes `queued_for_validation`.
                  requested:
                    type: integer
                    description: Lead ids in the request, before any skipping.
                  already_enrolled:
                    type: integer
                    description: Leads already enrolled in this campaign.
                  skipped_not_found:
                    type: integer
                    description: Ids that match no lead this workspace can see.
                  skipped_no_email:
                    type: integer
                    description: Leads with no email address.
                  skipped_unsubscribed:
                    type: integer
                    description: Leads who unsubscribed or are on the do-not-contact list.
                  skipped_bounced:
                    type: integer
                    description: Leads whose address bounced the last time you wrote.
                  skipped_invalid:
                    type: integer
                    description: >-
                      Addresses known to be dead: invalid, disposable, or a
                      domain that takes no mail.
                  skipped_unverifiable:
                    type: integer
                    description: >-
                      Addresses the mail server would not confirm, skipped
                      because the brand only writes to confirmed addresses.
                  skipped_over_limit:
                    type: integer
                    description: Ids past the first 1,000 in this request.
                  queued_for_validation:
                    type: integer
                    description: >-
                      Enrolled leads whose unchecked address is being verified
                      in the background, when the brand has validate-on-enroll
                      turned on.
                  summary:
                    type: string
                    description: >-
                      What happened, in plain language — the same text the
                      dashboard shows.
              example:
                enrolled: 214
                requested: 240
                already_enrolled: 9
                skipped_no_email: 12
                skipped_unsubscribed: 3
                skipped_bounced: 2
                queued_for_validation: 4
                summary: >-
                  Added 214 of 240 leads. 9 leads are already in this campaign.
                  12 leads have no email address yet, so there is nothing to
                  send to. Find their address first, then add them again. 3
                  leads unsubscribed, so they stay on your do-not-contact list.
                  Remove them from Suppressions if that was a mistake. 2 leads
                  bounced the last time you wrote. Sending again would only
                  damage the reputation of the inbox you send from.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            Outreach requires a paid plan (`code: "outreach_locked"`), or the
            workspace is over its seat count.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  responses:
    BadRequest:
      description: The request body or parameters failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: >-
        Missing, invalid or expired credential — or a key that lacks the
        permission this route requires.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      type: object
      properties:
        error:
          description: >-
            Human-readable message. A few validation failures (creating or
            updating an endpoint, bulk lead updates and deletes) send a list of
            the individual problems here instead of one string.
          oneOf:
            - type: string
            - type: array
              items:
                type: object
                properties:
                  path:
                    type: array
                    items:
                      type:
                        - string
                        - integer
                  message:
                    type: string
        code:
          type: string
          description: >-
            A machine-readable code on gated failures: `lead_limit`,
            `outreach_locked`, `validation_credits_exhausted`.
        details:
          description: >-
            Extra detail on some failures, such as the list of parameters that
            failed an endpoint's `param_schema`.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        A ManyPI API key (`mpi_...`) from the profile menu → API Access in the
        dashboard, or an OAuth 2.1 access token obtained through the MCP consent
        flow.

````

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