> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.telekesher.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.telekesher.dev/_mcp/server.

# Start audio playback

POST https://api.telekesher.dev/v1/sessions/{uuid}/playback/play
Content-Type: application/json

**Rate limit: Per command** · **Burst:** 8 · **Refill:** 4 req/s

Start finite-file, live-stream, or silence playback. Stops any active playback first (last-wins semantics).

Before accepting a finite URL playback, the gateway probes each source
with HEAD first and falls back to a ranged GET. A source that cannot be
prepared returns a synchronous HTTP error, and no playback webhook is emitted. After a
request is accepted, a later start failure emits `playback.failed`.

**Triggered webhooks:** `playback.started`, `playback.stopped`,
`playback.failed` (on error)

**Note on `playback.started` timing.** `playback.started` fires at the
true sound-start — the moment audio actually begins playing on the call,
not when the request is accepted. The gateway stages the event at
dispatch and emits it only when playback actually begins (audible),
so `timestamp` reflects real audio start (usable to measure
start latency). If playback never starts, `playback.failed` fires instead.

Reference: https://docs.telekesher.dev/api/playback/play

## OpenAPI Specification

```yaml
openapi: 3.1.0
info:
  title: voice-api
  version: 1.0.0
paths:
  /v1/sessions/{uuid}/playback/play:
    post:
      operationId: startAudioPlayback
      summary: Start audio playback
      description: >-
        **Rate limit: Per command** · **Burst:** 8 · **Refill:** 4 req/s


        Start finite-file, live-stream, or silence playback. Stops any active
        playback first (last-wins semantics).


        Before accepting a finite URL playback, the gateway probes each source

        with HEAD first and falls back to a ranged GET. A source that cannot be

        prepared returns a synchronous HTTP error, and no playback webhook is
        emitted. After a

        request is accepted, a later start failure emits `playback.failed`.


        **Triggered webhooks:** `playback.started`, `playback.stopped`,

        `playback.failed` (on error)


        **Note on `playback.started` timing.** `playback.started` fires at the

        true sound-start — the moment audio actually begins playing on the call,

        not when the request is accepted. The gateway stages the event at

        dispatch and emits it only when playback actually begins (audible),

        so `timestamp` reflects real audio start (usable to measure

        start latency). If playback never starts, `playback.failed` fires
        instead.
      tags:
        - playback
      parameters:
        - name: uuid
          in: path
          description: '[Session](/api/sessions) UUID (format `{5-char-prefix}-{uuid}`).'
          required: true
          schema:
            type: string
        - name: Authorization
          in: header
          description: >-
            Application auth. Send `Authorization: Bearer <app_uuid>:<api_key>`.
            See
            [Authentication](https://voice-platform.docs.buildwithfern.com/api/authentication)
            for details.
          required: true
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          description: >-
            Optional client-generated key for a mutating endpoint. It identifies
            one method, route, query, content type, and exact raw body within
            the authenticated app. Reusing it for a different request returns
            422. While its record exists, a retry replays the original accepted
            response when available. Keys are valid for 1 hour. Allowed
            characters: letters, digits, dot, hyphen, underscore; max 128
            characters. See the Idempotency guide.
          required: false
          schema:
            type: string
      responses:
        '202':
          description: Command accepted for async execution
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncCommandResponse'
        '400':
          description: >-
            Missing `Authorization`, malformed Bearer credentials, or invalid
            request parameters. A syntactically valid credential with an invalid
            API key returns `401` instead.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StartAudioPlaybackRequestBadRequestError'
        '401':
          description: >-
            The Bearer credential is syntactically valid but its API key is
            invalid. Missing `Authorization` or malformed Bearer credentials
            return `400`.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/StartAudioPlaybackRequestUnauthorizedError
        '404':
          description: >-
            Session not found. A session owned by a *different* application
            returns this same `404` (never a `403`) so the response cannot be
            used to probe for the existence of another tenant's session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StartAudioPlaybackRequestNotFoundError'
        '409':
          description: A media transition is already in progress; retry after it settles.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StartAudioPlaybackRequestConflictError'
        '413':
          description: Request body exceeds the endpoint's size limit.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/StartAudioPlaybackRequestContentTooLargeError
        '415':
          description: >-
            A request with a JSON body must use `Content-Type:
            application/json`.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/StartAudioPlaybackRequestUnsupportedMediaTypeError
        '422':
          description: >-
            The `Idempotency-Key` was reused with a different request body. A
            key maps to one request; use a new key. See the Idempotency guide.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/StartAudioPlaybackRequestUnprocessableEntityError
        '429':
          description: >-
            Rate limit exceeded — a per-command, per-room, or per-app token
            bucket was empty. The `retry_after` field gives the integer seconds
            to wait before retrying.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/StartAudioPlaybackRequestTooManyRequestsError
        '500':
          description: Internal gateway error.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/StartAudioPlaybackRequestInternalServerError
        '502':
          description: The playback source is unavailable, so the command was not accepted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StartAudioPlaybackRequestBadGatewayError'
        '503':
          description: Playback stop unavailable while replacing active playback.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/StartAudioPlaybackRequestServiceUnavailableError
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Playback_startAudioPlayback_Request'
servers:
  - url: https://api.telekesher.dev
    description: Gateway server
components:
  schemas:
    PlaybackStartAudioPlaybackRequest0:
      type: object
      properties:
        offset_ms:
          type: integer
          description: |-
            Optional starting offset in milliseconds. It is valid only
            with one finite source.
        operation_uuid:
          type: string
          format: uuid
          description: >-
            Optional caller-supplied per-command correlation id, a bare
            lowercase RFC-4122 v4 UUID (no prefix). Echoed back as
            `operation_uuid` in the 202 ack. A later lifecycle webhook carries
            it only when the gateway can unambiguously associate that event with
            this command; the field is correlation, not proof of causation. When
            omitted, the gateway mints one. Not an idempotency key — request
            deduplication is the `Idempotency-Key` header. Invalid input (not a
            v4 UUID) is rejected with `400 invalid_request`.
        type:
          type: string
          enum:
            - files
          description: Selects finite-file playback.
        urls:
          type: array
          items:
            type: string
            format: uri
          description: |-
            HTTP/HTTPS URLs of audio files to play sequentially. With two
            or more URLs, playback is one continuous playlist, but seeking
            across playlist file boundaries is undefined.
      required:
        - type
        - urls
      title: PlaybackStartAudioPlaybackRequest0
    PlaybackStartAudioPlaybackRequest1:
      type: object
      properties:
        operation_uuid:
          type: string
          format: uuid
          description: >-
            Optional caller-supplied per-command correlation id, a bare
            lowercase RFC-4122 v4 UUID (no prefix). Echoed back as
            `operation_uuid` in the 202 ack. A later lifecycle webhook carries
            it only when the gateway can unambiguously associate that event with
            this command; the field is correlation, not proof of causation. When
            omitted, the gateway mints one. Not an idempotency key — request
            deduplication is the `Idempotency-Key` header. Invalid input (not a
            v4 UUID) is rejected with `400 invalid_request`.
        type:
          type: string
          enum:
            - stream
          description: Selects live-stream playback.
        url:
          type: string
          format: uri
          description: The single live HTTP/HTTPS stream to play.
      required:
        - type
        - url
      title: PlaybackStartAudioPlaybackRequest1
    PlaybackStartAudioPlaybackRequest2:
      type: object
      properties:
        operation_uuid:
          type: string
          format: uuid
          description: >-
            Optional caller-supplied per-command correlation id, a bare
            lowercase RFC-4122 v4 UUID (no prefix). Echoed back as
            `operation_uuid` in the 202 ack. A later lifecycle webhook carries
            it only when the gateway can unambiguously associate that event with
            this command; the field is correlation, not proof of causation. When
            omitted, the gateway mints one. Not an idempotency key — request
            deduplication is the `Idempotency-Key` header. Invalid input (not a
            v4 UUID) is rejected with `400 invalid_request`.
        type:
          type: string
          enum:
            - silence
          description: Selects indefinite silence playback until replaced or stopped.
      required:
        - type
      title: PlaybackStartAudioPlaybackRequest2
    Playback_startAudioPlayback_Request:
      oneOf:
        - $ref: '#/components/schemas/PlaybackStartAudioPlaybackRequest0'
        - $ref: '#/components/schemas/PlaybackStartAudioPlaybackRequest1'
        - $ref: '#/components/schemas/PlaybackStartAudioPlaybackRequest2'
      description: >-
        Audio source. `files` uses `urls`, `stream` uses one `url`, and
        `silence` has no source URL. The shapes cannot be mixed.
      title: Playback_startAudioPlayback_Request
    AsyncCommandResponseStatus:
      type: string
      enum:
        - in_progress
        - completed
      title: AsyncCommandResponseStatus
    AsyncCommandResponse:
      type: object
      properties:
        operation_uuid:
          type: string
          format: uuid
        status:
          $ref: '#/components/schemas/AsyncCommandResponseStatus'
        already_ended:
          type: boolean
          enum:
            - true
          description: >-
            Optional. Set to `true` on idempotent terminal commands when the
            session was already in a terminal state at the time the request was
            received. Absent otherwise.
      required:
        - operation_uuid
        - status
      description: >-
        202 Accepted body for an async command. The command's success/failure is
        delivered later as a domain lifecycle webhook (e.g.
        `playback.started`/`stopped`/`failed`,
        `command.recording.start.accepted`, `digits.collected`,
        `session.answered`/`session.ended`). A lifecycle event carries
        `operation_uuid` only when it can be unambiguously associated with the
        submitted command — not as a generic ack on this response.
      title: AsyncCommandResponse
    V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode:
      type: string
      enum:
        - invalid_request
        - payload_too_large
        - result_set_too_large
        - unauthorized
        - forbidden
        - not_found
        - conflict
        - recording_not_active
        - room_full
        - rate_limited
        - unavailable
        - internal
      description: >-
        Stable, machine-readable error class from a closed set of twelve values.
        Branch on this for programmatic handling. New codes are only added with
        a documented API change. Maps to the HTTP status as follows:
        `invalid_request` (400/415/422), `payload_too_large` and
        `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403),
        `not_found` (404), `recording_not_active` (400); `conflict` and
        `room_full` (409), `rate_limited` (429), `unavailable` (502/503/529),
        `internal` (500).


        Note: `413` is the only status shared by two codes — `payload_too_large`
        means the request body exceeded its size cap, while
        `result_set_too_large` means a list response exceeded the system result
        ceiling (narrow the query with filters and retry).


        Note: `unavailable` is the only code that maps to multiple HTTP
        statuses, which represent different retry conditions: `502` means a
        command dependency could not accept the request, `503` means a required
        service (including the idempotency store) is temporarily unavailable,
        and `529` means the gateway is overloaded with no spare capacity. Use
        the HTTP status and operation description, not just `code`, to
        distinguish them.
      title: V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
    StartAudioPlaybackRequestBadRequestError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestBadRequestError
    StartAudioPlaybackRequestUnauthorizedError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestUnauthorizedError
    StartAudioPlaybackRequestNotFoundError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestNotFoundError
    StartAudioPlaybackRequestConflictError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestConflictError
    StartAudioPlaybackRequestContentTooLargeError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestContentTooLargeError
    StartAudioPlaybackRequestUnsupportedMediaTypeError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestUnsupportedMediaTypeError
    StartAudioPlaybackRequestUnprocessableEntityError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestUnprocessableEntityError
    StartAudioPlaybackRequestTooManyRequestsError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - retry_after
        - success
      title: StartAudioPlaybackRequestTooManyRequestsError
    StartAudioPlaybackRequestInternalServerError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestInternalServerError
    StartAudioPlaybackRequestBadGatewayError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestBadGatewayError
    StartAudioPlaybackRequestServiceUnavailableError:
      type: object
      properties:
        code:
          $ref: >-
            #/components/schemas/V1SessionsUuidPlaybackPlayPostResponsesContentApplicationJsonSchemaCode
          description: >-
            Stable, machine-readable error class from a closed set of twelve
            values. Branch on this for programmatic handling. New codes are only
            added with a documented API change. Maps to the HTTP status as
            follows: `invalid_request` (400/415/422), `payload_too_large` and
            `result_set_too_large` (413), `unauthorized` (401), `forbidden`
            (403), `not_found` (404), `recording_not_active` (400); `conflict`
            and `room_full` (409), `rate_limited` (429), `unavailable`
            (502/503/529), `internal` (500).


            Note: `413` is the only status shared by two codes —
            `payload_too_large` means the request body exceeded its size cap,
            while `result_set_too_large` means a list response exceeded the
            system result ceiling (narrow the query with filters and retry).


            Note: `unavailable` is the only code that maps to multiple HTTP
            statuses, which represent different retry conditions: `502` means a
            command dependency could not accept the request, `503` means a
            required service (including the idempotency store) is temporarily
            unavailable, and `529` means the gateway is overloaded with no spare
            capacity. Use the HTTP status and operation description, not just
            `code`, to distinguish them.
        error:
          type: string
          description: >-
            Human-readable, English-only error message. For display only —
            phrasing may change without notice, so branch on `code`, not on this
            string.
        retry_after:
          type: integer
          description: >-
            Integer seconds to wait before retrying. Present on `429` (the time
            until the denying token bucket refills by one token) and on `529`
            (overload back-off hint). Mirrors the `Retry-After` response header.
        success:
          type: boolean
      required:
        - code
        - error
        - success
      title: StartAudioPlaybackRequestServiceUnavailableError
  securitySchemes:
    bearerAppAuth:
      type: http
      scheme: bearer
      description: >-
        Application auth. Send `Authorization: Bearer <app_uuid>:<api_key>`. See
        [Authentication](https://voice-platform.docs.buildwithfern.com/api/authentication)
        for details.

```

## Examples



**Request**

```json
{
  "type": "string",
  "urls": [
    "string"
  ]
}
```

**Response**

```json
{
  "operation_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "in_progress"
}
```

**SDK Code**

```python Playback_startAudioPlayback_example
import requests

url = "https://api.telekesher.dev/v1/sessions/uuid/playback/play"

payload = {
    "type": "string",
    "urls": ["string"]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript Playback_startAudioPlayback_example
const url = 'https://api.telekesher.dev/v1/sessions/uuid/playback/play';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"type":"string","urls":["string"]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Playback_startAudioPlayback_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.telekesher.dev/v1/sessions/uuid/playback/play"

	payload := strings.NewReader("{\n  \"type\": \"string\",\n  \"urls\": [\n    \"string\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Playback_startAudioPlayback_example
require 'uri'
require 'net/http'

url = URI("https://api.telekesher.dev/v1/sessions/uuid/playback/play")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"type\": \"string\",\n  \"urls\": [\n    \"string\"\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Playback_startAudioPlayback_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.telekesher.dev/v1/sessions/uuid/playback/play")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"type\": \"string\",\n  \"urls\": [\n    \"string\"\n  ]\n}")
  .asString();
```

```php Playback_startAudioPlayback_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.telekesher.dev/v1/sessions/uuid/playback/play', [
  'body' => '{
  "type": "string",
  "urls": [
    "string"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Playback_startAudioPlayback_example
using RestSharp;

var client = new RestClient("https://api.telekesher.dev/v1/sessions/uuid/playback/play");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"type\": \"string\",\n  \"urls\": [\n    \"string\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Playback_startAudioPlayback_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "type": "string",
  "urls": ["string"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.telekesher.dev/v1/sessions/uuid/playback/play")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```