Agent Quickstarts

Quick copy/pasteable instructions for agents to implement transcription with bots

Create a bot and retrieve the final transcript after the meeting ends

# Recall.ai quickstart for agents: create a bot and retrieve the final transcript after the meeting ends

This quickstart is for agents building a Recall.ai integration on the v1.11 API that:

- sends a bot to a meeting
- retrieves the **final transcript after the meeting ends**
- returns both:
  - the **original transcript payload**
  - a **human-readable sentence-by-sentence transcript**

By default, this quickstart builds:

- a **direct Create Bot** flow
- a **webhook-driven completion flow** to track bot, recording, and transcript status
- **automatic transcript generation** by defining transcript configuration in the Create Bot request
- a **transcript retrieval helper** that:
  - looks up the stored transcript state
  - retrieves the transcript when it is done
  - returns the transcript failure `sub_code` when it failed
  - returns both the original transcript and a readable transcript
- an **optional endpoint** that calls the same transcript retrieval helper

This quickstart is intentionally for **post-meeting transcript retrieval**, not real-time transcription.

It can be used in any environment, but before going to production, if the workflow usually knows the meeting URL and start time ahead of time, you must implement **scheduled bots** separately. This quickstart does **not** cover scheduling.

Do **not** use this quickstart for:

- live transcript UX during the meeting
- real-time transcript streaming
- voice agents that need transcript chunks while the meeting is still happening
- scheduled bot workflows
- calendar-driven bot scheduling
- or any other real-time transcription or scheduling-specific use case

