> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fireflies.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Upload URL

> Generate a pre-signed URL for direct audio/video file uploads

<Warning>
  This API is not generally available. Whitelisting is currently closed.
</Warning>

## Overview

The `createUploadUrl` mutation generates a pre-signed URL that allows you to upload audio or video files directly to Fireflies.ai storage. This is useful when you want to upload files from your own infrastructure without exposing them via a public URL.

This mutation is part of a two-step upload flow:

1. Call `createUploadUrl` to get a pre-signed upload URL
2. Upload your file directly to the URL using an HTTP PUT request
3. Call [confirmUpload](/graphql-api/mutation/confirm-upload) to confirm the upload and start transcription

## Arguments

<ParamField path="input" type="CreateUploadUrlInput" required>
  <Expandable>
    <ResponseField name="content_type" type="String" required>
      The MIME type of the file being uploaded. Must be one of the supported audio or video formats. See [Supported Content Types](#supported-content-types) below.
    </ResponseField>

    <ResponseField name="file_size" type="Int" required>
      The size of the file in bytes. Used for validation against plan limits. Maximum 2GB for video files (paid users) or 400MB for audio files.
    </ResponseField>

    <ResponseField name="title" type="String">
      Title or name of the meeting. This will be used to identify the transcribed file. Maximum 256 characters.
    </ResponseField>

    <ResponseField name="custom_language" type="String">
      Specify a custom language code for your meeting, e.g. `es` for Spanish or `de` for German. For a complete list of language codes, please view [Language Codes](/miscellaneous/language-codes). Maximum 5 characters.
    </ResponseField>

    <ResponseField name="attendees" type="[Attendee]">
      An array of [Attendee](/schema/input/attendee) objects. This is relevant if you have active integrations like Salesforce, Hubspot etc. Fireflies uses the attendees value to push meeting notes to your active CRM integrations. Maximum 100 attendees.
    </ResponseField>
  </Expandable>
</ParamField>

## Response

<ResponseField name="upload_url" type="String">
  The pre-signed URL to upload your file to. Use an HTTP PUT request with the file content as the body.
</ResponseField>

<ResponseField name="meeting_id" type="String">
  The unique identifier for the meeting. Use this ID when calling `confirmUpload`.
</ResponseField>

<ResponseField name="expires_at" type="String">
  ISO 8601 timestamp indicating when the upload URL expires. URLs are valid for 1 hour.
</ResponseField>

## Usage Example

```graphql theme={null}
mutation createUploadUrl($input: CreateUploadUrlInput!) {
  createUploadUrl(input: $input) {
    upload_url
    meeting_id
    expires_at
  }
}
```

<RequestExample>
  ```bash curl theme={null}
  curl -X POST \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer your_api_key" \
    -d '{
      "query": "mutation($input: CreateUploadUrlInput!) { createUploadUrl(input: $input) { upload_url meeting_id expires_at } }",
      "variables": {
        "input": {
          "content_type": "audio/mpeg",
          "file_size": 10485760,
          "title": "Team Meeting Recording"
        }
      }
    }' \
    https://api.fireflies.ai/graphql
  ```

  ```javascript javascript theme={null}
  const axios = require('axios');

  const url = 'https://api.fireflies.ai/graphql';
  const headers = {
    'Content-Type': 'application/json',
    Authorization: 'Bearer your_api_key'
  };

  const input = {
    content_type: 'audio/mpeg',
    file_size: 10485760,
    title: 'Team Meeting Recording'
  };

  const data = {
    query: `
      mutation($input: CreateUploadUrlInput!) {
        createUploadUrl(input: $input) {
          upload_url
          meeting_id
          expires_at
        }
      }
    `,
    variables: { input }
  };

  axios
    .post(url, data, { headers })
    .then(result => {
      console.log(result.data);
      
      // Step 2: Upload the file to the signed URL
      const { upload_url, meeting_id } = result.data.data.createUploadUrl;
      // Use fetch or axios to PUT your file to upload_url
    })
    .catch(e => {
      console.log(JSON.stringify(e));
    });
  ```

  ```python python theme={null}
  import requests

  url = 'https://api.fireflies.ai/graphql'

  headers = {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer your_api_key'
  }

  input_data = {
      "content_type": "audio/mpeg",
      "file_size": 10485760,
      "title": "Team Meeting Recording"
  }

  data = {
      'query': '''
          mutation($input: CreateUploadUrlInput!) {
              createUploadUrl(input: $input) {
                  upload_url
                  meeting_id
                  expires_at
              }
          }
      ''',
      'variables': {'input': input_data}
  }

  response = requests.post(url, headers=headers, json=data)

  if response.status_code == 200:
      result = response.json()
      print(result)
      
      # Step 2: Upload the file to the signed URL
      upload_url = result['data']['createUploadUrl']['upload_url']
      meeting_id = result['data']['createUploadUrl']['meeting_id']
      # Use requests.put() to upload your file to upload_url
  else:
      print(response.text)
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "data": {
      "createUploadUrl": {
        "upload_url": "https://storage.googleapis.com/...",
        "meeting_id": "abc123def456",
        "expires_at": "2024-01-15T12:00:00.000Z"
      }
    }
  }
  ```
</ResponseExample>

## Uploading the File

After receiving the signed URL, upload your file using an HTTP PUT request:

```bash theme={null}
curl -X PUT \
  -H "Content-Type: audio/mpeg" \
  --data-binary @your-audio-file.mp3 \
  "https://storage.googleapis.com/..."
```

```javascript theme={null}
const fs = require('fs');
const axios = require('axios');

const fileBuffer = fs.readFileSync('your-audio-file.mp3');

await axios.put(uploadUrl, fileBuffer, {
  headers: {
    'Content-Type': 'audio/mpeg'
  }
});
```

```python theme={null}
with open('your-audio-file.mp3', 'rb') as f:
    file_data = f.read()

response = requests.put(
    upload_url,
    data=file_data,
    headers={'Content-Type': 'audio/mpeg'}
)
```

After the upload completes successfully, call [confirmUpload](/graphql-api/mutation/confirm-upload) to start transcription.

## Supported Content Types

### Audio Formats

| MIME Type        | Extension |
| ---------------- | --------- |
| `audio/mpeg`     | .mp3      |
| `audio/mp3`      | .mp3      |
| `audio/wav`      | .wav      |
| `audio/x-wav`    | .wav      |
| `audio/vnd.wave` | .wav      |
| `audio/x-m4a`    | .m4a      |
| `audio/mp4`      | .m4a      |
| `audio/ogg`      | .ogg      |
| `audio/webm`     | .webm     |
| `audio/aac`      | .aac      |
| `audio/x-aac`    | .aac      |
| `audio/aac-adts` | .aac      |
| `audio/amr`      | .amr      |
| `audio/opus`     | .opus     |
| `audio/3gpp`     | .3gp      |

### Video Formats

| MIME Type         | Extension |
| ----------------- | --------- |
| `video/mp4`       | .mp4      |
| `video/webm`      | .webm     |
| `video/quicktime` | .mov      |
| `video/x-m4v`     | .m4v      |
| `video/mpeg`      | .mpeg     |
| `video/x-msvideo` | .avi      |
| `video/ogg`       | .ogv      |
| `video/3gpp`      | .3gp      |

## File Size Limits

| File Type | User Plan | Maximum Size |
| --------- | --------- | ------------ |
| Audio     | All plans | 400 MB       |
| Video     | Free      | 200 MB       |
| Video     | Paid      | 2 GB         |

## Error Codes

<Accordion title="paid_required">
  This mutation requires a paid plan (Pro or higher). Free plan users cannot use direct file uploads.
</Accordion>

<Accordion title="invalid_arguments">
  The content type is not supported, or the file size exceeds the allowed limit for your plan.
</Accordion>

## Additional Resources

<CardGroup cols={2}>
  <Card title="Confirm Upload" icon="link" href="/graphql-api/mutation/confirm-upload">
    Confirm the upload and start transcription
  </Card>

  <Card title="Upload Audio (URL)" icon="link" href="/graphql-api/mutation/upload-audio">
    Alternative: Upload audio via public URL
  </Card>

  <Card title="Webhooks" icon="link" href="/graphql-api/webhooks">
    Receive notifications when transcription completes
  </Card>

  <Card title="Language Codes" icon="link" href="/miscellaneous/language-codes">
    Supported language codes for transcription
  </Card>
</CardGroup>
