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

# Request media upload

> Get a place for ONE image or video file, then pass its file_url to create_linkedin_post (images[].url or video.url) instead of base64. In a chat without HTTP (the user pasted or has the picture): give the user upload_link, ask them to open it and drop the file, and call create_linkedin_post with file_url once they confirm. With a shell: run the curl line (upload_link, replace <path>). Pass file_type to also get a pre-signed S3 POST form (upload). Never type base64 of a pasted image: the model sees pixels, not the file, and the bytes come out wrong. The link works once for 30 minutes, up to 35 MB, images PNG/JPEG/GIF/WEBP or video MP4/MOV/WEBM (checked by content). The file is public by URL and deleted after 7 days. 120 per workspace per hour.

Contract:
- MCP tool `request_media_upload`, registry package `mcp.id/media_uploads`, mount `id.platform`.
- Operation `action`, response envelope `action`.
- Flags: none.



## OpenAPI

````yaml /api-reference/id/openapi.yaml post /api/media-uploads/request-upload
openapi: 3.0.3
info:
  title: 'GTM API public contract: gtm.service.id'
  description: >-
    Identity, access and money: users, teams and members, API keys, OAuth
    clients and authorizations, billing products, subscriptions, transactions
    and payment methods, notifications, TLS certificates and support requests.


    GENERATED. This document is projected from the Zod MCP tool registry in
    `product/mcp/gtm.mcp` (one tool per public endpoint, 1:1). Do not edit it by
    hand; edit the tool definition and regenerate with `pnpm openapi:public`.


    Surface: the public `/api` contract of `gtm.service.id`, 75 operations. This
    is the only OpenAPI document the platform publishes. Internal (`/internal`)
    and health endpoints are deliberately absent: they are not part of any
    contract, they can change without notice, and the service source is their
    only description.


    Conventions:

    - Auth is a bearer JWT, optionally narrowed by the `Team-SID` header.

    - Every success body is an MCP envelope: `success: true` plus one typed
    `operation` shape (`search`, `get`, `create`, `update`, `delete`, `metrics`,
    `group_by`, `action`), and a `meta` block with `trace_id` for support.

    - Every failure is the same `McpError` envelope with a code from a fixed
    16-code taxonomy, so a client maps errors once.

    - Lists page with `page_size` (0 to 500, default 50) plus an opaque forward
    `cursor`; `page_size: 0` returns counts only.

    - On `GET` and `DELETE`, object-valued query parameters (`filter`, `sort`)
    travel as JSON text and array-valued ones repeat as `name[]=value`.

    - The MCP-only `_meta` field (usage analytics) never reaches the backend and
    is not part of this contract.
  version: '1.0'
  contact:
    name: GTM API
    url: https://gtm-api.com
    email: support@gtm-api.com
  license:
    name: Proprietary
    url: https://gtm-api.com/license
servers:
  - url: https://app.gtm-api.com/id/v4
    description: Production, through the app.gtm-api.com gateway
security:
  - BearerJwt: []
    TeamSid: []
