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

# Submit from local file

> Upload a local audio or video file for transcription using a two-step process.

Use this endpoint when your audio file is stored locally. Call this API first to receive a pre-signed upload URL, then upload your file directly to it. Transcription processing starts automatically once the upload completes.

## Step 1 — Request upload URL

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.heify.com/request-upload-url \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "configuration_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
      "evaluator_id": "2abb5563-dd64-47bb-bb17-94252e168b06",
      "name": "sales-call-2026-03-21.mp3"
    }'
  ```

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

  response = requests.post(
      "https://api.heify.com/request-upload-url",
      headers={"x-api-key": "YOUR_API_KEY"},
      json={
          "configuration_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
          "evaluator_id": "2abb5563-dd64-47bb-bb17-94252e168b06",
          "name": "sales-call-2026-03-21.mp3"
      }
  )

  data = response.json()["data"]
  upload_url = data["upload_url"]
  transcription_id = data["transcription_id"]
  ```
</CodeGroup>

<Warning>
  The `upload_url` expires in **5 minutes**. Proceed to Step 2 immediately after receiving it.
</Warning>

<Note>
  `participant_id` and `evaluator_id` are optional. If provided, they must exist and belong to your account.
</Note>

<Note>
  The `name` field is sanitized to ASCII — accented or non-Latin characters are automatically stripped.
</Note>

## Step 2 — Upload the file

Send a `PUT` request to the `upload_url` from the Step 1 response. You must include the metadata fields as headers — they are embedded in the upload URL signature and the request will fail if they are missing or don't match.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT \
    -H "Content-Type: audio/mpeg" \
    -H "x-amz-meta-configuration_id: CONFIGURATION_ID_FROM_STEP_1" \
    -H "x-amz-meta-evaluator_id: EVALUATOR_ID_FROM_STEP_1" \
    --data-binary @recording.mp3 \
    "UPLOAD_URL_FROM_STEP_1"
  ```

  ```python Python theme={null}
  data = response.json()["data"]  # Step 1 response

  # Build metadata headers from Step 1 response
  meta_headers = {
      "Content-Type": "audio/mpeg",
      "x-amz-meta-configuration_id": data["configuration_id"],
  }
  if data.get("participant_id"):
      meta_headers["x-amz-meta-participant_id"] = data["participant_id"]
  if data.get("evaluator_id"):
      meta_headers["x-amz-meta-evaluator_id"] = data["evaluator_id"]
  if data.get("name"):
      meta_headers["x-amz-meta-name"] = data["name"]

  with open("recording.mp3", "rb") as f:
      upload_response = requests.put(data["upload_url"], data=f, headers=meta_headers)

  if upload_response.status_code == 200:
      print(f"Upload successful. Transcription ID: {data['transcription_id']}")
  ```
</CodeGroup>

A `200 OK` with an empty body confirms the upload succeeded. Processing starts automatically in the background.

<Note>
  Use the `transcription_id` from Step 1 to [check results](/api-reference/transcription/details) once processing completes, or configure a [webhook](/core/configuration#webhooks) to receive a notification automatically.
</Note>

<Note>
  For supported formats, file size limits, and duration limits, see [Rate Limits & Quotas](/platform/rate-limits).
</Note>


## OpenAPI

````yaml api-reference/openapi-transcriptions.json POST /request-upload-url
openapi: 3.1.0
info:
  title: Heify API — Transcriptions
  description: Endpoints for submitting, retrieving, and managing Transcriptions.
  version: 1.0.0
servers:
  - url: https://api.heify.com
security:
  - apiKeyAuth: []
paths:
  /request-upload-url:
    post:
      summary: Submit from local file (1/2)
      description: >-
        Generates a secure, pre-signed S3 URL for uploading a local audio or
        video file. This is step 1 of 2 in the local file upload flow. The
        pre-signed URL is valid for **5 minutes** — upload the file immediately
        after receiving it.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestUploadUrlBody'
            examples:
              StandardRequest:
                summary: Request a pre-signed upload URL
                value:
                  configuration_id: a1b2c3d4-e5f6-7890-1234-567890abcdef
                  evaluator_id: 2abb5563-dd64-47bb-bb17-94252e168b06
                  name: sales-call-2026-03-21.mp3
      responses:
        '200':
          description: >-
            Pre-signed URL generated successfully. PUT the audio file to
            `upload_url` with the correct `Content-Type` header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestUploadUrlResponse'
              examples:
                SuccessResponse:
                  value:
                    data:
                      transcription_id: b147ee2b-41f8-43ac-8838-29b17229abf4
                      upload_url: >-
                        https://storage.heify.com/upload/client-id/b147ee2b-41f8-43ac-8838-29b17229abf4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=300&...
                      configuration_id: a1b2c3d4-e5f6-7890-1234-567890abcdef
                      participant_id: null
                      evaluator_id: 2abb5563-dd64-47bb-bb17-94252e168b06
                      name: sales-call-2026-03-21.mp3
components:
  schemas:
    RequestUploadUrlBody:
      type: object
      properties:
        configuration_id:
          type: string
          format: uuid
          description: >-
            The unique identifier of the configuration to use for this
            transcription.
        name:
          type: string
          description: >-
            Optional label or filename for the transcription. Only ASCII
            characters are kept — non-ASCII characters are automatically
            stripped.
        participant_id:
          type: string
          format: uuid
          description: >-
            Optional. Link this transcription to a participant. Must exist and
            belong to your account.
        evaluator_id:
          type: string
          format: uuid
          description: >-
            Optional. Link this transcription to an evaluator. Must exist and
            belong to your account.
      required:
        - configuration_id
    RequestUploadUrlResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            transcription_id:
              type: string
              format: uuid
              description: >-
                The unique identifier assigned to this transcription. Use this
                for all subsequent API calls.
            upload_url:
              type: string
              format: uri
              description: >-
                The pre-signed upload URL. Send a `PUT` request to this URL with
                your audio file. Valid for **5 minutes**.
            configuration_id:
              type: string
              format: uuid
              description: Echo of the configuration ID used.
            participant_id:
              type: string
              format: uuid
              nullable: true
              description: Echo of the participant ID provided, or `null`.
            evaluator_id:
              type: string
              format: uuid
              nullable: true
              description: Echo of the evaluator ID provided, or `null`.
            name:
              type: string
              nullable: true
              description: >-
                The sanitized name provided, or `null`. Non-ASCII characters are
                stripped.
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````