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

# Get Batch Upload URLs

> Generate pre-signed S3 PUT URLs for one or more sides on a service request.

**Required for private-CDN organizations.** `GET /intent` writes to the public bucket and cannot route private uploads. Public-CDN organizations may keep using `/intent`.

Authenticate with your `leo_` API key. Then `PUT` each image to the returned `signed_url` without an `Authorization` header.

See [Private CDN](/partner/private-media).

<Warning>Private-CDN organizations must use this endpoint instead of <code>GET /intent</code>. <code>/intent</code> always writes to the public bucket.</Warning>

<Note>Do not send <code>Authorization</code> on the S3 <code>PUT</code>. Only this request uses your API key. See <a href="/partner/private-media">Private CDN</a>.</Note>


## OpenAPI

````yaml /openapi.json post /api/media/signed-urls/{sr_uuid}
openapi: 3.1.0
info:
  title: Legitmark Partner API
  description: Comprehensive partner integration API for Legitmark authentication platform
  version: 2.0.0
  contact:
    name: Legitmark Support
    email: support@legitmark.com
    url: https://legitmark.com
servers:
  - url: https://api.legitmark.com
    description: Production API
  - url: https://staging.api.legitmark.com
    description: Staging API
  - url: https://dev.api.legitmark.com
    description: Development API
security:
  - BearerAuth: []
tags:
  - name: Service Requests
    description: Create, retrieve, and manage authentication service requests.
  - name: Media Management
    description: >-
      Upload images for service request authentication. Public-CDN organizations
      use GET /intent. Private-CDN organizations use POST
      /api/media/signed-urls/{sr_uuid}.
  - name: Taxonomy
    description: Browse categories, types, brands, models, and services to build requests.
paths:
  /api/media/signed-urls/{sr_uuid}:
    post:
      tags:
        - Media Management
      summary: Get Batch Upload URLs
      description: >-
        Generate pre-signed S3 PUT URLs for one or more sides on a service
        request.


        **Required for private-CDN organizations.** `GET /intent` writes to the
        public bucket and cannot route private uploads. Public-CDN organizations
        may keep using `/intent`.


        Authenticate with your `leo_` API key. Then `PUT` each image to the
        returned `signed_url` without an `Authorization` header.


        See [Private CDN](/partner/private-media).
      operationId: generateBatchSignedUrls
      parameters:
        - name: sr_uuid
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Service request UUID
          example: 8e61c991-553a-4a58-9eb6-561b64c11908
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - sides
              properties:
                sides:
                  type: array
                  minItems: 1
                  description: One entry per photo to upload
                  items:
                    $ref: '#/components/schemas/BatchSignedUrlSide'
                expires_in:
                  type: integer
                  minimum: 60
                  maximum: 3600
                  default: 900
                  description: Upload-URL lifetime in seconds. Default 900 (15 minutes).
            example:
              sides:
                - uuid: ec883c70-f896-47c9-81b6-8d6ff0b5856a
                  filename: ec883c70-f896-47c9-81b6-8d6ff0b5856a.jpg
                  content_type: image/jpeg
              expires_in: 900
      responses:
        '200':
          description: Batch signed URLs generated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: Batch signed URLs generated successfully.
                  urls:
                    type: object
                    additionalProperties:
                      $ref: '#/components/schemas/SignedUploadUrl'
                    description: Map of side UUID to signed upload URL
                  metadata:
                    type: object
                    properties:
                      total_urls:
                        type: integer
                        example: 1
                      failed_urls:
                        type: integer
                        example: 0
                      sr_uuid:
                        type: string
                        format: uuid
                      expires_in:
                        type: integer
                        example: 900
              example:
                success: true
                message: Batch signed URLs generated successfully.
                urls:
                  ec883c70-f896-47c9-81b6-8d6ff0b5856a:
                    signed_url: >-
                      https://s3.us-east-1.amazonaws.com/cdn.legitmark.com/org/9d31b4b9-13c5-4db4-8893-a792736965ef/sr/8e61c991-553a-4a58-9eb6-561b64c11908/ec883c70-f896-47c9-81b6-8d6ff0b5856a.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Expires=900&X-Amz-Signature=...
                    expires_at: '2026-09-01T08:15:00.000Z'
                    is_multipart: false
                metadata:
                  total_urls: 1
                  failed_urls: 0
                  sr_uuid: 8e61c991-553a-4a58-9eb6-561b64c11908
                  expires_in: 900
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
        '403':
          description: Caller is not allowed to upload media for this service request
        '404':
          description: Service request not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - BearerAuth: []
      x-codeSamples:
        - lang: javascript
          label: JavaScript
          source: >-
            const response = await fetch(
              'https://api.legitmark.com/api/media/signed-urls/8e61c991-553a-4a58-9eb6-561b64c11908',
              {
                method: 'POST',
                headers: {
                  Authorization: 'Bearer leo_your_api_key',
                  'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                  sides: [
                    {
                      uuid: 'ec883c70-f896-47c9-81b6-8d6ff0b5856a',
                      filename: 'ec883c70-f896-47c9-81b6-8d6ff0b5856a.jpg',
                      content_type: 'image/jpeg',
                    },
                  ],
                  expires_in: 900,
                }),
              }
            );

            const { urls } = await response.json();


            await fetch(urls['ec883c70-f896-47c9-81b6-8d6ff0b5856a'].signed_url,
            {
              method: 'PUT',
              body: imageFile,
              headers: { 'Content-Type': 'image/jpeg' },
            });
        - lang: curl
          label: cURL
          source: >-
            curl -X POST
            'https://api.legitmark.com/api/media/signed-urls/8e61c991-553a-4a58-9eb6-561b64c11908'
            \
              -H 'Authorization: Bearer leo_your_api_key' \
              -H 'Content-Type: application/json' \
              -d '{
                "sides": [
                  {
                    "uuid": "ec883c70-f896-47c9-81b6-8d6ff0b5856a",
                    "filename": "ec883c70-f896-47c9-81b6-8d6ff0b5856a.jpg",
                    "content_type": "image/jpeg"
                  }
                ],
                "expires_in": 900
              }'

            curl -X PUT 'SIGNED_URL_FROM_ABOVE' \
              -H 'Content-Type: image/jpeg' \
              --data-binary @photo.jpg
components:
  schemas:
    BatchSignedUrlSide:
      type: object
      required:
        - uuid
        - filename
      properties:
        uuid:
          type: string
          format: uuid
          description: Side UUID to upload
          example: ec883c70-f896-47c9-81b6-8d6ff0b5856a
        filename:
          type: string
          description: >-
            Object filename. Use `{side_uuid}.jpg` (or `.png`). The extension
            sets the upload content type.
          example: ec883c70-f896-47c9-81b6-8d6ff0b5856a.jpg
        content_type:
          type: string
          description: Optional MIME type for the upload
          example: image/jpeg
    SignedUploadUrl:
      type: object
      properties:
        signed_url:
          type: string
          format: uri
          description: >-
            Pre-signed S3 PUT URL. Do not send an Authorization header on the
            PUT.
        expires_at:
          type: string
          format: date-time
          description: When this upload URL expires
        is_multipart:
          type: boolean
          description: Always false for the partner batch path today
          example: false
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: integer
            timestamp:
              type: string
              format: date-time
            message:
              type: string
            details:
              type: string
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer token authentication. Use your API key in the format: Bearer
        leo_xxxxxxxx
      x-default: leo_your_api_key_here

````