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

# Handling Calls

> Answer inbound calls on Edge Compute via Call Control — your function is the Call Control app webhook; answer the call and play audio.

Inbound voice is webhook-driven through Call Control: Telnyx POSTs call events to your Call Control application's webhook, and your Edge Compute function is that webhook. On `call.initiated` you answer the call; on `call.answered` you play audio.

## 1. Write the handler

```ts theme={null}
// index.ts
import * as http from "node:http";
import { env } from "@telnyx/edge-runtime";

const port = Number(process.env.PORT ?? 8080);
const AUDIO_URL = "https://YOUR-HOST/song.mp3"; // a reachable HTTPS mp3/wav you have rights to

function body(req: http.IncomingMessage): Promise<string> {
  return new Promise((r) => {
    let b = "";
    req.on("data", (c) => (b += c));
    req.on("end", () => r(b));
  });
}

http.createServer(async (req, res) => {
  if (req.method === "GET") { res.writeHead(200).end(); return; } // health

  // parse the inbound webhook through the binding
  const evt = env.MY_TELNYX.webhooks.unsafeUnwrap<{ data: any }>(await body(req)).data;
  const id = evt?.payload?.call_control_id;

  if (evt?.event_type === "call.initiated" && id) {
    await env.MY_TELNYX.calls.actions.answer(id, {});
  } else if (evt?.event_type === "call.answered" && id) {
    await env.MY_TELNYX.calls.actions.startPlayback(id, { audio_url: AUDIO_URL });
  }

  res.writeHead(200);
  res.end();
}).listen(port);
```

Declare the binding in `func.toml`:

```toml theme={null}
[telnyx]
binding = "MY_TELNYX"
```

## 2. Ship

```bash theme={null}
telnyx-edge ship
```

## 3. Point a Call Control app at it

```bash theme={null}
# create a Call Control app whose webhook is your function
curl -X POST https://api.telnyx.com/v2/call_control_applications \
  -H "Authorization: Bearer $TELNYX_API_KEY" -H "Content-Type: application/json" \
  -d '{"application_name":"voice-demo","webhook_event_url":"https://YOUR-FUNC.telnyxcompute.com"}'

# route your number to that app (connection_id = the app id from the response)
curl -X PATCH https://api.telnyx.com/v2/phone_numbers/YOUR-NUMBER-ID \
  -H "Authorization: Bearer $TELNYX_API_KEY" -H "Content-Type: application/json" \
  -d '{"connection_id":"YOUR-CALL-CONTROL-APP-ID"}'
```

## 4. Test

Call the number from any phone. The function answers and plays your audio.

<Note>
  `audio_url` must be a publicly reachable HTTPS `.mp3` or `.wav`. The flow is two events — `call.initiated` (answer) then `call.answered` (play) — so handle both. To loop, hang up, or chain more actions, respond to later events (`call.playback.ended`, `call.hangup`) the same way.
</Note>

## Time-of-day routing

To route callers to a person instead of playing audio, replace both event branches in step 1 with a single `transfer` on `call.initiated` — Telnyx dials the destination and bridges the caller when it answers, so there's nothing to do on `call.answered`:

```ts theme={null}
const OFFICE = "+13125550100"; // business hours
const ON_CALL = "+13125550199"; // after hours

function businessHours(): boolean {
  const hour = Number(
    new Intl.DateTimeFormat("en-US", {
      timeZone: "America/New_York",
      hour: "numeric",
      hourCycle: "h23",
    }).format(new Date()),
  );
  return hour >= 9 && hour < 17;
}

if (evt?.event_type === "call.initiated" && id) {
  await env.MY_TELNYX.calls.actions.transfer(id, {
    to: businessHours() ? OFFICE : ON_CALL,
  });
}
```

If the transfer fails, you get a `call.hangup` webhook for the destination leg and the caller's leg stays active — transfer to an alternate number or answer and play a message.
