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

# Dispatch outbound calls

> Start an outbound call from the dashboard or API, pass per-call values, or process a contact list.

Dispatching a call tells an agent to dial a number now. The agent places the
call through its outbound connection, so the caller ID comes from that
connection's pool rather than from the request.

## Prerequisites

Before you begin:

* An outbound connection attached to the agent. Without one, dispatch fails.
  See [Place calls from an agent](/guides/agents/telephony/outbound).
* The agent's ID, from the create response or the project page.
* An SLNG key for the API path. See
  [How to set up](/guides/get-started/quickstart).

## Place one call

<Tabs>
  <Tab title="Dashboard" icon="monitor">
    <Steps>
      <Step title="Open the test panel">
        Open the project and click **Test agent**. The panel opens on the
        **Web session** channel.

        <Frame caption="The Test agent panel. Switch the channel to Outbound call.">
          <img src="https://mintcdn.com/slng-new-docs/_MURdOw87SJsfVag/heroshots/telephony-dispatch-step-1.png?fit=max&auto=format&n=_MURdOw87SJsfVag&q=85&s=f0adc3ad8045332c0d2f11d6f0d5ee6b" alt="The Test agent panel with the Channel set to Web session and an Outbound call option" width="2560" height="1600" data-path="heroshots/telephony-dispatch-step-1.png" />
        </Frame>
      </Step>

      <Step title="Switch to Outbound call">
        Set the **Channel** to **Outbound call**. A **Number to call** field
        appears. If the panel says telephony setup is needed, the agent has no
        outbound connection attached.

        <Frame caption="The Outbound call channel, with a field for the number to call.">
          <img src="https://mintcdn.com/slng-new-docs/_MURdOw87SJsfVag/heroshots/telephony-dispatch-step-2.png?fit=max&auto=format&n=_MURdOw87SJsfVag&q=85&s=bc68a1889726e881c6a49060102fa165" alt="The Test agent panel in outbound call mode showing the Number to call field" width="2560" height="1600" data-path="heroshots/telephony-dispatch-step-2.png" />
        </Frame>
      </Step>

      <Step title="Enter the number and start the call">
        Enter the destination under **Number to call** in E.164 format and click
        **Start call**. The agent dials while you watch the transcript.

        <Frame caption="A number entered and ready. Start call places the outbound call.">
          <img src="https://mintcdn.com/slng-new-docs/_MURdOw87SJsfVag/heroshots/telephony-dispatch-step-3.png?fit=max&auto=format&n=_MURdOw87SJsfVag&q=85&s=f0ae911e1b6ac99fdc0998c08b422bfd" alt="The Test agent panel with a number entered and the Start call button" width="2560" height="1600" data-path="heroshots/telephony-dispatch-step-3.png" />
        </Frame>
      </Step>
    </Steps>

    Use this to check an agent before you automate it. For anything repeated,
    use the API.
  </Tab>

  <Tab title="API" icon="code">
    Send the destination number to the agent's `calls` endpoint.

    ```bash Request theme={null}
    curl -X POST https://api.agents.slng.ai/v1/agents/$AGENT_ID/calls \
      -H "Authorization: Bearer $SLNG_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "phone_number": "+14155551234" }'
    ```

    ```json Response theme={null}
    {
      "call_id": "7c1d9f02-4b6a-4e18-9d3c-2a5f8b0e6417",
      "message": "Call dispatched successfully"
    }
    ```

    The response returns as soon as the call is dispatched, not when it is
    answered. Keep the `call_id` to look the call up later.
  </Tab>
</Tabs>

## Personalize each call

If the agent's system prompt or greeting uses `{{variable}}` placeholders, pass
values for them in `arguments`. They override any defaults set on the agent, and
the rendered prompt is stored with the call record.

```bash Request theme={null}
curl -X POST https://api.agents.slng.ai/v1/agents/$AGENT_ID/calls \
  -H "Authorization: Bearer $SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "arguments": {
      "customer_name": "Bruce",
      "company_name": "Wayne Enterprises"
    }
  }'
```

Values are strings, and the payload is bounded:

| Limit               | Value           |
| ------------------- | --------------- |
| Keys per request    | 32              |
| Key length          | 64 characters   |
| Value length        | 1024 characters |
| All values combined | 8192 characters |

The request rejects anything it does not recognize, so a misspelled field name
returns an error rather than being ignored.

## Dispatch calls from a list

The API accepts one call per request. When you process a contact list, control
the request rate and retry `429 Too Many Requests` responses. Limiting concurrent
requests does not control how many requests you send within the rate-limit
window.

This example sends calls sequentially, waits between contacts, and honors the
`Retry-After` header before retrying a rate-limited request. Set
`DISPATCH_INTERVAL_MS` for the rate limit applied to your account.

```javascript dispatch-list.mjs theme={null}
const BASE_URL = "https://api.agents.slng.ai";

const wait = (milliseconds) =>
  new Promise((resolve) => setTimeout(resolve, milliseconds));

async function dispatchCall(agentId, phoneNumber, args = {}, maxRetries = 3) {
  for (let attempt = 0; ; attempt += 1) {
    const response = await fetch(`${BASE_URL}/v1/agents/${agentId}/calls`, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.SLNG_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ phone_number: phoneNumber, arguments: args }),
    });

    if (response.ok) return response.json();

    if (response.status === 429 && attempt < maxRetries) {
      const retryAfter = Number(response.headers.get("retry-after"));
      await wait((Number.isFinite(retryAfter) ? retryAfter : 1) * 1000);
      continue;
    }

    const error = await response.json().catch(() => ({}));
    const detail =
      typeof error.detail === "string"
        ? error.detail
        : JSON.stringify(error.detail ?? error);
    throw new Error(detail || `Dispatch failed: ${response.status}`);
  }
}

async function dispatchList(agentId, contacts, intervalMs = 1000) {
  const results = [];

  for (const [index, contact] of contacts.entries()) {
    try {
      const value = await dispatchCall(agentId, contact.phone, contact.args);
      results.push({ phone: contact.phone, status: "fulfilled", value });
    } catch (error) {
      const reason = error instanceof Error ? error.message : String(error);
      results.push({ phone: contact.phone, status: "rejected", reason });
    }

    if (index < contacts.length - 1) await wait(intervalMs);
  }

  return results;
}

const contacts = [
  { phone: "+14155551234", args: { customer_name: "Bruce" } },
  { phone: "+14155559876", args: { customer_name: "Lucius" } },
];

if (!process.env.SLNG_API_KEY || !process.env.AGENT_ID) {
  throw new Error("Set SLNG_API_KEY and AGENT_ID before running this script.");
}

const intervalMs = Number(process.env.DISPATCH_INTERVAL_MS ?? 1000);
if (!Number.isFinite(intervalMs) || intervalMs < 0) {
  throw new Error("DISPATCH_INTERVAL_MS must be a non-negative number.");
}

const results = await dispatchList(process.env.AGENT_ID, contacts, intervalMs);
console.dir(results, { depth: null });
```

Run the script with your key and agent ID:

```bash theme={null}
SLNG_API_KEY=your-key AGENT_ID=your-agent-id node dispatch-list.mjs
```

A failed contact does not stop the list. Review entries with a `rejected`
status, fix the cause, then retry only those contacts.

## Follow the call

Each dispatched call becomes a record you can read back: its status, the
arguments you passed, the prompt after those arguments were filled in, and the
transcript once the call ends. See
[Observability and usage](/guides/usage-and-billing).

## Next steps

* [Receive calls on a number](/guides/agents/telephony/inbound) if callers also
  dial the agent.
