Skip to main content
Use the Recordings API to create a recording before its media is available, associate it with folders, attach media by URL or direct upload, and read the resulting recording and transcript. Recording resources use public UUIDs. Most recording endpoints accept either a user access token or an organization API key. The examples below use an organization API key:
The base URL for these endpoints is:
Except for the meeting-join command called out below, every endpoint on this page accepts either user authentication or an organization API key. Missing or invalid authentication returns 401 Unauthorized. Authorization failures return the status documented for the operation. Resource paths return 404 Not Found for unknown, inaccessible, cross-organization, or mismatched public UUIDs.
The GraphQL API is being deprecated for customer integrations. Use these REST endpoints for new recording and transcript integrations.

Endpoint overview

Public IDs

recordingId, folderIds, uploadId, participant personId, metadata fieldId, and other IDs documented on this page are public UUIDs. Do not send GraphQL BigInt IDs to these endpoints. The id returned by recording create, get, and list is the recording’s public UUID. Store it and use it in transcript and upload paths. Feedback IDs and recording IDs identify different resources and are not interchangeable. To associate a recording with folders, send the recording create request with the folders’ public UUIDs in folderIds.

List recordings

GET /v3/rest/recordings

Returns recordings visible to the authenticated user or organization.

Query parameters

Success response

200 OK
The list endpoint retains snake_case field names for its established list projection. Its metadata array can contain canonical API metadata and other source-scoped records linked to the recording. Use has_more to decide whether to request the next page. Individual recording reads use the camelCase resource shown below and project only the singular canonical API record into record.

Create a recording

POST /v3/rest/recordings

Creates the recording resource and returns its public UUID immediately. Media processing, when requested, continues asynchronously.

Request body

The server always places record in the organization’s dedicated metadata source where type is api and externalEntityName is recordings. If the source does not exist yet, BuildBetter creates it on demand. The request does not accept a metadata source selector. Create fields for this source through the Metadata API, then send their public UUIDs in record.values.

Folder association

folderIds works with either a user access token or an organization API key. BuildBetter deduplicates the list and resolves every folder under the authenticated user or organization context before creating the recording. Unknown, inaccessible, and cross-organization folder UUIDs are all returned as 404 Not Found without revealing whether the folder exists elsewhere. The recording and every requested folder association are committed in one transaction. If any folder cannot be resolved or any association cannot be written, BuildBetter creates neither the recording nor a partial set of folder associations. This also supports transcript-only integrations: media upload is not required to place the new recording in its destination folders. An assetUrl must use HTTP or HTTPS and cannot contain embedded credentials. The create request rejects localhost names and literal private or reserved IP addresses without performing DNS. BuildBetter resolves and revalidates the hostname in the durable ingestion worker, including every redirect, so transient DNS failures can be retried instead of failing recording creation permanently.

Participant shapes

Reference an existing person by public UUID:
Or upsert a person by email:
speaker must be a non-negative integer. An upsert requires email; names are optional. Within one request, a speaker cannot resolve to multiple people and a person cannot resolve to multiple speakers. When transcript is present, every participant speaker must appear in at least one supplied utterance; utterance speakers may remain unlabeled.

Transcript rules

Each utterance requires non-negative startSec and endSec, non-blank text, and a non-negative integer speaker. endSec must be greater than or equal to startSec. Utterances must be ordered by startSec, and utterances for the same speaker cannot overlap. A transcript can contain up to 10,000 utterances and 2,000,000 text characters in total. Each utterance can contain up to 20,000 characters. When you provide transcript, BuildBetter treats it as authoritative: transcript status is immediately completed, transcript source is api, and BuildBetter does not submit the recording for automatic transcription. This remains true whether or not you also provide media.

Success response

201 Created with a Location header pointing to /v3/rest/recordings/{recordingId}.
The recording, folder associations, metadata record, metadata values, participants, and supplied transcript are created atomically. If validation fails, correct the request and retry with the same record.externalId; the failed request does not reserve it. After a successful create, another request using the same external ID in the recordings source returns 409 Conflict with the existing recording’s public UUID:
If the original 201 Created response was lost, treat this conflict as recovery of that recording and continue with the returned recordingId. The API does not create or update another recording in this case.

Create errors

For example, an oversized transcript returns a stable limit code:
A typed metadata failure includes field-specific details that can be shown to the caller:

Get a recording

GET /v3/rest/recordings/{recordingId}

Returns the current recording, asset, transcript, participant, and canonical metadata state.

Success response

200 OK. The response uses the same recording resource shape returned by create. record can be null for older recordings that predate canonical API metadata records.
asset.url is a temporary playback URL derived at request time and may expire. The asset status can be waiting, queued, uploading, processing, completed, failed, or cancelled. asset.errorCode provides a stable failure code when one is available. The asset and transcript states are independent. For example, a supplied transcript can be complete while media is still queued, or uploaded media can be complete while automatic transcription is still processing. Unknown or inaccessible recording UUIDs return 404 Not Found.