tags:
  - name: account_shares
    description: Registry package `mcp.id/account_shares`, served on MCP mount `id.access`.
  - name: api_keys
    description: Registry package `mcp.id/api_keys`, served on MCP mount `id.access`.
  - name: api_requests
    description: Registry package `mcp.id/api_requests`, served on MCP mount `id.platform`.
  - name: billing_payment_methods
    description: >-
      Registry package `mcp.id/billing_payment_methods`, served on MCP mount
      `id.billing`.
  - name: billing_products
    description: >-
      Registry package `mcp.id/billing_products`, served on MCP mount
      `id.billing`.
  - name: billing_subscriptions
    description: >-
      Registry package `mcp.id/billing_subscriptions`, served on MCP mount
      `id.billing`.
  - name: billing_transactions
    description: >-
      Registry package `mcp.id/billing_transactions`, served on MCP mount
      `id.billing`.
  - name: media_uploads
    description: >-
      Registry package `mcp.id/media_uploads`, served on MCP mount
      `id.platform`.
  - name: notifications
    description: >-
      Registry package `mcp.id/notifications`, served on MCP mount
      `id.platform`.
  - name: oauth_authorizations
    description: >-
      Registry package `mcp.id/oauth_authorizations`, served on MCP mount
      `id.access`.
  - name: oauth_clients
    description: Registry package `mcp.id/oauth_clients`, served on MCP mount `id.access`.
  - name: sessions
    description: Registry package `mcp.id/sessions`, served on MCP mount `id.identity`.
  - name: ssl_certificates
    description: >-
      Registry package `mcp.id/ssl_certificates`, served on MCP mount
      `id.platform`.
  - name: support_requests
    description: >-
      Registry package `mcp.id/support_requests`, served on MCP mount
      `id.platform`.
  - name: team_members
    description: Registry package `mcp.id/team_members`, served on MCP mount `id.identity`.
  - name: teams
    description: Registry package `mcp.id/teams`, served on MCP mount `id.identity`.
  - name: users
    description: Registry package `mcp.id/users`, served on MCP mount `id.identity`.
paths:
  /api/media-uploads/request-upload:
    post:
      tags:
        - media_uploads
      summary: Request media upload
      description: >-
        Get a place for ONE image or video file, then pass its file_url to
        create_linkedin_post (images[].url or video.url) instead of base64. In a
        chat without HTTP (the user pasted or has the picture): give the user
        upload_link, ask them to open it and drop the file, and call
        create_linkedin_post with file_url once they confirm. With a shell: run
        the curl line (upload_link, replace <path>). Pass file_type to also get
        a pre-signed S3 POST form (upload). Never type base64 of a pasted image:
        the model sees pixels, not the file, and the bytes come out wrong. The
        link works once for 30 minutes, up to 35 MB, images PNG/JPEG/GIF/WEBP or
        video MP4/MOV/WEBM (checked by content). The file is public by URL and
        deleted after 7 days. 120 per workspace per hour.


        Contract:

        - MCP tool `request_media_upload`, registry package
        `mcp.id/media_uploads`, mount `id.platform`.

        - Operation `action`, response envelope `action`.

        - Flags: none.
      operationId: request_media_upload
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestMediaUploadRequest'
      responses:
        '200':
          description: '`action` success envelope.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestMediaUploadResponse'
        4XX:
          $ref: '#/components/responses/McpClientError'
        5XX:
          $ref: '#/components/responses/McpServerError'
