meetings permission scope. You can also invite a published persona from its Build page in the Lab. The API adds scheduling and region control on top.
Meeting participants always see that the persona is an AI. Its display name carries an “(AI)” suffix, added server-side if the name you provide doesn’t already include one, and its video shows a persistent AI-disclosure treatment.
Invite a persona
Send a meeting URL and a persona toPOST /v1/meetings/invites:
personaId— a saved persona from the Lab or the Personas API.personaConfig— a runtime configuration, the same shape you use when creating a session token. It needs at least anavatarId, avoiceId, and anllmId. The configuration is used for the meeting session but not stored.
pending status. Without a joinAt, the persona starts joining right away.
joinState is waiting_room. If nobody lets it in, the invite ends as failed with a statusReason of not_admitted or join_denied.
Schedule the join
For a meeting you know about in advance, setjoinAt instead of creating the invite at meeting time:
joinAt times less than 10 minutes out, use on-demand capacity instead and can be rejected with a 503 at busy moments.
joinAt is ISO 8601 and must include a timezone (Z or an offset such as +02:00). It must be in the future, at most 7 days ahead. The invite stays pending until the scheduled time, and you can cancel it at any point before then.
Group calls and 1:1 calls
By default the persona behaves as a well-mannered participant in a multi-person meeting: it joins silently and speaks only when addressed by its display name (“Cara, what do you think?”). This is thegroupCall: true default.
Set groupCall: false when the persona is the main counterpart on the call, such as an interview or a 1:1 demo. It then greets everyone when it joins and responds to everything it hears, the same way it would in a regular session.
Follow the invite
An invite moves through a small set of states. PollGET /v1/meetings/invites/{id} to follow it, or filter the list endpoint to watch several at once:
| Status | Meaning |
|---|---|
pending | Created; waiting for a scheduled joinAt or in the process of joining. |
active | The persona is in the call and its session is running. |
ended | The call finished normally: the meeting ended or the persona left. |
cancelled | You cancelled the invite. |
failed | The persona couldn’t join, or the call ended abnormally. |
joinStatereports the persona’s progress into the call as it happens:joining,waiting_room,in_call,media_denied,media_granted,media_active,left,done, orerror. New values may appear over time, so treat unrecognized ones as informational rather than as errors.statusReasonexplains how a finished invite got there, for examplenot_admitted,removed_by_host,meeting_ended,meeting_link_invalid, oridle_timeout. It’snullwhile the invite is in progress, and may also gain new values over time.
active, its sessionId refers to an ordinary session. Everything in the Sessions API works with it, including fetching the transcript after the call.
Remove the persona
DELETE /v1/meetings/invites/{id} cancels a pending invite. If the persona has already joined, it leaves the call and its session ends immediately:
204 and is idempotent for invites that already finished. You don’t have to clean up invites you leave alone: the persona leaves on its own when the meeting ends.
Regions
The persona joins the call from one of three regions:eu, us-east, or us-west. If you omit region, one is picked automatically based on where your request comes from. For the lowest latency, set the region closest to the meeting’s participants, which may not be where your server runs.
regionPolicy controls what happens when your chosen region is out of capacity:
preferred(the default) may serve the invite from another region so the persona still joins.strictnever leaves the selected region and fails with a503instead. It requires an explicitregion.
strict when data residency matters, for example to keep an EU customer’s call in the EU:
region field on the invite is the region actually serving the call, which under preferred can differ from the one you asked for.
Limits and capacity
Invite creation is rate limited to 10 requests per minute per requester and 30 per hour per organization. Successful (201) and rate-limited (429) responses both carry RateLimit-* headers for the per-minute window and X-RateLimit-Org-Hour-* headers for the hourly one.
A 503 on create means there’s no on-demand capacity right now. The response includes a Retry-After header; retry after that many seconds, or switch to a scheduled joinAt at least 10 minutes ahead so capacity is reserved instead. A 422 means the meeting service rejected the invite itself, which usually points to a problem with the meeting URL.
The full request and response reference, including every error shape, is in the Meetings API reference.
