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

# Set up outbound calls

> Configure a route and call service with explicit identity, authorization, and persistence.

Start with the [credential-free lifecycle recipe](/examples/telephony) to understand intents without placing a call. To connect a real carrier, choose its [adapter](/voice/telephony#adapters), then supply your application's persistence and authorization.

## Create the service

```bash theme={null}
npm install @agentium/core@4.0.0
```

This complete factory creates a service around one or more configured providers. It does not dial until your application calls `create()`.

```typescript theme={null}
import {
  OutboundCallService,
  type OutboundCallProvider,
  type CallIntentStore,
  type CallAuthorization,
} from "@agentium/core/telephony";

export function createCallService(
  providers: readonly OutboundCallProvider[],
  store: CallIntentStore,
  authorize: (request: CallAuthorization) => Promise<boolean>,
) {
  return new OutboundCallService({ providers, store, authorize });
}
```

Your host authenticates the user, selects `tenantId` and `userId`, and checks the destination, caller ID, calling permission, and spending policy. A value supplied in a request body is not a verified identity.

## Send one business intent

The following helper accepts an authenticated identity and an intent ID persisted by your application. **Calling it with a live provider places a real outbound call.**

```typescript theme={null}
import type { CallIdentity, OutboundCallService } from "@agentium/core/telephony";

export async function dial(
  calls: OutboundCallService,
  identity: CallIdentity,
  intentId: string,
  routeId: string,
  to: string,
  from: string,
) {
  const record = await calls.create({ identity, intentId, routeId, to, from });
  return { creation: record.creation, status: record.snapshot?.status };
}
```

Reuse the same `intentId` only for the same business operation and identical payload. A duplicate returns the existing record; changed input conflicts. The service claims a `dispatching` intent before contacting the provider.

## Store and track the result

For multiple workers, implement `CallIntentStore` with atomic, durable `claim` and revision-based `compareAndSet`. Use a unique key on `(tenantId, intentId)` and preserve immutable request, digest, and provider fields. Never expire an unresolved intent: losing it can permit duplicate dialing. `InMemoryCallIntentStore` is only for a single-process demonstration.

Use `get(identity, intentId)` to refresh provider status, `getIntent()` to inspect stored state, and `hangup()` to request a remote hangup. All operations recheck authorization. See [callbacks and recovery](/telephony/callbacks) for timeouts and uncertain outcomes.

## Connect the voice

The carrier answer route or SIP room must connect to your application's audio handling. Call control does not automatically attach a speech model. Choose [native realtime or a streaming pipeline](/voice/adapters) and implement the carrier's media protocol or use [LiveKit media](/voice/livekit).


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