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

# Create a dialer campaign

> Creates a new outbound dialer campaign in `draft` status (preview / progressive / predictive / agentless mode). Validates that `caller_id_e164` and every `caller_id_pool` entry are owned by the calling org (anti-spoofing), and that `voice_agent_id` (when set) references a real voice agent in this workspace. Recording requires `recording_consent_acknowledged=true` in the same request. Requires the `dialer:write` scope.



## OpenAPI

````yaml /openapi.yaml post /api/v1/dialer/campaigns
openapi: 3.1.0
info:
  title: Devotel CPaaS API
  description: Orbit by Devotel — Communications Platform as a Service API
  version: 1.0.0
  contact:
    name: Devotel
    url: https://devotel.io
    email: support@devotel.io
  license:
    name: Proprietary
servers:
  - url: https://api.orbit.devotel.io
    description: Production
security:
  - Bearer: []
  - ApiKey: []
tags:
  - name: Messages
    description: >-
      Send and manage messages across all channels (SMS, WhatsApp, RCS, Email,
      Viber, etc.)
  - name: Agents
    description: AI agent creation, configuration, and execution
  - name: Voice
    description: Voice calls, IVR, conferencing, and SIP trunking
  - name: Webhooks
    description: Webhook endpoint management and delivery logs
  - name: Numbers
    description: Phone number search, provisioning, and configuration
  - name: Contacts
    description: Contact management, segmentation, and lifecycle tracking
  - name: Campaigns
    description: Marketing campaign orchestration and analytics
  - name: Flows
    description: Automation flow builder and execution engine
  - name: Templates
    description: Message template management and approval workflows
  - name: Settings
    description: Organization, channel, and user preference settings
  - name: Verify
    description: OTP generation and verification across channels
  - name: Push
    description: Push notification delivery via FCM and APNs
  - name: Telegram
    description: >-
      Telegram bring-your-own-bot channel: connect a bot, verify a chat against
      the shared sandbox bot, and read unified channel state. Production sends
      go through the Messaging API.
  - name: USSD
    description: >-
      Menu-driven USSD for feature phones: define a menu tree, simulate session
      steps, and host the tenant-scoped aggregator callback.
  - name: Integrations
    description: Third-party service connections and OAuth management
  - name: Files
    description: >-
      Server-to-server media upload, listing, retrieval, and deletion
      (signed-URL backed)
  - name: Messaging Services
    description: >-
      Twilio MessagingService-parity containers bundling sender pool, opt-out
      list, inbound webhook, and sticky-sender/geomatch flags
  - name: Sender Pools
    description: >-
      Group sending numbers into pools with a selection strategy (sticky /
      round-robin / random) for outbound sends
  - name: Opt-Out Lists
    description: >-
      Per-list STOP / HELP / START keyword sets and auto-response copy (Twilio
      Advanced Opt-Out parity)
  - name: SMPP
    description: Tenant BYO-SMPP bind credentials and upstream termination carriers
  - name: Commerce
    description: >-
      Unified omnichannel conversational-commerce: cart/checkout state machine,
      cross-channel payment reconciliation, hosted pay-by-link, native WhatsApp
      checkout, and agentic-checkout payment mandates
  - name: Orby
    description: >-
      In-dashboard Orby operator assistant: streamed assistant turns,
      conversation threads, product knowledge-base search, and the tool-action
      approval gate. Available to signed-in operators only (dashboard session
      auth — API-key requests are rejected).
