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

# Call multiple phone numbers

> Learn how to initiate AI-powered phone calls to multiple numbers in a single request

## Trigger Bulk AI Phone Calls

Initiate AI-powered phone calls to multiple numbers in a single API request. This is useful for outreach campaigns or when you need to contact several people at once.

<CodeGroup>
  ```bash request.sh theme={null}
  # Basic bulk call - phone numbers only
  curl --request POST \
  --url https://api.dev.uselevers.com/api-service/v1/ai/phone-calls/action/call-bulk \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "contacts": [
      {
        "numberToCall": "+96612341234",
        "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
      },
      {
        "numberToCall": "+96612345678",
        "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
      }
    ]
  }'

  # With contact details
  curl --request POST \
  --url https://api.dev.uselevers.com/api-service/v1/ai/phone-calls/action/call-bulk \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "contacts": [
      {
        "numberToCall": "+96612341234",
        "firstName": "John",
        "lastName": "Doe",
        "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
      },
      {
        "numberToCall": "+96612345678",
        "firstName": "Jane",
        "lastName": "Smith",
        "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
      }
    ]
  }'

  # Update existing contacts if found
  curl --request POST \
  --url https://api.dev.uselevers.com/api-service/v1/ai/phone-calls/action/call-bulk \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "updateExisting": true,
    "contacts": [
      {
        "numberToCall": "+96612341234",
        "firstName": "John",
        "lastName": "Doe",
        "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
      },
      {
        "numberToCall": "+96612345678",
        "firstName": "Jane",
        "lastName": "Smith",
        "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
      }
    ]
  }'

  # With custom AI settings template
  curl --request POST \
  --url https://api.dev.uselevers.com/api-service/v1/ai/phone-calls/action/call-bulk \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "aiSettingsTemplateId": "template-uuid-here",
    "contacts": [
      {
        "numberToCall": "+96612341234",
        "firstName": "John",
        "lastName": "Doe",
        "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
      },
      {
        "numberToCall": "+96612345678",
        "firstName": "Jane",
        "lastName": "Smith",
        "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
      }
    ]
  }'

  # With prompt tags per contact for template variable substitution
  curl --request POST \
  --url https://api.dev.uselevers.com/api-service/v1/ai/phone-calls/action/call-bulk \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "aiSettingsTemplateId": "template-uuid-here",
    "contacts": [
      {
        "numberToCall": "+96612341234",
        "firstName": "John",
        "promptTags": {"amount": "$500.00", "due_date": "January 15, 2026"}
      },
      {
        "numberToCall": "+96612345678",
        "firstName": "Jane",
        "promptTags": {"amount": "$1,200.00", "due_date": "February 1, 2026"}
      }
    ]
  }'
  ```

  ```python request.py theme={null}
  import requests

  url = "https://api.dev.uselevers.com/api-service/v1/ai/phone-calls/action/call-bulk"
  headers = {"Authorization": "Bearer <token>"}

  # Basic bulk call - phone numbers only
  data = {
    "contacts": [
        {
            "numberToCall": "+96612341234",
            "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
        },
        {
            "numberToCall": "+96612345678",
            "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
        }
    ]
  }
  response = requests.post(url, json=data, headers=headers)
  print(response.text)

  # With contact details
  data = {
    "contacts": [
        {
            "numberToCall": "+96612341234",
            "firstName": "John",
            "lastName": "Doe",
            "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
        },
        {
            "numberToCall": "+96612345678",
            "firstName": "Jane",
            "lastName": "Smith",
            "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
        }
    ]
  }
  response = requests.post(url, json=data, headers=headers)
  print(response.text)

  # Update existing contacts if found
  data = {
    "updateExisting": True,
    "contacts": [
        {
            "numberToCall": "+96612341234",
            "firstName": "John",
            "lastName": "Doe",
            "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
        },
        {
            "numberToCall": "+96612345678",
            "firstName": "Jane",
            "lastName": "Smith",
            "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
        }
    ]
  }
  response = requests.post(url, json=data, headers=headers)
  print(response.text)

  # With custom AI settings template
  data = {
    "aiSettingsTemplateId": "template-uuid-here",
    "contacts": [
        {
            "numberToCall": "+96612341234",
            "firstName": "John",
            "lastName": "Doe",
            "metadata": {"project_id": "proj_123", "extra_id": "custom_id_456"}
        },
        {
            "numberToCall": "+96612345678",
            "firstName": "Jane",
            "lastName": "Smith",
            "metadata": {"project_id": "proj_124", "extra_id": "custom_id_789"}
        }
    ]
  }
  response = requests.post(url, json=data, headers=headers)
  print(response.text)

  # With prompt tags per contact for template variable substitution
  data = {
    "aiSettingsTemplateId": "template-uuid-here",
    "contacts": [
        {
            "numberToCall": "+96612341234",
            "firstName": "John",
            "promptTags": {"amount": "$500.00", "due_date": "January 15, 2026"}
        },
        {
            "numberToCall": "+96612345678",
            "firstName": "Jane",
            "promptTags": {"amount": "$1,200.00", "due_date": "February 1, 2026"}
        }
    ]
  }
  response = requests.post(url, json=data, headers=headers)
  print(response.text)
  ```
