> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Gegenereerde audio versturen via Twilio

> **Note**
>
> **Handleiding** · Hierbij wordt ervan uitgegaan dat je de [ElevenAPI quickstart](/docs/nl/eleven-api/quickstart) hebt voltooid en een Twilio-account hebt.

In deze handleiding leer je hoe je met Twilio en ElevenLabs een door AI gegenereerd bericht via een telefoongesprek verstuurt. Hiermee kun je hoogwaardige spraakberichten rechtstreeks naar je bellers sturen.

## Accounts maken bij Twilio en ngrok

We gebruiken Twilio en ngrok voor deze handleiding, dus maak daar accounts aan.

* [twilio.com](https://www.twilio.com)
* [ngrok.com](https://ngrok.com)

## De server maken met Express

### Je project initialiseren

Maak een nieuwe map voor je project

```
mkdir elevenlabs-twilio
cd elevenlabs-twilio
npm init -y
```

### Afhankelijkheden installeren

```
npm install @elevenlabs/elevenlabs-js express express-ws twilio
```

### Dev-afhankelijkheden installeren

```
npm i @types/node @types/express @types/express-ws @types/ws dotenv tsx typescript
```

### Je bestanden maken

```ts
// src/app.ts
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";
import express, { Response } from "express";
import ExpressWs from "express-ws";
import { Readable } from "stream";
import VoiceResponse from "twilio/lib/twiml/VoiceResponse";
import { type WebSocket } from "ws";

const app = ExpressWs(express()).app;
const PORT: number = parseInt(process.env.PORT || "5000");

const elevenlabs = new ElevenLabsClient();
const voiceId = "aMSt68OGf4xUZAnLpTU8";
const outputFormat = "ulaw_8000";
const text = "This is a test. You can now hang up. Thank you.";

function startApp() {
  app.post("/call/incoming", (_, res: Response) => {
    const twiml = new VoiceResponse();

    twiml.connect().stream({
      url: `wss://${process.env.SERVER_DOMAIN}/call/connection`,
    });

    res.writeHead(200, { "Content-Type": "text/xml" });
    res.end(twiml.toString());
  });

  app.ws("/call/connection", (ws: WebSocket) => {
    ws.on("message", async (data: string) => {
      const message: {
        event: string;
        start?: { streamSid: string; callSid: string };
      } = JSON.parse(data);

      if (message.event === "start" && message.start) {
        const streamSid = message.start.streamSid;
        const response = await elevenlabs.textToSpeech.convert(voiceId, {
          modelId: "eleven_flash_v2_5",
          outputFormat: outputFormat,
          text,
        });

        const readableStream = Readable.from(response);
        const audioArrayBuffer = await streamToArrayBuffer(readableStream);

        ws.send(
          JSON.stringify({
            streamSid,
            event: "media",
            media: {
              payload: Buffer.from(audioArrayBuffer as any).toString("base64"),
            },
          })
        );
      }
    });

    ws.on("error", console.error);
  });

  app.listen(PORT, () => {
    console.log(`Local: http://localhost:${PORT}`);
    console.log(`Remote: https://${process.env.SERVER_DOMAIN}`);
  });
}

function streamToArrayBuffer(readableStream: Readable) {
  return new Promise((resolve, reject) => {
    const chunks: Buffer[] = [];

    readableStream.on("data", (chunk) => {
      chunks.push(chunk);
    });

    readableStream.on("end", () => {
      resolve(Buffer.concat(chunks).buffer);
    });

    readableStream.on("error", reject);
  });
}

