Skip to content
Skip to page content

Call lifecycle

How manual, power and parallel modes place calls, how a call progresses, what wrap-up requires, and what to do when an outcome is uncertain.

View as Markdown

One owner for queue scheduling

Manual, power and parallel

The SDK is the only owner of queue scheduling. Your interface renders snapshots and calls methods when the user acts. The transport turns backend and audio events into the SDK’s call events.

The three dialing modes
ModePlacementAfter a conversation
ManualOne explicit dial(task).Waits for wrap-up. The next call needs another action.
PowerOne queued call at a time.Waits for wrap-up, then continues the ordered queue.
ParallelUp to the requested number of calls at once.Stops filling slots when one call connects to the rep, ends the other calls in the window, then waits for wrap-up.

Start a manual call with dial(task). Start a power or parallel run with start(). Power requires one line. Parallel requires at least two.

How a parallel window resolves

  • The first connected event wins the window. The SDK stops filling slots and asks for the other calls to end.
  • connected means the rep joined that call. A destination that answers, or a live detection, does not prove the rep’s audio is attached.
  • Calls canceled because another call won become skipped with the reason parallel_loser. They are not redialed automatically within the same queue.
  • A task canceled before it was dispatched stays queued.
  • Choose any later retry list explicitly in your own workflow.

Call progression

Call statuses
creating → ringing → connected → ending → ended → wrap-up complete
    │          │          │
    └──────────┴──────────┴─→ unknown → reconcile with the existing session
  • Some stages can be skipped. A busy or unanswered call can go straight from ringing to ended.
  • An immediate rejection by the server becomes failed.
  • A request that may have been dispatched stays unknown. It is not treated as a safe failed call.
  • hangup() moves a call to ending. It stays there until a terminal event confirms the end.

Wrap-up

A call that ends without a rep conversation frees its capacity automatically. A call that ends after a rep conversation needs wrap-up:

  1. The attempt ID appears in pendingWrapUp.
  2. Your interface collects the outcome and calls completeWrapUp(attemptId, disposition).
  3. If you supplied onDisposition, the SDK awaits it. Its promise must resolve first.
  4. The SDK clears that call’s wrap-up and allows further scheduling.
Complete wrap-up
await dialer.completeWrapUp(attemptId, { disposition: 'Connected', notes: 'Example' });

Save the outcome in onDisposition

onDisposition is the boundary for a save that your application acknowledges. The callback owns persistence. There is no implicit write to Trellus or to a CRM.

An onDisposition save hook
const dialer = createDialer({
  transport,
  maxLines: 3,
  onDisposition: async ({ call, disposition }) => {
    // Your authenticated application persists the exact task/attempt outcome.
    // Resolve only when your own save contract succeeds.
    await saveCallOutcome({
      taskId: call.taskId,
      attemptId: call.attemptId,
      sessionId: call.sessionId,
      ...disposition,
    });
  },
});

saveCallOutcome is yours to implement. The package does not supply it.

  • A failed save keeps the wrap-up pending and the queue paused.
  • Repeated completeWrapUp calls while a save is pending share that save.
  • Without an onDisposition handler, completeWrapUp continues the local queue.
  • Saving a disposition, writing a CRM record, completing a task and receiving a webhook are separate actions. Each has its own acknowledgment.

Pause, hangup and teardown

  • pause() stops new placement at once and cancels work that has not been dispatched. Ringing and connected calls stay active.
  • resume() continues the last power or parallel run when no unknown call or wrap-up is unresolved.
  • hangup(attemptId) asks the transport to end one known call.
  • To stop a run, pause first, then hang up each active call.
  • On permanent teardown, await destroy(). It tries to end known calls before it disposes owned audio and subscriptions.
Disposing local audio is not proof. A server or network failure can prevent a confirmed end. Disposing local media alone does not prove that an unknown call stopped ringing.

The SDK does not persist queue runs across page reloads, and it has no cross-tab ownership lease. Do not reconnect or create a second dialer automatically while a call is uncertain.

Uncertain outcomes

A request to create a call can time out after the server accepted it. The call may be ringing. The SDK cannot tell.

Never retry an unknown call automatically. The SDK blocks continuation with an unknown call and does not redial the destination. Your application must not redial it either.
  • The same rule applies when the event stream of a known call is lost: scheduling stops and the call keeps its identity.
  • When the stream cannot be restored, the SDK reports connection_lost and keeps the call’s capacity as uncertain. It never invents an end.
  • A failure whose outcome is uncertain carries outcomeUnknown: true.
  • Reconcile the existing call through the transport and server before you continue. A custom transport can re-establish observation and emit ended once the end of the call is confirmed.
  • This preview has no public method that marks an unknown call as ended because the user dismissed a warning.
  • A create with an ambiguous outcome may not yield a sessionId.

Error codes are listed in the API reference.

Snapshots are not stored records

  • Snapshots are local observed state. They are not a durable audit log.
  • Persist the exact task and attempt mapping in your application where you need it.
  • After a confirmed create, call.sessionId is the identifier to correlate with stored call data. Keep it separate from your task ID and the SDK attempt ID.
  • Transcript updates can finish after a call ends. See transcript finality.
  • A task status of completed is local queue progress. It is not a receipt for a saved outcome.