## Upload a meeting recording

**post** `/v1/meetings/{id}/recordings`

A recording is one session of the meeting: its transcript and, when there is one, its audio or video. Recordings come from the Lightfield notetaker, Gong, Granola, or an upload. Only uploaded recordings can be created or given media through the API. Creates an uploaded recording from files already uploaded through `POST /v1/files`: a transcript (purpose `meeting_transcript`, required) and optionally its audio or video (purpose `meeting_recording`). Both files attach in one write, so a failed request attaches neither. Media can also be added later by updating the recording. Sending a transcript file that is already on the meeting returns that recording. Only meeting participants and workspace owners may upload.

Supports idempotency via the `Idempotency-Key` header.

**[Required scope](/using-the-api/scopes/):** `meetings:update`

**[Rate limit category](/using-the-api/rate-limits/):** Write

### Path Parameters

- `id: string`

  Unique identifier of the meeting.

### Body Parameters

- `transcriptFileId: string`

  File ID of a completed upload with purpose `meeting_transcript`.

- `isCanonical: optional boolean`

  Pin this as the meeting's primary recording. Defaults to `true`. `false` attaches it without pinning; on a meeting with no pinned recording, the primary is chosen by source (notetaker, Gong, Granola, then uploads) and then recency, so a newer upload can still become primary.

- `mediaFileId: optional string`

  File ID of a completed upload with purpose `meeting_recording`. Can also be added later by updating the recording.

### Returns

- `MeetingCreateRecordingResponse object { id, isCanonical, media, 4 more }`

  - `id: string`

    Unique identifier of the recording.

  - `isCanonical: boolean`

    Whether this is the meeting's primary recording, the one summaries and `$transcript` use.

  - `media: object { mimeType, url }`

    Playable audio or video. Null when the recording has none, such as a Granola note, a private Gong call, a failed notetaker recording or an upload without media.

    - `mimeType: string`

      MIME type of the media, when known.

    - `url: string`

      Short-lived download URL for the audio or video. Anyone with the URL can download it until it expires, so fetch it again when needed rather than storing it.

  - `provider: "RECALL" or "GONG" or "GRANOLA" or "UPLOAD"`

    Where the recording came from: `RECALL` (Lightfield notetaker), `GONG`, `GRANOLA`, or `UPLOAD`.

    - `"RECALL"`

    - `"GONG"`

    - `"GRANOLA"`

    - `"UPLOAD"`

  - `recordedAt: string`

    When the provider recorded it, in ISO 8601. Null if unknown.

  - `recordedBy: string`

    Display name of who recorded or uploaded it. Not a member reference.

  - `transcript: object { fileId }`

    The transcript text file. Null for older notetaker recordings.

    - `fileId: string`

      File ID of the transcript. Read its text through `GET /v1/files/{id}/url`.

### Example

```http
curl https://api.lightfield.app/v1/meetings/$ID/recordings \
    -H 'Content-Type: application/json' \
    -H 'Lightfield-Version: 2026-03-01' \
    -H "Authorization: Bearer $API_KEY" \
    -d '{
          "transcriptFileId": "transcriptFileId"
        }'
```

#### Response

```json
{
  "id": "id",
  "isCanonical": true,
  "media": {
    "mimeType": "mimeType",
    "url": "url"
  },
  "provider": "RECALL",
  "recordedAt": "recordedAt",
  "recordedBy": "recordedBy",
  "transcript": {
    "fileId": "fileId"
  }
}
```