If the human asks for real-time transcription, the agent must say this quickstart does not apply, point them to [Bot Real-Time Transcription](https://docs.recall.ai/docs/bot-real-time-transcription), and abort this implementation.

If the human asks for scheduled bots or calendar-driven scheduling, the agent must say this quickstart does not cover scheduling, point them to [Creating and scheduling bots](https://docs.recall.ai/docs/creating-and-scheduling-bots), and abort this implementation.

---

## Outline

- [1. Use-case fit](#1-use-case-fit)
- [2. Mandatory acknowledgement](#2-mandatory-acknowledgement)
- [3. Human-required blocking setup](#3-human-required-blocking-setup)
- [4. Default implementation choices](#4-default-implementation-choices)
- [5. Minimal state model](#5-minimal-state-model)
- [6. Critical rules](#6-critical-rules)
- [7. Step 1: create the webhook endpoint first](#7-step-1-create-the-webhook-endpoint-first)
- [8. Step 2: create the bot](#8-step-2-create-the-bot)
- [9. Step 3: handle bot, recording, and transcript webhooks](#9-step-3-handle-bot-recording-and-transcript-webhooks)
- [10. Step 4: implement the transcript retrieval helper](#10-step-4-implement-the-transcript-retrieval-helper)
- [11. Required failure handling](#11-required-failure-handling)
- [12. Verification checklist](#12-verification-checklist)
- [13. Minimal implementation outline](#13-minimal-implementation-outline)
- [14. Required human-facing explanations](#14-required-human-facing-explanations)

---

## 1. Use-case fit

Use this quickstart when the human wants all of the following:

- a Recall.ai bot joins a meeting
- the app gets the **final transcript after the meeting ends**
- the app does **not** need transcript chunks during the meeting
- the app is able to rely on **webhooks**
- the app wants to retrieve the final transcript only after Recall marks it done
- the app wants either:
  - a function that can retrieve the transcript after completion, or
  - an endpoint that returns the transcript after completion

This quickstart uses **automatic transcript generation** by including transcript configuration in the Create Bot request. There is **no separate “start transcription” step** in this guide.

Stop and use a different guide if the human says any of the following:

- “I need transcript chunks during the call”
- “I need live captions”
- “I need a websocket or realtime webhook transcript stream”
- “I want to fetch transcript-so-far while the meeting is still in progress”
- “I need scheduled bots”
- “I need calendar integration”
- or any other real-time transcription or scheduling-specific use case

---

## 2. Mandatory acknowledgement

Do **not** start implementation until the human acknowledges the following.

Tell the human:

```text
This quickstart uses direct bot creation and is intended for development, testing, and truly last-minute meetings.

It does not cover scheduled bots or calendar-driven scheduling. In production, if meeting details are usually known ahead of time, you should implement scheduled bots instead so that your bots will join on time.

Ad-hoc bot creation can return HTTP 507 when temporary bot capacity is unavailable and a bot will not join your call, so the implementation in this guide includes the required retry behavior (every 30 seconds for up to 10 attempts) until you claim a bot or retries finish.

Just to be clear:

1. this guide does not cover scheduling
2. this guide is for direct bot creation + post-meeting transcript retrieval
3. scheduled bots should be implemented separately before using this as the default production path

Once you acknowledge with "yes", I will start.

Wait for acknowledgement before continuing.

Reference:


3. Human-required blocking setup

The agent must stop and wait for completion or acknowledgement on each of these before proceeding.

3.1 Create a Recall API key

Tell the human:

Head to the Recall dashboard via one of the following links (create an account if needed):
+-----------------------------------------------------------------------------------+
| Recall Region    | Dashboard URL                                                  |
+-----------------------------------------------------------------------------------+
| `us-west-2`      | https://us-west-2.recall.ai/dashboard/developers/api-keys      |
| `us-east-1`      | https://us-east-1.recall.ai/dashboard/developers/api-keys      |
| `eu-central-1`   | https://eu-central-1.recall.ai/dashboard/developers/api-keys   |
| `ap-northeast-1` | https://ap-northeast-1.recall.ai/dashboard/developers/api-keys |
+-----------------------------------------------------------------------------------+

Create a:

- Recall API key
- Workspace verification secret

Note down the following:

- Recall region
- API key
- Workspace verification secret

Let me know when this step is complete.

Reference:

Wait for completion.

3.2 Create a stable public webhook endpoint

Tell the human:

Set up a stable public HTTPS base URL for local development or the target environment.

If you are developing locally, use a stable tunneling URL (for example, a static ngrok domain), not one that changes on restart.

You can create a static ngrok domain by following this guide:
https://docs.recall.ai/docs/local-webhook-development

Make sure the stable public URL is running and reachable.

Let me know when this step is complete.

Reference:

Wait for completion.

3.3 Add the webhook endpoint in the Recall dashboard

Tell the human:

Head to the Recall webhooks dashboard for the same Recall region you chose earlier:
+------------------------------------------------------------------------+
| Recall Region    | Dashboard URL                                       |
+------------------------------------------------------------------------+
| `us-west-2`      | https://us-west-2.recall.ai/dashboard/webhooks      |
| `us-east-1`      | https://us-east-1.recall.ai/dashboard/webhooks      |
| `eu-central-1`   | https://eu-central-1.recall.ai/dashboard/webhooks   |
| `ap-northeast-1` | https://ap-northeast-1.recall.ai/dashboard/webhooks |
+------------------------------------------------------------------------+

Add the following webhook endpoint in the dashboard, where SERVER_DOMAIN is the stable public base URL you generated in the previous step:
`SERVER_DOMAIN/api/webhooks/recallai`

Subscribe to at least the following events:

- `bot.*`
- `recording.done`
- `recording.failed`
- `transcript.done`
- `transcript.failed`

Note down the following:

- Stable public webhook base URL

Let me know when this step is complete.

Reference:

Wait for completion.

3.4 Provide the required values to the agent

The human must provide the required values to the agent.

Required values:

RECALL_REGION=...
RECALL_API_KEY=...
RECALL_WORKSPACE_VERIFICATION_SECRET=...
SERVER_DOMAIN=https://your-public-domain.example

Agent behavior:

  • the human provides the required values
  • the agent sets the environment variables in the implementation/runtime environment
  • the agent must not proceed until the human has provided all required values

Tell the human:

Please provide the following values so I can configure the environment for the implementation:

- RECALL_REGION
- RECALL_API_KEY
- RECALL_WORKSPACE_VERIFICATION_SECRET
- SERVER_DOMAIN

I will wait until all four values are available before continuing.

Wait for completion.


4. Default implementation choices

Unless the human explicitly overrides them, use these defaults:

  • transcript provider: recallai_streaming
  • transcript language code: auto
  • transcript mode: prioritize_accuracy
  • diarization: use_separate_streams_when_available=true

Important behavior:

  • the transcript is automatically generated because it is defined in the Create Bot request
  • there is no separate transcript-start API call in this guide
  • once the transcript status becomes transcript.done, the transcript is ready to retrieve
  • the transcript will not change after it reaches transcript.done

This quickstart shows how to retrieve:

  1. the original transcript payload
  2. a readable transcript derived from the original payload

Reference:


5. Minimal state model

Store only the minimum state needed to drive the workflow.

5.1 Required fields

Persist at least:

  • bot_id (required; this can be the primary identifier for this quickstart)
  • internal_lookup_key (optional; use this only if the customer already has a separate app-specific identifier)
  • recording_id (nullable until known)
  • transcript_id (nullable until known)
  • bot_status (scheduled until first bot webhook, then latest bot.* status)
  • recording_status (nullable until known, then latest stored recording event such as recording.done or recording.failed)
  • transcript_status (nullable until known, then latest stored transcript event such as transcript.done or transcript.failed)
  • transcript_failure_sub_code (nullable; set when transcript fails)

5.2 Status meanings

Use a simple model like this:

  • bot_status

    • scheduled until first bot status change webhook
    • then the latest bot event, for example:
      • bot.joining_call
      • bot.in_waiting_room
      • bot.in_call_not_recording
      • bot.recording_permission_allowed
      • bot.recording_permission_denied
      • bot.in_call_recording
      • bot.call_ended
      • bot.done
      • bot.fatal
  • recording_status

    • null until known
    • then the latest recording event that the app stores, for example:
      • recording.done
      • recording.failed
  • transcript_status

    • null until known
    • then the latest transcript event that the app stores, for example:
      • transcript.done
      • transcript.failed

5.3 Why this model exists

This state model supports:

  • webhook-driven progress tracking
  • knowing whether the transcript is ready without polling
  • retrieving the transcript by bot_id
  • optionally retrieving it by an app-specific lookup key if the customer has one
  • returning the failure sub_code when transcript generation fails

6. Critical rules

These are required, not optional.

  1. Do not ever use polling to wait for bot, recording, or transcript completion.
  2. Do not implement this as a real-time transcription workflow.
  3. Do not add a separate “start transcription” step. In this guide, the transcript is automatically generated because it is configured in the Create Bot request.
  4. Do not go to production with direct/ad-hoc bot creation as the default path if meetings are usually known ahead of time. Implement scheduled bots separately.
  5. Do not use localhost, 127.0.0.1, or private callback URLs in Recall-facing configuration.
  6. Do not use an unstable/ephemeral tunnel URL that changes on restart.
  7. Do not assume webhooks arrive only once.
  8. Do not assume webhook order is guaranteed.
  9. Do not block transcript updates on bot state or recording state being in any specific order first.
  10. Do not update unrelated artifact fields from a webhook event.
    • bot events update bot fields
    • recording events update recording fields
    • transcript events update transcript fields
  11. Do not ignore 429. Respect the Retry-After header.
  12. Do not treat ad-hoc 507 as final until the required retries are exhausted.
  13. Do not fetch transcript data before transcript.done.
  14. Do not rely on webhook retries to drive application logic. Return 2xx immediately and do follow-up work separately.

7. Step 1: create the webhook endpoint first

Create the webhook route before creating bots.

Example route:

POST /api/webhooks/recallai

7.1 Required webhook behavior

The webhook handler must:

  • read the raw request body
  • verify the Recall signature before trusting the payload
  • identify the webhook event type
  • update the relevant persistent state for that event type
  • trigger any follow-up work separately if needed
  • return 2xx immediately to prevent Recall from retrying
  • be idempotent

Important wording:

  • do the follow-up work separately
  • do not wait for all downstream processing to finish before returning 2xx

Reference:

7.2 Required event subscriptions

At minimum, listen to:

  • bot.*
  • recording.done
  • recording.failed
  • transcript.done
  • transcript.failed

7.3 Required update behavior by event type

Update only the fields related to the webhook you received.

  • On bot.*

    • update bot_status
    • optionally store the bot event sub_code for debugging
  • On recording.done

    • set recording_id
    • set recording_status=recording.done
  • On recording.failed

    • set recording_id
    • set recording_status=recording.failed
  • On transcript.done

    • set transcript_id
    • set transcript_status=transcript.done
  • On transcript.failed

    • set transcript_id
    • set transcript_status=transcript.failed
    • set transcript_failure_sub_code from the webhook payload

Do not fetch the transcript body in the webhook handler.


8. Step 2: create the bot

Use the regional Create Bot endpoint from the correct region and define transcript configuration directly in the Create Bot request.

Example request:

curl --request POST \
 --url "https://$RECALL_REGION.recall.ai/api/v1/bot/" \
 --header "Authorization: Token $RECALL_API_KEY" \
 --header "Content-Type: application/json" \
 --header "Accept: application/json" \
 --data '{
  "meeting_url": "CONFIGURED_MEETING_URL",
  "join_at": "CONFIGURED_JOIN_TIME_ISO8601",
  "recording_config": {
    "transcript": {
      "provider": {
        "recallai_streaming": {
          "mode": "prioritize_accuracy",
          "language_code": "auto"
        }
      },
      "diarization": {
        "use_separate_streams_when_available": true
      }
    }
  }
}'

Because transcript configuration is included in this request, the transcript will be generated automatically after the meeting completes. There is no separate transcript-start step.

8.1 Required persistence after Create Bot succeeds

Persist at least:

  • bot_id
  • bot_status=scheduled

If the app has its own meeting identifier, it may also store:

  • internal_lookup_key

For this quickstart, bot_id is sufficient as the required unique identifier.

Do not continue as if the bot exists unless Create Bot returned a successful response.

Reference:


9. Step 3: handle bot, recording, and transcript webhooks

The webhook layer is the source of truth for completion state.

When a webhook is received:

  1. verify the request
  2. update only the fields related to that webhook event
  3. trigger any follow-up work separately if needed
  4. return 2xx immediately

9.1 Verify the webhook request

You can see this guide for how to verify requests from Recall using Recall’s HMAC signature verification method:

9.2 Bot webhook schema

The bot webhook schema follows:

{
  "event": "bot.\*",
  "data": {
    "data": {
      "code": "string",
      "sub_code": "string | null",
      "updated_at": "string"
    },
    "bot": {
      "id": "string",
      "metadata": {}
    }
  }
}

Required behavior:

  • persist the latest bot state needed for debugging and product UX
  • do not hardcode the implementation to only one tiny subset of bot states

At minimum, the app should be able to tell whether the bot:

  • is scheduled
  • is in the waiting room
  • is in the meeting and not recording
  • is in the meeting recording
  • has completed the call
  • has fatally failed

9.3 Recording webhook schema

The recording webhook schema follows:

{
  "event": "recording.done | recording.failed",
  "data": {
    "data": {
      "code": "string",
      "sub_code": "string | null",
      "updated_at": "string"
    },
    "recording": {
      "id": "string",
      "metadata": {}
    },
    "bot": {
      "id": "string",
      "metadata": {}
    }
  }
}

Required behavior:

  • if event=recording.done

    • set recording_id
    • set recording_status=recording.done
  • if event=recording.failed

    • set recording_id
    • set recording_status=recording.failed

9.4 Transcript webhook schema

The transcript webhook schema follows:

{
  "event": "transcript.done | transcript.failed",
  "data": {
    "data": {
      "code": "string",
      "sub_code": "string | null",
      "updated_at": "string"
    },
    "transcript": {
      "id": "string",
      "metadata": {}
    },
    "recording": {
      "id": "string",
      "metadata": {}
    },
    "bot": {
      "id": "string",
      "metadata": {}
    }
  }
}

Required behavior:

  • if event=transcript.done

    • set transcript_id
    • set transcript_status=transcript.done
  • if event=transcript.failed

    • set transcript_id
    • set transcript_status=transcript.failed
    • set transcript_failure_sub_code

9.5 Out-of-order webhook handling

Webhook order should not be assumed.

Required behavior:

  • rely on the event payload you received
  • update only the related artifact fields
  • do not require some other artifact to already be in a specific state before updating the current one

Examples:

  • if a transcript.done event arrives, update transcript fields even if the app has not yet seen the other final events yet
  • if a recording.failed event arrives, update recording fields even if transcript fields are still null
  • if duplicate deliveries arrive and you have already safely applied the same state update, returning early is fine

Reference:


10. Step 4: implement the transcript retrieval helper

Implement a helper function that returns the transcript result for a bot.

This helper can be used in either of these ways:

  • from a background process after transcript.done or transcript.failed
  • from an API endpoint when a client asks for the transcript

The point of the helper is to retrieve the transcript. What the application does next with the transcript is use-case specific.

10.1 Required helper behavior

The helper must:

  1. look up the bot by bot_id
  2. inspect stored transcript_status, transcript_id, and related transcript fields
  3. return the current status immediately if the transcript is not yet terminal
  4. return a failure response if the transcript failed
  5. if transcript_id is present and the transcript is done, retrieve the transcript
  6. return both:
    • the original transcript payload
    • a readable transcript

Do not poll Recall from this helper.

10.2 Helper behavior by transcript state

If transcript_status or transcript_id is null

Return a non-terminal status response.

Example:

{
  "status": {
    "code": "pending",
    "sub_code": null,
    "message": "The transcript has not been processed yet"
  },
  "raw_transcript": null,
  "readable_transcript": null
}

If transcript_status = "transcript.failed"

Return a failure response using the stored sub_code when available.

Example:

{
  "status": {
    "code": "failed",
    "sub_code": "zoom_global_captions_disabled",
    "message": "Transcript generation failed"
  },
  "raw_transcript": null,
  "readable_transcript": null
}

If transcript_status = "transcript.done"

Retrieve the transcript and return both formats.

Recommended sequence:

  1. use the stored transcript_id
  2. retrieve the transcript by transcript_id
  3. fetch the download_url from the transcript object
  4. parse the downloaded transcript payload as the original transcript
  5. convert it into a readable transcript
  6. return both

Example:

{
  "status": {
    "code": "done",
    "sub_code": null,
    "message": null
  },
  "raw_transcript": [...],
  "readable_transcript": [...],
}

10.3 List transcripts for a recording

If needed, call the List Transcript endpoint for a recording using the recording ID to get the list of transcripts.

Reference request:

curl --request GET \
  --url "https://$RECALL_REGION.recall.ai/api/v1/transcript/?recording_id=RECORDING_ID" \
  --header "Authorization: Token $RECALL_API_KEY" \
  --header "accept: application/json"

10.4 Retrieve the transcript by transcript ID

Once you have the transcript ID, call Retrieve Transcript using that ID, then read transcript.data.download_url from the response and fetch the payload from that URL.

10.5 Return both transcript formats

The helper should return:

  • raw_transcript: the original downloaded transcript payload
  • readable_transcript: a sentence-based readable transcript derived from the original payload

For the readable transcript, you can use the helper function here or implement equivalent logic in your own app:

Example success response:

{
  "status": {
    "code": "done",
    "sub_code": null,
    "message": null
  },
  "raw_transcript": [
    {
      "words": [
        {
          "text": "Hello.",
          "start_timestamp": {
            "relative": 0.0
          },
          "end_timestamp": {
            "relative": 0.5
          }
        }
      ],
      "language_code": "en",
      "participant": {
        "id": 1,
        "name": "Speaker 1",
        "is_host": false,
        "platform": "zoom",
        "extra_data": {},
        "email": null
      }
    }
  ],
  "readable_transcript": [
    {
      "speaker": "Speaker 1",
      "paragraph": "Hello.",
      "start_timestamp": {
        "relative": 0.0,
        "absolute": null
      },
      "end_timestamp": {
        "relative": 0.5,
        "absolute": null
      }
    }
  ]
}

11. Required failure handling

This section is mandatory.

11.1 HTTP 507 on ad-hoc bot creation

Ad-hoc bot creation can return 507 when temporary bot capacity is unavailable.

Required behavior:

  • retry every 30 seconds
  • retry for up to 10 attempts
  • after the 10th failed attempt, stop and surface a clear failure

Required failure message:

Ad-hoc bot capacity was unavailable after 10 retries spaced 30 seconds apart. For production, if meeting details are known ahead of time, implement scheduled bots instead of relying on ad-hoc bot creation as the default path.

Reference:

11.2 HTTP 429 rate limiting

For any Recall API request that returns 429:

  • read the Retry-After header
  • wait exactly that long before retrying
  • add small jitter to space out requests
  • do not use tight retry loops
  • do not ignore the header

11.3 No polling

Do not poll Recall to wait for:

  • bot completion
  • recording completion
  • transcript completion

Recall is designed for an async event-driven implementation. The transcript becomes available after Recall sends transcript.done. Wait for the webhook and then retrieve it when needed.

If you are not receiving a webhook, ensure that:

  • the bot has joined the call and completed the recording
  • the webhooks dashboard in the set region has the webhook endpoint configured and is not disabled
  • the webhooks dashboard in the set region has the correct webhook domain and endpoint configured

11.4 Invalid callback URLs

If Recall-facing configuration uses any of the following:

  • localhost
  • 127.0.0.1
  • private LAN URLs
  • a tunnel URL that changes on restart

stop and fix it before testing.

Required explanation:

Recall must be able to reach a stable public HTTPS callback URL.

Localhost and private addresses are not reachable by Recall. Unstable tunnel URLs that change on restart will break webhook delivery.

In some setups, invalid callback values can also result in HTTP 403 errors from CloudFront. Use a stable public HTTPS URL instead.

11.5 Webhook idempotency, duplicates, and out-of-order delivery

Webhook handlers must tolerate:

  • duplicate deliveries
  • out-of-order delivery
  • repeated terminal events

Required behavior:

  • verify the webhook
  • update only the fields for the artifact in that event
  • make repeated updates safe
  • do not require a specific prior webhook to have been seen first

Terminal states to treat carefully:

  • Bots:

    • bot.done
    • bot.fatal
  • Recording:

    • recording.done
    • recording.failed
  • Transcript:

    • transcript.done
    • transcript.failed

12. Verification checklist

Do not call the integration complete until all of these pass.

12.1 Functional verification

  1. create a test meeting
  2. create the bot
  3. confirm Create Bot returns an id
  4. confirm the bot joins the meeting via the bot.in_call_recording webhook
  5. end the meeting
  6. confirm the app receives bot webhook event bot.done
  7. confirm the app receives either:
    • recording.done, or
    • recording.failed
  8. confirm the app receives either:
    • transcript.done, or
    • transcript.failed
  9. confirm the database stores:
    • bot_id
    • recording_id
    • transcript_id
    • bot/recording/transcript statuses
    • transcript failure sub_code when relevant
  10. call the transcript retrieval helper or the optional endpoint
  11. confirm that when transcript succeeds, the app returns:
  • the original transcript payload
  • the readable transcript
  1. confirm that when transcript fails, the app returns the failure sub_code

13. Minimal implementation outline

A minimal implementation should look like this:

  1. get human acknowledgement that this guide is only for direct bot creation + post-meeting transcript retrieval
  2. wait for all human-required setup to be completed
  3. configure the environment variables
  4. create the webhook endpoint
  5. verify webhook signatures
  6. persist bot_id and statuses
  7. create the bot with transcript config included
  8. update artifact fields from webhook events
  9. implement a transcript retrieval helper that:
    • checks stored status
    • returns failure info when transcript failed
    • retrieves the transcript when transcript is done
    • returns both original and readable transcript
  10. optionally expose an endpoint that returns the helper result
  11. verify success and failure paths

14. Required human-facing explanations

14.1 If the human asks for real-time transcription

Use this wording:

I cannot implement that with this quickstart because this guide is only for final transcript retrieval after the meeting ends. For real-time transcript chunks, live captions, or during-call transcript access, use the Bot Real-Time Transcription guide instead.

14.2 If the human asks for scheduled bots or calendar-driven scheduling

Use this wording:

This quickstart does not cover scheduled bots or calendar-driven scheduling. It only covers direct bot creation plus post-meeting transcript retrieval. For production scheduling, consult the Creating and Scheduling Bots documentation or the separate scheduling guide.

14.3 If the human does not yet have a stable public callback URL

Use this wording:

I cannot complete a reliable implementation until you provide a stable public HTTPS webhook URL. If you are developing locally, use a stable tunnel URL rather than one that changes on restart.

14.4 If the human asks what they can do after retrieving the transcript

Use this wording:

This quickstart shows how to retrieve both the original transcript payload and a readable transcript after the meeting ends. What you do next depends on your product: you can print it, return it from an endpoint, store it, summarize it, analyze it, or push it to another system.

14.5 If the human asks whether they must use an internal lookup key

Use this wording:

No. For this quickstart, bot_id is enough as the required unique identifier. If your application already has its own meeting or run identifier, you may also store that as an optional internal lookup key.

14.6 If the human asks about the 507 error

Use this wording:

HTTP 507 during ad-hoc bot creation means temporary bot capacity is unavailable right now. Retry every 30 seconds for up to 10 attempts; if all 10 attempts fail, stop and surface a clear failure, and for production flows with known meeting details use scheduled bots instead of relying on ad-hoc creation as the default path.

14.7 If the human asks about the 403 or CloudFront error

Use this wording:

An HTTP 403 or CloudFront error usually means the callback URL or webhook configuration is not valid for Recall to reach. Localhost, `127.0.0.1`, private LAN addresses, and unstable tunnel URLs will not work; switch to a stable public HTTPS URL and verify the webhook endpoint is correctly configured and enabled in the dashboard for the correct region.