paths:
  /api/v1/dialer/campaigns:
    post:
      tags:
        - Dialer
      summary: Create a dialer campaign
      description: >-
        Creates a new outbound dialer campaign in `draft` status (preview /
        progressive / predictive / agentless mode). Validates that
        `caller_id_e164` and every `caller_id_pool` entry are owned by the
        calling org (anti-spoofing), and that `voice_agent_id` (when set)
        references a real voice agent in this workspace. Recording requires
        `recording_consent_acknowledged=true` in the same request. Requires the
        `dialer:write` scope.
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Stripe-style idempotency token. Pass a stable, client-generated
            value (1-255 chars) to dedupe retries on transient timeouts. The
            same key+credential+path replays the original response for 24h on
            2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request
            with the same key is already in flight; replayed responses include
            the `Idempotency-Replay: true` response header.
          schema:
            type: string
            minLength: 1
            maxLength: 255
        - name: X-Test-Mode
          in: header
          required: false
          description: >-
            Sandbox opt-in for Clerk-session-authenticated requests. Set to
            `true` to route the call through the test-mode pipeline: no real
            provider delivery, no credits deducted, response `meta.test_mode:
            true`. **Ignored for live API keys (`dv_live_sk_*`)** —
            server-to-server clients must use a test-prefixed key
            (`dv_test_sk_*`) to exercise sandbox. Test-prefixed keys
            unconditionally enable sandbox regardless of this header.
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Campaign display name.
                mode:
                  type: string
                  description: >-
                    Dial strategy: 'preview' (agent reviews + clicks to dial),
                    'progressive', 'predictive', or 'agentless' (broadcast, no
                    agent leg).
                caller_id_e164:
                  type: string
                  description: >-
                    Default outbound caller-ID in E.164 format. Must be a number
                    this org owns.
                pacing_ratio:
                  type: number
                  description: >-
                    Predictive/progressive dial-to-agent ratio. 0.8-3.0, default
                    1.2.
                max_abandon_rate:
                  type: number
                  description: >-
                    FCC abandon-rate ceiling for this campaign, as a fraction
                    (e.g. 0.03 = 3%). Cannot exceed the platform's 3% ceiling.
                target_service_level_seconds:
                  type: number
                  description: >-
                    Target seconds-to-answer used by the predictive pacer.
                    5-120, default 20.
                application_sid:
                  type: string
                  description: >-
                    Optional explicit Jambonz voice-control-plane application
                    override. Omit to use the mode/AMD-resolved default.
                agent_skills_required:
                  type: array
                  description: >-
                    Required agent skills for this campaign — legacy string
                    array (e.g. ['french']) or structured `{skill, min_level,
                    weight}` objects.
                call_script_id:
                  type: string
                  description: Optional legacy call-script reference.
                recording_enabled:
                  type: boolean
                  description: >-
                    Whether calls in this campaign are recorded. Requires
                    `recording_consent_acknowledged=true`.
                amd_enabled:
                  type: boolean
                  description: Whether answering-machine detection runs on each dialed leg.
                dispatch_mode:
                  type: string
                  description: >-
                    'human' (default, agent-fronted) or 'voice_agent' (each leg
                    connects to the AI voice agent named by `voice_agent_id`,
                    dispatched via `POST /campaigns/:id/batch-dispatch`).
                voice_agent_id:
                  type: string
                  description: >-
                    Required when `dispatch_mode='voice_agent'`; must reference
                    an existing agent in this workspace.
                concurrency_limit:
                  type: number
                  description: >-
                    Max simultaneous in-flight legs for voice-agent batch
                    dispatch. 1-200, default 10.
                broadcast_message_url:
                  type: string
                  description: >-
                    HTTPS URL of the message Jambonz plays on answer. Required
                    when `mode='agentless'`, forbidden otherwise.
                voicemail_message_url:
                  type: string
                  description: >-
                    HTTPS voicemail-drop audio URL played when AMD detects a
                    machine. Only valid for agent-driven modes.
                amd_sensitivity:
                  type: string
                  description: >-
                    AMD detection sensitivity: 'low', 'medium', or 'high'. Only
                    meaningful when `amd_enabled=true`.
                preview_decision_seconds:
                  type: number
                  description: >-
                    Per-campaign override of how long a preview-mode agent has
                    to decide before the claim auto-skips. Only valid for
                    `mode='preview'`.
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    Free-form operator metadata (e.g. TCPA quiet-hours override,
                    disposition codes).
                retry_policy:
                  type: object
                  additionalProperties: true
                  description: >-
                    Per-outcome retry backoff schedule keyed by outcome bucket
                    (no_answer, busy, machine, machine_silence, failed).
                caller_id_pool:
                  type: array
                  description: >-
                    Local-presence caller-ID rotation pool. Every entry must be
                    owned by this org. Required (non-empty) when
                    `caller_id_strategy` is not 'single'.
                caller_id_strategy:
                  type: string
                  description: >-
                    Caller-ID assignment strategy: 'single' (default) or
                    'npa_match' (local-presence rotation from `caller_id_pool`).
                campaign_script:
                  type: object
                  additionalProperties: true
                  description: >-
                    Optional human-agent guided-dialog script (sections +
                    branches). Omitted campaigns persist the canonical empty
                    shape.
                recording_consent_acknowledged:
                  type: boolean
                  description: >-
                    Operator's two-party-consent acknowledgement. Required when
                    `recording_enabled=true`.
                best_time_to_dial:
                  type: boolean
                  description: >-
                    When true, contacts uploaded to this campaign are enrolled
                    at their highest-answer-probability window instead of list
                    order.
            example:
              name: Q3 renewals
              mode: preview
              caller_id_e164: '+14155550100'
              recording_enabled: false
      responses:
        '201':
          description: The created campaign.
          content:
            application/json:
              schema:
                type: object
                description: The created campaign.
                properties:
                  data:
                    type: object
                    additionalProperties: true
                    description: >-
                      The created campaign row, echoing every submitted field
                      plus server-assigned `id` and `status: 'draft'`.
                    properties:
                      id:
                        type: string
                        description: Dialer campaign id.
                      name:
                        type: string
                      mode:
                        type: string
                      status:
                        type: string
                        description: Always 'draft' on create.
                  meta:
                    type: object
                    properties:
                      request_id:
                        type: string
                        description: >-
                          Unique request identifier (also returned in
                          X-Request-Id header)
                      timestamp:
                        type: string
                        format: date-time
                        description: ISO 8601 UTC timestamp of the response
          headers:
            Idempotency-Replay:
              description: >-
                Set to `true` when the response is a cached replay of a prior
                request with the same `Idempotency-Key`. Absent (or `false`) on
                first-write responses.
              schema:
                type: string
        '400':
          $ref: '#/components/responses/StandardError'
        '401':
          $ref: '#/components/responses/StandardError'
        '403':
          $ref: '#/components/responses/StandardError'
        '404':
          $ref: '#/components/responses/StandardError'
        '422':
          $ref: '#/components/responses/StandardError'
        '429':
          $ref: '#/components/responses/RateLimitedResponse'
        '500':
          $ref: '#/components/responses/StandardError'