components:
  schemas:
    RequestMediaUploadRequest:
      type: object
      description: Request body of `request_media_upload`.
      properties:
        purpose:
          type: string
          enum:
            - post_media
          description: >-
            What the file is for. post_media (the default): an image or video
            for create_linkedin_post.
        file_name:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            Optional file name, e.g. "q3-chart.png". Characters outside A-Z a-z
            0-9 . _ - become "-" in the stored name. Omit when you do not know
            it yet.
        file_type:
          type: string
          enum:
            - image/png
            - image/jpeg
            - image/gif
            - image/webp
            - video/mp4
            - video/quicktime
            - video/webm
          description: >-
            Optional MIME type, one the purpose takes. Given, it also mints the
            pre-signed S3 form with this Content-Type bound in. The upload_link
            needs no type: it reads it from the file.
    RequestMediaUploadResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            purpose:
              type: string
              description: >-
                What the slot is for (post_media today); it decides the accepted
                file types.
            upload_link:
              type: string
              description: >-
                One-time link on our domain, valid until upload_expires_at. A
                person opens it in a browser and drops the file; a shell sends
                it with the curl line. Accepts one successful upload.
            upload:
              type: object
              nullable: true
              properties:
                url:
                  type: string
                  description: The S3 form action to POST to.
                method:
                  type: string
                  enum:
                    - POST
                enctype:
                  type: string
                  enum:
                    - multipart/form-data
                fields:
                  type: object
                  additionalProperties:
                    type: string
                  description: Send EVERY entry verbatim as a form field, before the file.
                file_field:
                  type: string
                  enum:
                    - file
                  description: >-
                    The form field that carries the bytes; it must be the LAST
                    part of the form.
              required:
                - url
                - method
                - enctype
                - fields
                - file_field
              description: >-
                A pre-signed S3 POST form for the same object, only when
                file_type was given; null otherwise.
            file_url:
              type: string
              description: >-
                The object's public https URL once uploaded: pass it as
                images[].url or video.url.
            upload_expires_at:
              type: string
              description: 'ISO 8601: the form refuses uploads after this.'
            retained_until:
              type: string
              description: 'ISO 8601: the object is deleted after this.'
            max_byte_size:
              type: integer
              description: The largest file the form accepts, in bytes.
            curl:
              type: string
              description: >-
                A ready upload command through upload_link: replace <path> with
                the local file path. Answers 201 with the stored type and size.
          required:
            - purpose
            - upload_link
            - upload
            - file_url
            - upload_expires_at
            - retained_until
            - max_byte_size
            - curl
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: >-
                The team this call ran in (the token team, or the team_sid
                override). Null when unauthenticated; absent from pre-2026-08-20
                backends.
            actor_type:
              type: string
              nullable: true
              description: >-
                user | agent | api_key | system. Null when unauthenticated;
                absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    McpError:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - validation_failed
                - nothing_to_update
                - not_found
                - relation_not_found
                - invalid_transition
                - limit_exceeded
                - payment_required
                - duplicate_rejected
                - conflict
                - delete_blocked
                - unauthorized
                - forbidden
                - rate_limited
                - internal_error
                - service_unavailable
                - not_implemented
            message:
              type: string
            recoverable:
              type: boolean
            suggestion:
              type: string
            field_errors:
              type: object
              additionalProperties:
                type: array
                items:
                  type: object
                  properties:
                    rule:
                      type: string
                    message:
                      type: string
                  required:
                    - rule
                    - message
            blockers:
              type: array
              items:
                type: object
                properties:
                  type:
                    type: string
                    description: >-
                      Machine-readable blocker type (active_flow, pending_tasks,
                      …).
                  severity:
                    type: string
                    enum:
                      - hard
                      - soft
                    description: >-
                      hard = external action required; soft = acknowledge is
                      enough.
                  description:
                    type: string
                  entity_sid:
                    type: string
                    nullable: true
                  count:
                    type: integer
                  resolution:
                    type: string
                    description: 'Hard: tool name to call. Soft: code for acknowledge[].'
                  resolution_hint:
                    type: string
                required:
                  - type
                  - severity
                  - description
                  - entity_sid
                  - resolution
                  - resolution_hint
            context:
              type: object
              additionalProperties: {}
          required:
            - code
            - message
            - recoverable
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: >-
                The team this call ran in (the token team, or the team_sid
                override). Null when unauthenticated; absent from pre-2026-08-20
                backends.
            actor_type:
              type: string
              nullable: true
              description: >-
                user | agent | api_key | system. Null when unauthenticated;
                absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - error
  responses:
    McpClientError:
      description: >-
        MCP error envelope. `error.code` is one of validation_failed,
        nothing_to_update, not_found, relation_not_found, invalid_transition,
        limit_exceeded, payment_required, duplicate_rejected, conflict,
        delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/McpError'
    McpServerError:
      description: >-
        MCP error envelope with `error.code` internal_error or
        service_unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/McpError'
  securitySchemes:
    BearerJwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Access token issued by gtm.service.id. Its `access_identity` claim
        carries `team_sid`, `actor_sid` and `actor_type`, and that team scope is
        authoritative.
    TeamSid:
      type: apiKey
      in: header
      name: Team-SID
      description: >-
        Team scope for tokens that do not carry one. Ignored when the token
        already names a team.

````