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

# Quickstart

> Receive or place a FaceTime call with your own LiveKit agent.

## What to have ready

* A Chert project and provisioned FaceTime line, including its handle and line ID.
* Your LiveKit project, WebSocket URL, and server-side API key and secret.
* A backend that prepares a room and mints separate tokens for your agent and Chert's bridge.
* An agent that publishes audio and consumes the caller's audio. For inbound video, also publish and subscribe to video.
* A person ready to place or answer the test call. Each line handles one active call at a time.

Chert operates the FaceTime endpoint; you do not need to install the open-source connector. Inbound calls need an acceptance webhook. Outbound calls use an authenticated API request and require an outbound-enabled line.

<a id="keys" />

## 1. Get your project key

Open **Developer → Project API keys**. Create a key with `facetime:write` for create/end and `facetime:read` for status/events. Store it on your backend and copy the Project ID.

```bash theme={null}
export CHERT_API_KEY="<your-project-api-key>"
export PROJECT_ID="<your-project-uuid>"
export BASE=https://facetime.trychert.com/api
```

<a id="connectivity" />

## 2. Choose your line

```bash theme={null}
curl "$BASE/v1/lines" \
  -H "Authorization: Bearer $CHERT_API_KEY" \
  -H "X-Chert-Project-Id: $PROJECT_ID"
```

Confirm the line's worker is accepting calls with fresh readiness in **Workers & Lines**. For outbound, confirm that this line is enabled for outbound audio, then use its exact ID as `line_id`. Chert does not fall back to another line when it is unavailable.

<a id="room" />

## 3. Prepare your LiveKit agent

Run your agent in your room with exactly one eligible, unmuted audio publication. Mint a separate, room-scoped bridge token with join, publish, and subscribe grants and an identity distinct from your agent. See the [token requirements](/facetime/bring-your-own-room#token).

For outbound, keep the agent silent until `bridge_ready`. The bridge token needs more than 90 seconds remaining at allocation and an issued lifetime of at most two hours.

## 4. Choose a calling direction

<Tabs>
  <Tab title="Inbound">
    <a id="webhook" />

    Set the line to `customer_decides` with no default Assistant. Configure its HTTPS Integration URL. If you enable webhook signing, store the signing secret on your backend and verify incoming signatures.

    On `call.incoming`, return an accept response within the decision deadline (five seconds by default):

    ```json theme={null}
    {
      "action": "accept",
      "livekit_url": "wss://your-project.livekit.cloud",
      "participant_token": "<room-scoped bridge JWT>",
      "remote_participant_identity": "your-agent"
    }
    ```

    Call your provisioned handle using FaceTime Audio, or FaceTime Video on a video-enabled line. The [BYOR guide](/facetime/bring-your-own-room#inbound) covers the incoming event and decline response.
  </Tab>

  <Tab title="Outbound">
    Your backend sends the request; no incoming-decision webhook is needed. Use audio only and save this body as a protected local file named `outbound-call.json`, replacing the placeholders:

    ```json theme={null}
    {
      "direction": "outbound",
      "mode": "customer_managed",
      "line_id": "<your-line-uuid>",
      "destination": "recipient@example.com",
      "destination_type": "email",
      "media": { "audio": true, "video": false },
      "livekit_url": "wss://your-project.livekit.cloud",
      "participant_token": "<room-scoped bridge JWT>",
      "remote_participant_identity": "your-agent"
    }
    ```

    Send it with a unique create key (8–200 characters):

    ```bash theme={null}
    curl --fail-with-body "$BASE/v1/calls" \
      -H "Authorization: Bearer $CHERT_API_KEY" \
      -H "X-Chert-Project-Id: $PROJECT_ID" \
      -H "Idempotency-Key: $CREATE_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @outbound-call.json
    ```

    Set `CREATE_KEY` before running the command. HTTP `201` means allocated, not answered. Save `data.id` as `CALL_ID`. Retry an uncertain request with the same body and key; do not create a new attempt automatically.

    Poll `GET /api/v1/calls/<call ID>/events` with the same project headers. Start the greeting once on `bridge_ready`, or the corresponding outbound `call.started` webhook. Room join or an `active` status alone is insufficient. Ignore activation after termination.

    See [Outbound](/facetime/outbound) for phone destinations, line selection, and the full flow.
  </Tab>
</Tabs>

<a id="call" />

## 5. Verify the call and cleanup

Confirm clear two-way audio. For inbound video, also confirm that each side sees the other's current video. Subscribe to the bridge's `facetime-remote-audio` track and, when enabled, `facetime-remote-video`.

Hang up from either end, or end through the API using the call ID and a unique end key (8–200 characters):

```bash theme={null}
curl --fail-with-body -X POST "$BASE/v1/calls/$CALL_ID/end" \
  -H "Authorization: Bearer $CHERT_API_KEY" \
  -H "X-Chert-Project-Id: $PROJECT_ID" \
  -H "Idempotency-Key: $END_KEY" \
  -H "Content-Type: application/json" \
  --data-binary '{}'
```

Set `END_KEY` before running the command. HTTP `202` acknowledges the request. Check that FaceTime ends, the call becomes terminal, and the line becomes available again. Your backend must also release its agent and room resources. See [Calls API](/facetime/calls-api).