components:
  responses:
    StandardError:
      description: >-
        Standard error envelope. `error.code` is machine-readable; see the
        [error reference](https://docs.orbit.devotel.io/reference/error-codes)
        for the catalogue.
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                required:
                  - code
                  - message
                  - status
                properties:
                  code:
                    type: string
                    description: Machine-readable error code (e.g. INVALID_PHONE_NUMBER)
                  message:
                    type: string
                    description: Human-readable error description
                  status:
                    type: integer
                    description: HTTP status code
                  details:
                    type: object
                    additionalProperties: true
                    description: Additional context about the error
              meta:
                type: object
                properties:
                  request_id:
                    type: string
                  timestamp:
                    type: string
                    format: date-time
                  docs_url:
                    type: string
                    format: uri
                    description: Link to relevant error documentation
    RateLimitedResponse:
      description: >-
        Rate limit exceeded. Wait `error.retry_after` seconds (or read the
        `Retry-After` header) before retrying. Returned when the request would
        exceed the bucket identified by `X-RateLimit-Bucket`.
      headers:
        X-RateLimit-Limit:
          description: Total request quota for the current window.
          schema:
            type: integer
            minimum: 0
        X-RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
            minimum: 0
        X-RateLimit-Reset:
          description: >-
            Absolute unix-epoch-seconds timestamp at which the current window
            resets.
          schema:
            type: integer
            minimum: 0
        X-RateLimit-Bucket:
          description: >-
            Name of the rate-limit bucket the request was bound by (e.g.
            `auth-write`, `money`, `agent-invoke`, or `custom:<max>/<window>`).
            Stripe-style — lets clients see which named cap they hit.
          schema:
            type: string
        RateLimit-Limit:
          description: >-
            draft-ietf-httpapi-ratelimit-headers no-prefix mirror of
            `X-RateLimit-Limit`. Some SDKs read only this form.
          schema:
            type: integer
            minimum: 0
        RateLimit-Remaining:
          description: >-
            draft-ietf-httpapi-ratelimit-headers no-prefix mirror of
            `X-RateLimit-Remaining`.
          schema:
            type: integer
            minimum: 0
        RateLimit-Reset:
          description: >-
            draft-ietf-httpapi-ratelimit-headers no-prefix mirror — delta
            seconds from now until the window resets (NOT epoch).
          schema:
            type: integer
            minimum: 0
        Retry-After:
          description: >-
            RFC 7231 §7.1.3 — number of seconds the client should wait before
            retrying.
          schema:
            type: integer
            minimum: 1
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                required:
                  - code
                  - message
                  - status
                  - retry_after
                properties:
                  code:
                    type: string
                    enum:
                      - RATE_LIMITED
                    description: >-
                      Always `RATE_LIMITED` — the global request-limiter 429.
                      Distinct from `RATE_LIMIT_EXCEEDED`, the live
                      per-recipient/per-tenant/per-resource frequency-cap 429
                      (not retired).
                  message:
                    type: string
                  status:
                    type: integer
                    enum:
                      - 429
                  retry_after:
                    type: integer
                    minimum: 1
                    description: >-
                      Seconds to wait before retrying. Mirrors `Retry-After`
                      header.
              meta:
                type: object
                properties:
                  request_id:
                    type: string
                  timestamp:
                    type: string
                    format: date-time
                  docs_url:
                    type: string
                    format: uri
  securitySchemes:
    Bearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Dashboard JWT token from Clerk
    ApiKey:
      type: apiKey
      name: X-API-Key
      in: header
      description: Server-to-server API key (dv_live_sk_*)

````