</CodeGroup>

### Request Fields

<ResponseField name="contacts" type="array" required>
  Array of contact objects, each containing at minimum a `numberToCall`. Each contact can optionally include `firstName`, `lastName`, `metadata`, and `promptTags` for personalized prompt template substitution. For each contact in the list, we automatically search for any existing contact with that phone number to avoid creating duplicates.

  <Expandable title="Contact Object Fields" defaultOpen>
    <ResponseField name="numberToCall" type="string" required>
      Phone number to call (1-100 characters)
    </ResponseField>

    <ResponseField name="firstName" type="string">
      Contact's first name
    </ResponseField>

    <ResponseField name="lastName" type="string">
      Contact's last name
    </ResponseField>

    <ResponseField name="metadata" type="object">
      Optional field for sending extra payload data with each call. This metadata will be included in webhook responses as `requestMetadata`, allowing you to track additional context like `project_id`, `extra_id`, or any custom key-value pairs relevant to your application.

      <Expandable title="Example" defaultOpen>
        ```json theme={null}
        {
          "project_id": "proj_123",
          "extra_id": "custom_id_456"
        }
        ```
      </Expandable>
    </ResponseField>

    <ResponseField name="promptTags" type="object">
      Optional key-value pairs for template variable substitution in the system prompt for this specific contact. Each key maps to a placeholder in your prompt template (e.g., \{\{amount}}), and the value replaces it before the call starts. Only string values are supported.

      Since each contact in a bulk request can have different `promptTags`, you can personalize the AI conversation per contact (e.g., different amounts owed, due dates, or account-specific instructions).

      This is separate from `metadata` — `metadata` is stored on the call log and included in webhooks, while `promptTags` is consumed at call time to populate the system prompt.

      <>
        <Expandable title="How template substitution works" defaultOpen>
          Your system prompt template uses double-curly-brace placeholders (e.g., \{\{amount}}):

          ```plain theme={null}
          You are a collections agent. The customer owes {{amount}} due by {{due_date}}.
          Be professional and offer payment plan options if the customer cannot pay in full.
          ```

          With this request:

          ```json theme={null}
          {
            "promptTags": {
              "amount": "$500.00",
              "due_date": "January 15, 2026"
            }
          }
          ```

          The AI receives:

          ```plain theme={null}
          You are a collections agent. The customer owes $500.00 due by January 15, 2026.
          Be professional and offer payment plan options if the customer cannot pay in full.
          ```
        </Expandable>

        <Expandable title="Using promptTags for guardrails">
          You can also inject additional instructions dynamically:

          ```json theme={null}
          {
            "promptTags": {
              "amount": "$1,200.00",
              "due_date": "February 1, 2026",
              "guardrail": "Do not mention late fees. If the customer asks about penalties, redirect to their account portal."
            }
          }
          ```
        </Expandable>
      </>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="updateExisting" type="boolean" default="false">
  When `true`, if an existing contact is found with the provided `numberToCall`, their `firstName` and `lastName` will be updated with the provided values. If no contact is found with that phone number, a new contact will be created with the provided details.
</ResponseField>

<ResponseField name="aiSettingsTemplateId" type="string (UUID)">
  Customize how the AI behaves during all calls in this batch using your prompt templates from the Levers app. If not specified, the default template will be used. This setting applies to all contacts in the request.
</ResponseField>
