Files
twenty/packages/twenty-apps/public/call-recorder/SETUP.md
T
nitin c862a2a43d Switch call recorder post-call transcription to Gladia with code switching (#23532)
## What

Switches the Call Recorder app's post-meeting transcription provider
from Recall.ai's built-in transcription (`recallai_async`) to Gladia
(`gladia_v2_async`), with code switching enabled so mixed-language calls
transcribe correctly.

## Changes

- `create_transcript` requests now send `provider: { gladia_v2_async: {
language_config: { code_switching: true } } }` instead of
`recallai_async` with `language_code: 'auto'`. Gladia auto-detects the
spoken language by default, and code switching re-detects it per
utterance for calls that mix languages.
- The provider payload is extracted into a
`RECALL_ASYNC_TRANSCRIPT_PROVIDER` constant so a future
provider-selection variable can slot in without touching the request
code.
- SETUP.md documents the new operational requirement: a Gladia API key
must be added in the Recall.ai dashboard (Transcription > Gladia) for
each region in use, otherwise transcripts fail.

<img width="2810" height="1656" alt="CleanShot 2026-07-30 at 15 00
27@2x"
src="https://github.com/user-attachments/assets/c702ab09-eea8-4c54-8e5a-4941951391c9"
/>

tested on twenty dev recall workspace 

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23532?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-07-30 10:42:14 +00:00

6.3 KiB

Call Recorder — Self-hosting setup

This guide is for Twenty server admins. It covers connecting Call Recorder to the recording service (Recall.ai), the environment variables it reads, and how to wire up the webhook.

If you're on Twenty Cloud, these credentials may already be configured — check with your workspace before setting them.

What you need to wire up

Call Recorder talks to Recall.ai to send bots to meetings and to receive recordings back. Two things must be configured:

  1. A Recall.ai API key (and optionally a region), so the app can schedule, update, and cancel bots.
  2. A webhook from Recall.ai back to your deployment, so the app learns when a recording is ready and can ingest it.
  3. A Gladia API key in the Recall.ai dashboard (Transcription → Gladia, per region) — transcripts fail without it.

Server variables

Set these on the application registration after installing (Settings → Applications → Call Recorder):

Server variable Required Purpose
RECALL_API_KEY Yes Recall.ai API key for the configured region; used to schedule, update, and cancel bots.
RECALL_REGION No Recall.ai region for API requests. Defaults to eu-central-1 (Europe / Frankfurt).
CALL_RECORDER_RECORDING_RETENTION_HOURS No How long Recall.ai retains the source media after processing. Defaults to 166 hours (6 days 22 hours), just under Recall's 168-hour free-storage window. Values above 168 may incur Recall storage charges. Twenty's ingested copy is unaffected.
RECALL_WEBHOOK_SECRET Yes Svix signing secret (whsec_…) used to verify incoming Recall webhooks.

Bot behavior settings (display name, join timing, lobby and leave timeouts) and the summary settings (CALL_RECORDER_SUMMARY_ENABLED, CALL_RECORDER_ADDITIONAL_SUMMARY_PROMPT) are application variables that a workspace admin tunes inside the app — not server variables.

Configuring the Recall webhook

The app exposes a server webhook route that verifies the Recall/Svix signature, advances the matching recording's lifecycle status (JOININGRECORDINGPROCESSING, or FAILED), and — once the recording finishes — ingests the audio, video, and transcript. It never moves a status backward, so out-of-order or duplicate deliveries are safe, and it returns a non-2xx response on signature failures so Recall retries.

Use this URL on your deployment, replacing only the host:

https://<your-twenty-host>/webhooks/server/9215afe6-1497-4149-a49d-e608e239bbaf

The ID is the Recall webhook logic function.

  1. In the Recall.ai dashboard, create a webhook endpoint pointing at your deployment's webhook URL, subscribed to the bot status-change, recording, and transcript events (bot.status_change, recording.done, recording.failed, transcript.done, transcript.failed). Status-change drives the lifecycle; the recording and transcript events trigger media and transcript ingestion. Subscribing to status changes alone leaves ingestion to the reconciliation backstop.
  2. Copy the endpoint's signing secret — it starts with whsec_.
  3. Set it as the RECALL_WEBHOOK_SECRET server variable on the Call Recorder application registration.
  4. Set RECALL_API_KEY (and optionally RECALL_REGION) the same way.

Recording lifecycle

Each recording is stored as a CallRecording record and moves through a lifecycle status: SCHEDULEDJOININGRECORDINGPROCESSINGCOMPLETED, or FAILED (with a failure reason when one is available).

A recording reaches COMPLETED only once both its audio and video have been ingested. Recall produces only the artifacts requested at bot creation (mixed MP3 + MP4); if processing fails, the recording is marked FAILED.

Recall.ai retains the source media for a limited window (about seven days by default) to stay inside its free-storage window. Twenty ingests and stores the video, audio, and transcript in its own storage, so they remain available after Recall's media expires.

A periodic reconciliation job runs as a safety net, pulling the latest status from Recall and keeping recordings and bots in sync even when a real-time webhook update is missed.

Troubleshooting

Symptom Likely cause Fix
No bot joined a meeting Recording was off, the event had no conference link, it wasn't synced from a connected calendar, or RECALL_API_KEY isn't set Confirm the event is on, upcoming, has a video link, and came from a synced calendar; confirm RECALL_API_KEY is set
Recording never reaches COMPLETED A Recall webhook was missed, or only one of audio/video was produced The reconciliation job pulls the latest status from Recall within a few minutes; if it is marked FAILED, inspect the bot in the Recall dashboard
Transcript empty, or marked pending/failed Recall hasn't finished async transcription yet, or transcription failed for that call Wait for the reconciliation job to ingest the transcript; a persistent failure leaves a marker in the transcript
Webhook rejected with 500 (Invalid webhook signature, Recall keeps retrying) RECALL_WEBHOOK_SECRET doesn't match the Recall endpoint's signing secret Re-copy the whsec_… secret from the Recall webhook endpoint into the RECALL_WEBHOOK_SECRET server variable
Webhook rejected with 500 (RECALL_WEBHOOK_SECRET … not set) RECALL_WEBHOOK_SECRET is not set Set it on the application registration
Bot left almost immediately No one was admitted before the lobby / empty-meeting timeout, or everyone left Adjust the lobby / empty-meeting timeouts in the app settings (see Customize the bot in the README) if they're too aggressive
Bot joined a meeting you didn't want recorded Recording is on by default Set the event's Recording field to Off; the scheduled bot is canceled
Summary stays empty after the transcript arrives Summaries are disabled, or the summarizer run failed (for example, out of AI credits) Confirm CALL_RECORDER_SUMMARY_ENABLED isn't false and the workspace has AI credits
Summary shows "No summary available." The transcript was empty or unintelligible No action needed; this is the expected outcome for low-quality transcripts