startApp();
```

```env
# .env
SERVER_DOMAIN=
ELEVENLABS_API_KEY=
```

## De code begrijpen

### Het binnenkomende gesprek afhandelen

Wanneer je je nummer belt, doet Twilio een POST-request naar je endpoint op `/call/incoming`.
Vervolgens gebruiken we twiml.connect om Twilio te vertellen dat we het gesprek via onze websocket willen afhandelen door de URL in te stellen op ons endpoint `/call/connection`.

```ts
function startApp() {
  app.post('/call/incoming', (_, res: Response) => {
    const twiml = new VoiceResponse();

    twiml.connect().stream({
      url: `wss://${process.env.SERVER_DOMAIN}/call/connection`,
    });

    res.writeHead(200, { 'Content-Type': 'text/xml' });
    res.end(twiml.toString());
  });
```

### De tekst-naar-spraak maken

Hier luisteren we naar berichten die Twilio naar ons websocket-endpoint stuurt. Wanneer we een `start`-berichtgebeurtenis ontvangen, genereren we audio met de ElevenLabs [TypeScript SDK](https://github.com/elevenlabs/elevenlabs-js).

```ts
  app.ws('/call/connection', (ws: WebSocket) => {
    ws.on('message', async (data: string) => {
      const message: {
        event: string;
        start?: { streamSid: string; callSid: string };
      } = JSON.parse(data);

      if (message.event === 'start' && message.start) {
        const streamSid = message.start.streamSid;
        const response = await elevenlabs.textToSpeech.convert(voiceId, {
          modelId: 'eleven_flash_v2_5',
          outputFormat: outputFormat,
          text,
        });
```

### Het bericht versturen

Wanneer we de audio van ElevenLabs ontvangen, zetten we deze om naar een array buffer en sturen we de audio via de websocket naar Twilio.

```ts
const readableStream = Readable.from(response);
const audioArrayBuffer = await streamToArrayBuffer(readableStream);

ws.send(
  JSON.stringify({
    streamSid,
    event: "media",
    media: {
      payload: Buffer.from(audioArrayBuffer as any).toString("base64"),
    },
  })
);
```

## Ngrok naar je applicatie laten verwijzen

Twilio vereist een openbaar toegankelijke URL. We gebruiken ngrok om de lokale poort van onze applicatie door te sturen en als openbare URL beschikbaar te maken.

Voer de volgende opdracht uit in je terminal:

```
ngrok http 5000
```

Kopieer het ngrok-domein (zonder https\://) om in je omgevingsvariabelen te gebruiken.

![](/docs/_fern-img/830a701ecee4b2bd32f44a891806a91e00f27dcf263c5917fa20a91a3353d6a1.webp)

## Je omgevingsvariabelen bijwerken

Werk het `.env`-bestand bij met je ngrok-domein en ElevenLabs API-sleutel.

```
# .env
SERVER_DOMAIN=*******.ngrok.app
ELEVENLABS_API_KEY=*************************
```

## De applicatie starten

Voer de volgende opdracht uit om de app te starten:

```
npm run dev
```

## Twilio instellen

Volg de handleidingen van Twilio om een nieuw nummer te maken. Nadat je je nummer hebt gemaakt, ga je naar het tabblad "Configure" in Phone Numbers -> Manage -> Active numbers

Voer in het gedeelte "A call comes in" de volledige URL naar je applicatie in (zorg dat je het pad `/call/incoming` toevoegt):

Bijv. https\://**\*\*\***&#x6E;grok.app/call/incoming

![](/docs/_fern-img/8f57f550bca8ac451980d98482ff5877c4f8fac30035e712cd0375a6527686ff.webp)

## Bellen

Bel je nummer. Je hoort een bericht met de ElevenLabs-stem.

## Tips voor deployment naar productie

Wanneer je de applicatie in productie uitvoert, moet je de omgevingsvariabele `SERVER_DOMAIN` instellen op die van je server. Werk ook de URL in Twilio bij zodat deze naar je productieserver verwijst.

## Conclusie

Je hebt nu een basiskennis van het integreren van Twilio met ElevenLabs-stemmen. Als je nog vragen hebt of suggesties om deze blogpost te verbeteren, klik dan gerust hieronder op de knop "Suggest edits" of "Raise issue".