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

# Upload Media

> Uploads a file to Meta's resumable upload API and returns a **media handle**.

Two endpoints consume that handle: Create Template uses it as the header example for an `IMAGE`, `VIDEO`, or `DOCUMENT` header, and Update Business Profile uses it as `profilePictureReference`. Neither accepts raw file bytes or a public URL.

The endpoint runs both Meta steps in one call: it creates an upload session for the file length and content type, then uploads the bytes and reads back the handle. Content type is derived from the uploaded part, validated against the allowed list, and checked against the size limit for its media type — all before anything reaches Meta.

**Limits.** Image (`image/jpeg`, `image/png`) up to 5 MB, video (`video/mp4`) up to 16 MB, document (`application/pdf`) up to 100 MB. Anything else is rejected with `422`.

**A handle is single-use.** It is consumed by the first request that references it and cannot be replayed. The same image used in two templates needs two uploads. Never cache or share handles.

This is the one Public API endpoint that is not JSON — the body is `multipart/form-data`.



## OpenAPI

````yaml /public-openapi.json post /wa/{app_id}/media/upload
openapi: 3.0.3
info:
  title: Connexease Public API
  version: 1.0.0
  description: >-
    Panel-independent API for managing WhatsApp Business operations from your
    own servers.


    Every endpoint is scoped to the organization resolved from your secret key.
    Read endpoints are uncached and proxy straight to the source.


    **On-premises installations** are served from your own domain with an extra
    `/public` segment: `https://{your_domain}/public/api/v1/...`.
    Authentication, bodies, responses, and error codes are identical.
servers:
  - url: https://public-api.gateway.connexease.com/api/v1
    description: Production
security:
  - secretKey: []
tags:
  - name: Analytics
    description: Organization-wide message volume.
  - name: Application
    description: The WhatsApp business profile linked to an application.
  - name: Template
    description: >-
      The full template lifecycle: create, list, inspect, update, delete, and
      measure.
  - name: Media
    description: >-
      Uploads that produce the single-use handle for template headers and the
      profile picture.
  - name: Developers
    description: Webhook configuration and API keys.
paths:
  /wa/{app_id}/media/upload:
    post:
      tags:
        - Media
      summary: Upload Media
      description: >-
        Uploads a file to Meta's resumable upload API and returns a **media
        handle**.


        Two endpoints consume that handle: Create Template uses it as the header
        example for an `IMAGE`, `VIDEO`, or `DOCUMENT` header, and Update
        Business Profile uses it as `profilePictureReference`. Neither accepts
        raw file bytes or a public URL.


        The endpoint runs both Meta steps in one call: it creates an upload
        session for the file length and content type, then uploads the bytes and
        reads back the handle. Content type is derived from the uploaded part,
        validated against the allowed list, and checked against the size limit
        for its media type — all before anything reaches Meta.


        **Limits.** Image (`image/jpeg`, `image/png`) up to 5 MB, video
        (`video/mp4`) up to 16 MB, document (`application/pdf`) up to 100 MB.
        Anything else is rejected with `422`.


        **A handle is single-use.** It is consumed by the first request that
        references it and cannot be replayed. The same image used in two
        templates needs two uploads. Never cache or share handles.


        This is the one Public API endpoint that is not JSON — the body is
        `multipart/form-data`.
      operationId: uploadMedia
      parameters:
        - $ref: '#/components/parameters/AppId'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: >-
                    The file part. Its MIME type must be one of `image/jpeg`,
                    `image/png`, `video/mp4`, `application/pdf`, and its size
                    must stay within that media type's limit. Both the media
                    type and the size are resolved from the uploaded part, so
                    they are not sent separately.
      responses:
        '200':
          description: >-
            The media handle. It identifies the uploaded bytes on Meta's side;
            it is not a public URL and cannot be fetched directly.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      handle:
                        type: string
                        description: >-
                          Pass as the header example when creating a template
                          with a media header, or as `profilePictureReference`
                          when updating the business profile. Valid for exactly
                          one such use.
                  isSuccess:
                    type: boolean
                    enum:
                      - true
              example:
                data:
                  handle: 4::aW1hZ2UvcG5n:ARZ9k1sample_handle_value
                isSuccess: true
        '400':
          description: >-
            Meta rejected a parameter while creating the session (`META_070`) or
            uploading the bytes (`META_073`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: >-
            Secret key missing or invalid (`ORGANIZATION_SECRET_010` / `011`),
            or Meta token invalid or expired (`META_068` / `META_071`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '404':
          $ref: '#/components/responses/AppNotFound'
        '422':
          description: >-
            Rejected before reaching Meta: content type not allowed
            (`WA_VAL_003`), file over the size limit for its media type
            (`WA_VAL_004`), resolved media type not one of image / video /
            document (`WA_VAL_002`), or the `file` part missing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                errors:
                  code: WA_VAL_004
                  group: VALIDATION
                  description: File size 9437184 bytes exceeds maximum 5242880 bytes.
                isSuccess: false
        '429':
          description: >-
            Meta rate limit while creating the session (`META_069`) or uploading
            (`META_072`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '502':
          description: >-
            General Meta-side failure creating the upload session (`META_015`)
            or uploading the bytes (`META_016`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
components:
  parameters:
    AppId:
      name: app_id
      in: path
      required: true
      description: >-
        Application ID. Must belong to the organization resolved from your
        secret key, otherwise the request returns `404` with `APPLICATION_004`.
      schema:
        type: string
        example: app_7poyXj8GXuv76e
  schemas:
    ErrorEnvelope:
      type: object
      description: >-
        Every failure shares this shape. `description` already has any `params`
        interpolated into it.
      properties:
        isSuccess:
          type: boolean
          enum:
            - false
        errors:
          type: object
          properties:
            code:
              type: string
              description: >-
                `VAL_*`, `WA_*`, `META_*`, `APPLICATION_*`,
                `ORGANIZATION_SECRET_*`, `REQ_001`, or `SYS_001`.
              example: META_075
            group:
              type: string
              enum:
                - VALIDATION
                - NOT_FOUND
                - CONFLICT
                - AUTHENTICATION
                - NOT_ALLOWED
                - LIMIT_EXCEEDED
                - SERVICE_UNAVAILABLE
                - SYSTEM
            description:
              type: string
              example: Template with 0000000000 not found in Meta.
            params:
              type: object
              additionalProperties: true
              description: >-
                Raw values interpolated into `description`. Present only on
                parametric messages.
            fields:
              type: object
              description: >-
                Field-level validation errors only. Field name (dot-joined for
                nested fields, list indices omitted) to its own `code` /
                `description` / `params`.
              additionalProperties:
                type: object
                properties:
                  code:
                    type: string
                  description:
                    type: string
                  params:
                    type: object
                    additionalProperties: true
          required:
            - code
            - group
            - description
      required:
        - isSuccess
        - errors
  responses:
    AppNotFound:
      description: '`app_id` does not belong to the organization (`APPLICATION_004`).'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  securitySchemes:
    secretKey:
      type: http
      scheme: bearer
      description: >-
        Secret key in `Bearer sk_...` format. Server-to-server only — never
        embed it in a browser or mobile client. The organization is resolved
        from the key, so `organization_id` is never passed explicitly.

````