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

# Place calls in bulk

> Place calls to multiple destinations in one request, up to **10
destinations**.

**The whole request is validated before any call is placed.** If
validation fails - an invalid number, more than 10 destinations, a
missing prompt variable - the entire request is rejected with a `400`
and **no calls are placed**.

**Once validation passes, each destination is dialed independently**, so
a bulk can return a mix of successes and failures per destination. It
returns `201` even when some - or all - destinations fail: check each
entry's `success` and `status` in `results`.

Duplicate destinations are de-duplicated; each unique number is called
once.




## OpenAPI

````yaml /api-reference/openapi.yaml post /calls/bulk
openapi: 3.1.0
info:
  title: Outbound Calls API
  version: 1.0.0-beta
  description: |
    REST API for placing AI-powered outbound calls to your contacts. Place a
    single call or a batch, personalize each call's prompt, and review the
    results.

    This reference is in **beta**: the endpoints below are live in production,
    but the reference itself is still being expanded to cover the rest of the
    platform API.
servers:
  - url: https://aipro.placetel.de/api/v1/outbound
security:
  - bearerAuth: []
tags:
  - name: Calls
    description: Place outbound calls.
  - name: Batches
    description: Review the outcome of calls you placed.
  - name: Consents
    description: Manage individual call records before they are dialed.
