---
title: "Upload an image"
method: POST
path: "/v1/images/upload"
tags: ["Images"]
---

# Upload an image

`POST /v1/images/upload`

## Request

- Base URL: `https://www.postquick.ai/api`
- URL: `https://www.postquick.ai/api/v1/images/upload`
- Auth: HTTP bearer

Uploads an image to PostQuickAI storage and returns a public URL hosted on a domain whitelisted by our TikTok developer app. Use this to host externally-generated carousel slides (or any image) on a URL that TikTok will accept when publishing via /v1/posts/create.

Accepts three input shapes:
- multipart/form-data with a `file` field — direct binary upload (best for browsers / curl).
- application/json with a `data` field — base64-encoded raw bytes (best for MCP clients / Claude / ChatGPT that have a file inline but cannot send multipart). Optionally include `contentType` and `fileName`.
- application/json with a `sourceUrl` field — server fetches and re-hosts a public URL (best for re-hosting from your own CDN).

Limits: image/jpeg, image/png, image/webp, image/gif. Max 10MB. Counts against your storage quota.

Typical MCP flow: call `uploadImage` with base64 `data` → take the returned `imageUrl` → pass it as `imageUrl` to `createPost` (or as one entry in `imageUrls` for a carousel).

## Request body

- object
  - `data` string: Raw image bytes encoded as base64. Accepts either a plain base64 string or a full data URL (e.g. "data:image/png;base64,..."). Use this when an MCP client (Claude, ChatGPT, etc.) has the file inline and cannot send multipart/form-data. Max 10MB decoded.
  - `contentType` 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif': MIME type of the inline `data` payload. Optional — the server falls back to the data-URL prefix or magic-byte sniffing if omitted, but providing it is the most reliable.
  - `fileName` string: Optional original file name. Used only to derive a fallback extension.
  - `sourceUrl` string, uri: Publicly accessible image URL to fetch and re-host on PostQuickAI storage. Use this instead of `data` when the image is already hosted somewhere (Cloudinary, S3, your CDN). The resulting URL is on a TikTok-whitelisted domain.

## Response `201`

Image uploaded.

- object
  - `success` true, required
  - `data` object, required
    - `imageUrl` string, uri, required: Public URL of the hosted image. Safe to pass to /v1/posts/create as imageUrl / imageUrls.
    - `contentType` string, required: Detected image MIME type
    - `size` integer, required: Image size in bytes

## Other responses

- `400`: Invalid request (missing file/sourceUrl, unsupported type, oversized).
- `403`: Storage limit exceeded.

---

[API](https://skmtc.dev/postquick/apis/postquickai-api.md) · [All operations](https://skmtc.dev/postquick/apis/postquickai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/postquick/apis/postquickai-api/revisions/d9bc2bcf3042?raw)
