Skip to main content
Start with the credential-free lifecycle recipe to understand intents without placing a call. To connect a real carrier, choose its adapter, then supply your application’s persistence and authorization.

Create the service

This complete factory creates a service around one or more configured providers. It does not dial until your application calls create().
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.
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 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 and implement the carrier’s media protocol or use LiveKit media.