paths:
  /calls/bulk:
    post:
      tags:
        - Calls
      summary: Place calls in bulk
      description: |
        Place calls to multiple destinations in one request, up to **10
        destinations**.

        **The whole request is validated before any call is placed.** If
        validation fails - an invalid number, more than 10 destinations, a
        missing prompt variable - the entire request is rejected with a `400`
        and **no calls are placed**.

        **Once validation passes, each destination is dialed independently**, so
        a bulk can return a mix of successes and failures per destination. It
        returns `201` even when some - or all - destinations fail: check each
        entry's `success` and `status` in `results`.

        Duplicate destinations are de-duplicated; each unique number is called
        once.
      operationId: placeCallsBulk
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - destinations
                - agent_number
              properties:
                destinations:
                  description: >
                    Up to 10 destinations, either as objects (with optional

                    per-destination variables) or as plain E.164 strings. The
                    two

                    forms cannot be mixed.
                  oneOf:
                    - type: array
                      title: Objects
                      maxItems: 10
                      items:
                        type: object
                        required:
                          - phone
                        properties:
                          phone:
                            type: string
                            pattern: ^\+\d+$
                            examples:
                              - '+491761234567'
                          prompt_variables:
                            $ref: '#/components/schemas/PromptVariables'
                    - type: array
                      title: Plain numbers
                      maxItems: 10
                      items:
                        type: string
                        pattern: ^\+\d+$
                      examples:
                        - - '+491761234567'
                          - '+491769876543'
                agent_number:
                  type: string
                  description: >-
                    Your agent's phone number, or its SIP ID - see the
                    Introduction.
                  examples:
                    - '+4921186942846'
                caller_number:
                  type: string
                  description: Caller ID for SIP-trunk agents - see the Introduction.
                  pattern: ^\+\d+$
                prompt_variables:
                  allOf:
                    - $ref: '#/components/schemas/PromptVariables'
                  description: |
                    Shared variables applied to **every** destination. Cannot be
                    combined with per-destination `prompt_variables` in the same
                    request - use one or the other.
            examples:
              shared:
                summary: Shared variables for every destination
                value:
                  agent_number: '+4921186942846'
                  destinations:
                    - phone: '+491761234567'
                    - phone: '+491769876543'
                  prompt_variables:
                    campaign: Spring 2026
              perDestination:
                summary: Per-destination variables
                value:
                  agent_number: '+4921186942846'
                  destinations:
                    - phone: '+491761111111'
                      prompt_variables:
                        customer_name: Max Müller
                    - phone: '+491762222222'
                      prompt_variables:
                        customer_name: Anna Schmidt
      responses:
        '201':
          description: |
            Request accepted and every destination attempted. Per-destination
            outcomes are in `results`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    examples:
                      - true
                  batch_id:
                    type: string
                    format: uuid
                    description: >-
                      Groups these calls together. Use it with [Get a
                      batch](#tag/batches).
                  total:
                    type: integer
                    examples:
                      - 3
                  succeeded:
                    type: integer
                    examples:
                      - 2
                  failed:
                    type: integer
                    examples:
                      - 1
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        destination:
                          type: string
                          examples:
                            - '+491761234567'
                        success:
                          type: boolean
                        consent_id:
                          type: integer
                        call_sid:
                          type: string
                          nullable: true
                        status:
                          type: string
                          description: |
                            `initiated` on success. On failure, the reason the
                            destination was not dialed.
                          enum:
                            - initiated
                            - failed
                            - skipped
                            - locked
                            - rate_limited
                            - temporarily_unavailable
                        error:
                          type: string
                          nullable: true
                          description: Null on success.
              examples:
                partial:
                  summary: Partial failure
                  value:
                    success: true
                    batch_id: 6f1e9c2a-4d3b-4a1f-9c8e-2b7d5a0f3e11
                    total: 2
                    succeeded: 1
                    failed: 1
                    results:
                      - destination: '+491761234567'
                        success: true
                        consent_id: 48213
                        call_sid: outb_9f2c1d
                        status: initiated
                        error: null
                      - destination: '+491760000000'
                        success: false
                        consent_id: 48214
                        call_sid: null
                        status: failed
                        error: >-
                          Something went wrong. Please try again or contact
                          support.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/AgentNotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  schemas:
    PromptVariables:
      type: object
      description: |
        Values injected into the agent's prompt at call time. Every
        `{{placeholder}}` in the prompt must be supplied, or the request is
        rejected with `400`. Extra keys the prompt does not use are accepted and
        ignored.

        Key names should be lower `snake_case`. Values must be strings - send
        numbers and booleans as strings (`"3"`, `"true"`). Up to 25 keys, each
        value up to 500 characters. The `system__` and `secret__` prefixes are
        reserved.
      additionalProperties:
        type: string
        maxLength: 500
      examples:
        - customer_name: Max Mustermann
          order_id: ORD-2026-0042
    Error:
      type: object
      properties:
        success:
          type: boolean
          examples:
            - false
        error:
          type: string
          description: Description of the issue, in English.
        error_type:
          type: string
          description: Machine-readable error category, present on limit-related errors.
        detail:
          type: string
          description: Where to go next, present on rate-limit errors.
  responses:
    BadRequest:
      description: |
        Missing or invalid parameters - no call was placed. Common causes: a
        number not in E.164 format, more than 10 bulk destinations, a prompt
        placeholder with no matching variable, or mixing shared and
        per-destination `prompt_variables`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            format:
              summary: Invalid number format
              value:
                success: false
                error: >-
                  Invalid destination format. Must be E.164 international format
                  starting with '+', e.g. '+491761234567'.
            missingVariables:
              summary: Prompt placeholder not supplied
              value:
                success: false
                error: 'Missing prompt_variables keys: customer_name, order_id'
    Unauthorized:
      description: Missing or invalid API token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Outbound calling is not enabled for your account.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    AgentNotFound:
      description: No agent matches `agent_number` on your account.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            success: false
            error: Agent not found or not accessible
    UnprocessableEntity:
      description: |
        The request was understood but could not be carried out - most often
        your daily call limit is reached, or the account is locked.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: >
        Too many requests, or your outbound calling limit is reached. Retry
        after

        the period given in the `Retry-After` header, or request a higher daily

        limit from the Outbound page in your dashboard.
      headers:
        Retry-After:
          description: >-
            Seconds to wait before retrying. Present when a retry window is
            known.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            success: false
            error: Outbound rate limit exceeded. Please retry later.
            error_type: rate_limit
            detail: >-
              You have reached your outbound calling limit. Open the Outbound
              page in your dashboard to request a higher daily limit.
    ServiceUnavailable:
      description: Outbound calling is temporarily unavailable. Retry shortly.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        Generate (or rotate) your token on the **Outbound Calls** page in your
        dashboard. The token is shown once - store it securely; rotating it
        invalidates the previous token. A token only reaches your own agents and
        data.

````