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

# didlogic Frame Serializer

> DidlogicFrameSerializer converts audio between Pipecat frames and the didlogic voice-stream WebSocket protocol.

> [!NOTE]
>
> **Community-maintained integration.** This service is built and
> maintained by
> [didlogic-cy](https://github.com/didlogic-cy)
> . Pipecat does not test or officially support it. Please report issues and
> request changes on the
> [source repository](https://github.com/didlogic-cy/pipecat-didlogic)
> . Learn more about
> [community integrations](https://docs.pipecat.ai/api-reference/server/services/community-integrations.md)
> .

## Overview

`DidlogicFrameSerializer` converts audio between Pipecat frames and the
[didlogic](https://didlogic.com/) voice-stream WebSocket protocol, so a Pipecat
bot can take a call on a didlogic number or be the agent leg of an outbound
call. It is used with `FastAPIWebsocketTransport`.

didlogic dials your endpoint, so the bot is the WebSocket server. One protocol
carries both directions of call: inbound, where somebody called a number pointed
at your endpoint, and outbound, placed through the Click2Call API with
`a_type: "stream"`.

> [card] [Source Repository](https://github.com/didlogic-cy/pipecat-didlogic)
>
> Source code, examples, and issues for the didlogic integration

> [card] [PyPI Package](https://pypi.org/project/pipecat-didlogic/)
>
> The `pipecat-didlogic` package on PyPI

> [card] [Protocol Reference](https://docs.didlogic.com/docs/guides/apps-developer-tools/websocket-calls)
>
> The WebSocket call protocol this serializer implements

> [card] [didlogic](https://didlogic.com/)
>
> didlogic telephony platform and account signup

## Installation

This is a community-maintained package distributed separately from `pipecat-ai`:

```bash theme={null}
uv add pipecat-didlogic
```

## Prerequisites

### didlogic Account Setup

Before using the didlogic serializer, you need:

1. **didlogic account** with voice streaming enabled. This is enabled per
   account — if the WebSocket destination type is absent from the portal, or the
   API answers `422 a_type_unsupported`, ask support to turn it on.
2. **A publicly reachable `wss://` address.** The platform dials your endpoint
   rather than the other way round, so it has to be reachable from the internet.
3. **One of:** a phone number with its destination set to your `wss://` address,
   for inbound calls; or an API token and SIP account, to place outbound calls
   through Click2Call.

### Required Environment Variables

Nothing is required by the serializer itself — it reads everything it needs off
the socket. The outbound example in the source repository uses:

* `DIDLOGIC_API_TOKEN`: your API token, for placing Click2Call calls
* `DIDLOGIC_SIP_ACCOUNT`: the SIP account the call is billed and routed against
* `PUBLIC_WSS_URL`: the public `wss://` base the platform dials back on
* `DIDLOGIC_STREAM_TOKEN`: optional, sent to your endpoint as
  `Authorization: Bearer <token>` on the WebSocket upgrade

Both examples also use `OPENAI_API_KEY`, `DEEPGRAM_API_KEY` and
`CARTESIA_API_KEY` for the speech and LLM services in the pipeline.

## Configuration

The serializer takes no required arguments. The call id, both numbers and the
direction are read from the `start` message.

**params** `DidlogicFrameSerializer.InputParams` (default: None)

Serializer configuration. Defaults to `DidlogicFrameSerializer.InputParams()`
when not provided. See [Input Parameters](#input-parameters) below.

**call\_id** `Optional[str]` (default: None)

The call's identifier, for a caller that read `start` before building the
serializer. Left unset, it is learned from `start`.

**from\_number** `Optional[str]` (default: None)

The calling party, on the same terms as `call_id`.

**to\_number** `Optional[str]` (default: None)

The called party, on the same terms as `call_id`.

**direction** `Optional[str]` (default: None)

`"inbound"` or `"outbound"`, on the same terms as `call_id`.

### Input Parameters

Configuration passed via the `params` constructor argument using
`DidlogicFrameSerializer.InputParams(...)`.

| Parameter | Type | Default | Description |
| - | - | - | - |
| `didlogic_sample_rate` | `int` | `24000` | The WebSocket wire sample rate. The platform does not negotiate this. |
| `sample_rate` | `Optional[int]` | `None` | Optional override for the Pipecat input sample rate. |
| `auto_hang_up` | `bool` | `True` | Whether an `EndFrame` or `CancelFrame` ends the call by sending `hangup`. |

> [!NOTE]
>
> didlogic uses a fixed media format: PCM16, 24 kHz, mono, base64-encoded inside
> JSON messages, one 10 ms frame per `media` message. Audio sent back may be any
> length. See the [source
> repository](https://github.com/didlogic-cy/pipecat-didlogic) for the
> authoritative, up-to-date list of parameters.

## Usage

Wire the serializer into a `FastAPIWebsocketTransport`:

```python theme={null}
from pipecat_didlogic import DidlogicFrameSerializer
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.processors.aggregators.llm_response_universal import (
    LLMContextAggregatorPair,
    LLMUserAggregatorParams,
)
from pipecat.transports.websocket.fastapi import (
    FastAPIWebsocketTransport,
    FastAPIWebsocketParams,
)

transport = FastAPIWebsocketTransport(
    websocket=websocket,
    params=FastAPIWebsocketParams(
        audio_in_enabled=True,
        audio_out_enabled=True,
        add_wav_header=False,
        serializer=DidlogicFrameSerializer(),
    ),
)

context_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
)
```

Telephony audio carries no WAV header, so `add_wav_header` must be `False`.
Everything else in the pipeline — STT, LLM, TTS — is ordinary Pipecat.

### Waiting for an outbound call to be answered

On an outbound call the platform answers the bot's leg as soon as it has sent
`start`, which is before the person's phone has rung. A bot that greets on
connect talks to a line nobody is on. The `answered` event is what says the far
end picked up, and it reaches the pipeline as an `InputTransportMessageFrame`:

```python theme={null}
from pipecat.frames.frames import InputTransportMessageFrame, LLMRunFrame
from pipecat.processors.frame_processor import FrameProcessor


class GreetWhenAnswered(FrameProcessor):
    async def process_frame(self, frame, direction):
        await super().process_frame(frame, direction)

        if (
            isinstance(frame, InputTransportMessageFrame)
            and frame.message.get("event") == "answered"
        ):
            await self.push_frame(LLMRunFrame())

        await self.push_frame(frame, direction)
```

Place it directly after `transport.input()`. On an inbound call the caller is
already on the line, so the greeting belongs right after the pipeline starts
instead.

Interruptions are handled by sending `clear`, so the platform drops audio it has
buffered but not yet played. DTMF arrives as `InputDTMFFrame`. See the
[source repository](https://github.com/didlogic-cy/pipecat-didlogic) for
complete inbound and outbound examples, including the Click2Call request.

## Compatibility

Tested with `pipecat-ai` 1.12.0. Check the
[source repository](https://github.com/didlogic-cy/pipecat-didlogic) for the
latest tested version and changelog.


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