Get a transcript

GET /v3/rest/recordings/{recordingId}/transcript

Returns transcript text as sentence-level utterances or contiguous same-speaker monologues.
The optional type query parameter accepts:
  • utterance: sentence-level transcript rows. This is the default.
  • monologue: contiguous rows from the same speaker combined into blocks.

Utterance response

200 OK

Monologue response

200 OK
Transcript entries do not include internal database IDs. Unknown or inaccessible recording UUIDs return 404 Not Found; an unsupported type returns 400 Bad Request.

Attach a direct upload

Create the recording first, then create an upload nested beneath its public UUID. Do not provide assetUrl when you intend to use this flow.
1

Create the recording

Call POST /v3/rest/recordings and store the returned recording id.
2

Create an upload

Call POST /v3/rest/recordings/{recordingId}/uploads with the file name and byte size.
3

Transfer the file

Send the file to the temporary uploadUrl using a resumable upload client. Treat this URL as a short-lived secret and do not log or persist it.
4

Poll status

Poll GET /v3/rest/recordings/{recordingId}/uploads/{uploadId} until the phase is ready, failed, or cancelled.

Create an upload

POST /v3/rest/recordings/{recordingId}/uploads

fileName must be non-blank and fileSize must be an integer from 1 through 9,007,199,254,740,991 containing the file’s size in bytes. The request also accepts optional public UUIDs folderId and batchId. The folder must be visible to the principal. Upload batches are user-scoped, so an organization API key cannot attach an upload to a batch. inMobileApp defaults to false and is reserved for BuildBetter mobile clients. Browser requests authenticated as a user must include their Origin header so the temporary upload destination can be scoped for CORS. Server-to-server requests using an organization API key do not require Origin. 201 Created
The real uploadUrl is temporary and unique to this attempt. Begin the transfer before timeoutSeconds elapses. A recording can have only one active media ingestion. A different create request while an upload or URL ingestion is active returns 409 Conflict. If this exact request succeeded but its response was lost, retrying with the same recording, fileName, fileSize, source, folderId, and batchId returns the existing unexpired waiting upload attempt, including the same uploadId and uploadUrl. This recovery does not create a second Mux destination. The same status can ask a caller to retry after an in-progress credit recharge. Unknown recording, folder, or batch UUIDs return 404 Not Found.

Get upload status

GET /v3/rest/recordings/{recordingId}/uploads/{uploadId}

200 OK
encodeProgress is null outside encoding or when live progress is unavailable. On failure, errorCode can be upload_failed, upload_expired, or processing_failed. The uploadId must belong to the recordingId in the path. Unknown, inaccessible, or mismatched IDs return 404 Not Found.

Cancel an upload

DELETE /v3/rest/recordings/{recordingId}/uploads/{uploadId}

Cancels an upload while it is still waiting for file bytes.
200 OK
Cancellation releases the waiting media claim, so you can create a new upload for the same recording. Repeating the DELETE after a successful cancellation returns the same cancelled state. Once processing has begun, cancellation returns 409 Conflict; continue polling the existing attempt instead. Unknown or mismatched IDs return 404 Not Found.

Ingest media from a URL

As an alternative to direct upload, include assetUrl in POST /v3/rest/recordings. BuildBetter validates locally decidable HTTP or HTTPS URL policy, creates the recording and a durable ingestion attempt atomically, and schedules media transfer asynchronously. DNS resolution and destination validation happen in the durable worker, not in the create request. The create response does not wait for the media transfer. Poll GET /v3/rest/recordings/{recordingId} and inspect asset.status. A retryable transfer remains queued; terminal failures use failed and may include asset.errorCode. Transient DNS failures and a successful HTTP response containing zero media bytes are retryable; empty media is never published as a completed asset. Do not start a nested upload while URL ingestion is active, because the recording permits one active media ingestion at a time. The URL must be directly retrievable with an unauthenticated GET. BuildBetter accepts common AAC, FLAC, MP4, MPEG, Ogg, WAV, WebM, and QuickTime audio/video content types, plus application/octet-stream, up to 5 GiB.

Ask the recorder to join a meeting

This command requires an authenticated BuildBetter user. Organization API keys are not accepted and return 403 Forbidden.

POST /v3/rest/recordings/meeting-joins

type must be meetingUrl, and joinUrl must be a non-blank meeting URL supported by the recorder. When the join request is accepted, the endpoint returns 201 Created:
The response identifies the recording resource immediately; joining, recording, media processing, and transcription continue asynchronously. An authenticated user whose organization is not allowed to record receives 401 Unauthorized. If an active recording already exists for the same meeting identity, the endpoint returns that recording’s public UUID rather than creating another recording.

Legacy GraphQL transcript migration

Move transcript reads to GET /v3/rest/recordings/{recordingId}/transcript. Existing GraphQL integrations should avoid interview.monologues and use the REST transcript endpoint with type=monologue when contiguous same-speaker blocks are required.