Loops Uploads API

Upload image assets for use in emails via a presigned-URL flow. 2 operation(s) in the Loops REST API v1 (OpenAPI 1.21.6).

Operations 2

Each operation below carries the questions people ask an LLM about it and the instructions they give an agent to run it. Generated by API Evangelist overlay

POST /v1/uploads Request a pre-signed URL to upload an image · Create an upload #
Ask an LLM
“How do I upload an image to use in my emails?”
“What image types and file sizes can I upload?”
Tell an agent
Get an upload URL for a {contentType} image of {contentLength} bytes.
Start an image upload of type {contentType}, size {contentLength} bytes.
POST /v1/uploads/{emailAssetId}/complete Finalize an image upload · Complete an upload #
Ask an LLM
“What do I do after putting the file to the pre-signed URL?”
“How do I get the public URL of an image I uploaded?”
Tell an agent
Complete upload {emailAssetId}.
Finalize image asset {emailAssetId} and give me its public URL.

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/loops:loops-uploads-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

loops-uploads-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Loops OpenAPI Spec Uploads API
  description: This is the OpenAPI Spec for the Loops API.
  version: 1.21.6
servers:
- url: https://app.loops.so/api
tags:
- name: Uploads
  description: Upload image assets
paths:
  /v1/uploads:
    post:
      operationId: createUpload
      tags:
      - Uploads
      summary: Create an upload
      description: Request a pre-signed URL to upload an image asset. Upload the file with an HTTP `PUT` to the returned `presignedUrl` (sending the same `Content-Type` and `Content-Length`), then call `/uploads/{emailAssetId}/complete` to finalize the asset.
      x-mint:
        href: /api-reference/create-upload
        content: Request a pre-signed URL to upload an image asset. Upload the file with an HTTP `PUT` to the returned `presignedUrl` (sending the same `Content-Type` and `Content-Length`), then call [Complete an upload](/api-reference/complete-upload) to finalize the asset.
        metadata:
          description: Request a pre-signed URL to upload an image asset.
          sidebarTitle: Create an upload
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUploadRequest'
      responses:
        '200':
          description: Pre-signed upload URL created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateUploadResponse'
        '400':
          description: Invalid request body or unsupported `contentType`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadFailureResponse'
        '401':
          description: Invalid API key or content API not enabled for this team.
        '405':
          description: Wrong HTTP request method.
        '413':
          description: Upload exceeds the maximum allowed size.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadFailureResponse'
      security:
      - apiKey: []
  /v1/uploads/{emailAssetId}/complete:
    parameters:
    - name: emailAssetId
      in: path
      required: true
      description: The `emailAssetId` returned when the upload was created via `POST /v1/uploads`.
      schema:
        type: string
        examples:
        - cla3s5s7e9t1i3d5f7g9h1j3
    post:
      operationId: completeUpload
      tags:
      - Uploads
      summary: Complete an upload
      description: Finalize an image upload after the file has been uploaded to the pre-signed URL. Returns the public URL of the uploaded image asset.
      x-mint:
        href: /api-reference/complete-upload
        metadata:
          description: Finalize an image upload after the file has been uploaded to the pre-signed URL.
      responses:
        '200':
          description: Upload completed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompleteUploadResponse'
        '400':
          description: Upload id is missing or the uploaded file has an unsupported content type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadFailureResponse'
        '401':
          description: Invalid API key or content API not enabled for this team.
        '404':
          description: Upload not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '429':
          description: Upload limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadLimitExceededFailureResponse'
      security:
      - apiKey: []
components:
  schemas:
    UploadFailureResponse:
      type: object
      properties:
        message:
          type: string
          examples:
          - Unsupported content type.
        supportedContentTypes:
          type: array
          description: Present when the request was rejected for an unsupported `contentType`. Lists the accepted MIME types.
          items:
            type: string
        maxBytes:
          type: integer
          description: Present when the upload exceeds the size limit. The maximum allowed size in bytes.
      required:
      - message
      examples:
      - message: Unsupported content type.
        supportedContentTypes:
        - image/jpeg
        - image/png
        - image/gif
        - image/webp
        maxBytes: 4000000
    CompleteUploadResponse:
      type: object
      properties:
        emailAssetId:
          type: string
          examples:
          - cla3s5s7e9t1i3d5f7g9h1j3
          description: The ID of the created asset.
        finalUrl:
          type: string
          description: The public URL of the uploaded asset.
          examples:
          - https://assets.loops.so/cla3s5s7e9t1i3d5f7g9h1j3/logo.png
      required:
      - emailAssetId
      - finalUrl
      examples:
      - emailAssetId: cla3s5s7e9t1i3d5f7g9h1j3
        finalUrl: https://assets.loops.so/cla3s5s7e9t1i3d5f7g9h1j3/logo.png
    CreateUploadResponse:
      type: object
      properties:
        emailAssetId:
          type: string
          examples:
          - cla3s5s7e9t1i3d5f7g9h1j3
          description: The ID of the created asset. Pass this as `emailAssetId` to `POST /v1/uploads/{emailAssetId}/complete` once the file has been uploaded.
        presignedUrl:
          type: string
          description: The pre-signed URL to upload the file to with an HTTP `PUT` request. Send the same `Content-Type` and `Content-Length` used in the create request.
          examples:
          - https://loops-assets.s3.amazonaws.com/uploads/cla3s5s7e9t1i3d5f7g9h1j3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
      required:
      - emailAssetId
      - presignedUrl
      examples:
      - emailAssetId: cla3s5s7e9t1i3d5f7g9h1j3
        presignedUrl: https://loops-assets.s3.amazonaws.com/uploads/cla3s5s7e9t1i3d5f7g9h1j3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
    CreateUploadRequest:
      type: object
      properties:
        contentType:
          type: string
          description: The MIME type of the file to upload. Supported types are `image/jpeg`, `image/png`, `image/gif` and `image/webp`.
          examples:
          - image/png
        contentLength:
          type: integer
          description: The size of the file in bytes. Must be a positive integer no greater than 4,000,000 bytes.
          examples:
          - 102400
      required:
      - contentType
      - contentLength
      additionalProperties: false
    UploadLimitExceededFailureResponse:
      type: object
      properties:
        message:
          type: string
          examples:
          - 'Upload limit exceeded: max 50 uploads per 24 hours. Please contact support if you need to increase your upload limit.'
        maxUploads:
          type: integer
          description: The maximum number of uploads allowed per window.
          examples:
          - 50
        windowHours:
          type: integer
          description: The number of hours in the upload limit window.
          examples:
          - 24
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer