Skip to main content
imgtree
Sign inRegister

© 2026 imgtree — fast image hosting

Free image hostingAboutGuidesChrome extensionAPIPrivacy policyTerms of service

Developer reference

Image upload API

REST API for image hosting — integrate from scripts, ShareX, desktop tools, backends, or your own site.

GET /api/v1/uploadOpenAPI JSONAPI keys

The stable surface for third parties is the Bearer API under /api/v1/ after you create a key in API. Use it as a ShareX custom uploader, presigned upload pipeline, or backend integration. See the ShareX setup guide for a copy-paste custom uploader. OpenAPI (JSON) summarizes the v1 surface; the reference below is the full guide.

Quickstart

  1. Step 1

    Create an API key
    Sign in and open API to generate a Bearer token. Copy it immediately — it is shown once.
  2. Step 2

    Upload an image
    Send POST /api/v1/upload with Authorization: Bearer … and a multipart file field.
  3. Step 3

    Use the direct URL
    The response includes direct_url, thumb_url, and embed codes in codes.

Need limits first? Call GET /api/v1/upload without auth.

← Guest image upload (home)About imgtree

On this page

  • Overview
  • Quickstart
  • Authentication
  • Upload flows
  • Upload endpoints
  • Images
  • Rate limits

Uploads are back to normal. Sorry for the brief outage.

API documentation

This reference is for webmasters and developers who integrate with imgtree: automation, mobile or desktop clients, forum tools (for example ShareX), or server-side scripts.

Base URL: use your site’s origin (for example https://img.example.com). All paths below are rooted at that origin.

Live limits: send an unauthenticated GET /api/v1/upload to receive JSON with the current max file size, allowed image types, rate-limit notes, and a short index of upload-related routes for this deployment.

Browser note: imgtree does not send broad Access-Control-* headers on the API. Call the API from your server or backend, or place your own proxy or edge rules if you need direct browser fetch from third-party pages.


API keys (recommended for integrations)

  1. Create a free account and sign in.
  2. Open Settings (or your dashboard’s API keys section) and create an API key.
  3. Copy the key when it is shown — it is only displayed once.
  4. Send it on every request as:
Authorization: Bearer <your_api_key>

The sections below describe the version 1 HTTP API (/api/v1/...), which uses this header. Keys are tied to your account; uploads count against your storage quota.


Upload flows compared

FlowBest forNotes
Multipart POST /api/v1/uploadShareX, form posts, small/medium filesSimplest; subject to host body-size limits
JSON + base64 POST /api/v1/uploadServer scripts, one image per requestBase64 inflates payload size
Presign → PUT → completeLarge originalsBypasses app-server body limit for the main file

For automation, start with multipart. Switch to presign when files exceed your host’s request body cap or when uploading from a client that already speaks S3-style PUT URLs.

Implementation note: Legacy multipart handlers (POST /api/upload, POST /api/upload/guest, and multipart POST /api/v1/upload) are thin route adapters. They read the request body and delegate to lib/store-image.ts (storeImageFromBuffer), which applies shared type/size policy (lib/upload/image-policy.ts), Sharp thumbnail generation, R2 storage, and DB insert. Response JSON shapes are unchanged. For large originals, prefer presign → PUT → complete so the main file bytes bypass the app server’s HTTP body limit.


Rate limits and quotas

  • Upload rate limit: about 30 requests per minute per client IP on upload routes (see GET /api/v1/upload for the exact wording on this deployment).
  • Storage quota: Bearer uploads count against the API key owner’s account quota.
  • Batch presign / complete: up to 20 files per batch request.
  • Pagination: GET /api/v1/images accepts limit up to 100.

When limited, the API responds with 429 Too Many Requests. Retry with backoff.


GET/api/v1/upload

Returns machine-readable capabilities for this instance: max upload size, allowed MIME types, presigned URL lifetime, batch limits, and brief endpoint descriptions. No Authorization header.

Use this in installers or scripts so you do not hard-code limits.


POST/api/v1/upload

Upload one or more images using multipart (typical for ShareX and form posts) or JSON with base64 for a single image (convenient from servers).

Multipart

Content-Type: multipart/form-data
Authorization: Bearer <your_api_key>

file: <binary>   # repeat the field name "file" for multiple files
albumId: <uuid>  # optional — must belong to your account

JSON (one image per request)

Content-Type: application/json
Authorization: Bearer <your_api_key>
{
  "filename": "screenshot.png",
  "contentType": "image/png",
  "file_base64": "<base64 or data:image/png;base64,...>",
  "albumId": "<optional uuid>"
}

The field base64 is accepted as an alias for file_base64.

Sizing: Base64 increases payload size. For large files, prefer multipart or the presign → PUT → complete flow below.

Unsupported Content-Type: the server responds with 415.

Image types: image/jpeg, image/png, image/gif, image/webp

Max size: Defined by this deployment (see GET /api/v1/upload). Multipart uploads may also be limited by your host’s maximum request body size.

Large files: Use POST /api/v1/upload/presign, PUT the bytes to put_url, then POST /api/v1/upload/complete with completion_token. That path bypasses your app server’s body limit for the main file.

Rate limiting: By default, about 30 requests per minute per client IP (see the discovery response for wording used on this instance).

Response 200

{
  "success": true,
  "images": [
    {
      "id": "abc12xyz",
      "url": "https://{origin}/i/abc12xyz",
      "direct_url": "https://{origin}/direct/{slug}.{ext}",
      "thumb_url": "https://{origin}/thumbnail/{slug}.jpg",
      "delete_url": "https://{origin}/api/images/<uuid>?token=<delete_token>",
      "codes": {
        "bbcode": "[img]https://…[/img]",
        "bbcode_thumb": "[url=https://…][img]https://…/thumb[/img][/url]",
        "html": "<img src=\"https://…\" alt=\"file.jpg\" />",
        "markdown": "![file.jpg](https://…)",
        "direct": "https://…"
      }
    }
  ]
}

id is the image slug (public page /i/{slug}). delete_url uses the internal image UUID.

Common errors

StatusMeaning
401Missing or invalid API key
403Account inactive
429Too many requests
400Bad request (for example no files)
500Server error

Per-file failures in multipart batches appear as objects with an error string instead of URLs.


POST/api/v1/upload/presign

Returns a time-limited URL to upload the original file bytes with PUT, using the same Content-Type you declare.

Request — Content-Type: application/json

{
  "filename": "photo.jpg",
  "contentType": "image/jpeg",
  "sizeBytes": 1234567,
  "albumId": "<optional uuid>"
}

Response 200

{
  "put_url": "https://…",
  "completion_token": "<opaque>"
}

Then: PUT to put_url with the raw bytes and header Content-Type matching contentType.


POST/api/v1/upload/presign/batch

Up to 20 presigns in one call (same auth and album rules as a single presign).

Request — Content-Type: application/json

{
  "albumId": "<optional uuid>",
  "files": [
    { "filename": "a.jpg", "contentType": "image/jpeg", "sizeBytes": 1000 },
    { "filename": "b.png", "contentType": "image/png", "sizeBytes": 2000 }
  ]
}

Response 200

{
  "success": true,
  "uploads": [
    { "put_url": "https://…", "completion_token": "…" },
    { "error": "Filename required", "status": 400 }
  ]
}

Order matches files. After each successful PUT, call complete or complete/batch with the matching tokens.


POST/api/v1/upload/complete

Request — Content-Type: application/json

{ "completion_token": "<from presign>" }

token is accepted as an alias.

Response 200 — Same shape as POST /api/v1/upload (success, images[]).


POST/api/v1/upload/complete/batch

Finalize up to 20 direct uploads after PUT to each put_url.

Request — Content-Type: application/json

{
  "completion_tokens": ["<from presign>", "<from presign>"]
}

tokens is accepted as an alias for completion_tokens.

Response 200

{
  "success": true,
  "images": [
    { "id": "<slug>", "url": "…", "direct_url": "…", "thumb_url": "…", "delete_url": "…", "codes": { } },
    { "error": "Invalid or expired upload token" }
  ]
}

Order matches the input tokens. Your API key’s upload counter increases by the number of successful finalizations.


GET/api/v1/images

Lists images owned by the API key (not deleted), with pagination.

Query: page (default 1), limit (default 24, max 100).

Response 200

{
  "success": true,
  "images": [
    {
      "id": "<uuid>",
      "slug": "…",
      "url": "https://{origin}/i/{slug}",
      "direct_url": "…",
      "thumb_url": "…",
      "original_name": "…",
      "created_at": "…"
    }
  ],
  "page": 1,
  "limit": 24,
  "total": 42,
  "has_more": true
}

DELETE/api/v1/images/[imageId]

Soft-deletes an image by UUID (imageId), using the API key. Behaviour matches an authenticated delete in the web app, without cookies.


ShareX (example custom uploader)

Replace the URL with your site and paste your API key:

{
  "Name": "imgtree",
  "DestinationType": "ImageUploader",
  "RequestMethod": "POST",
  "RequestURL": "https://{your-site}/api/v1/upload",
  "Headers": {
    "Authorization": "Bearer <your_api_key>"
  },
  "Body": "MultipartFormData",
  "FileFormName": "file",
  "URL": "$json:images[0].url$",
  "ThumbnailURL": "$json:images[0].thumb_url$",
  "DeletionURL": "$json:images[0].delete_url$"
}

Multipart vs presigned upload: ShareX’s single-request custom uploader works well with multipart POST /api/v1/upload. If your hosting enforces a small HTTP body limit (often a few megabytes), very large files may fail before they reach the app. For larger files, use presign → PUT → complete from a script or another client, or keep multipart uploads under the limit.


Signed-in session API (cookies)

These routes power the imgtree web app. They expect a logged-in browser session (session cookie), not the Bearer API key. Use them only if you are building tooling that runs as the signed-in user in a trusted environment.

Images

MethodPathDescription
GET/api/imagesPaginated list (page, limit ≤ 100)
PATCH/api/images/[imageId]Update allowed fields (owner only)
DELETE

GET /api/images returns { images, page, limit, total, has_more }.

Albums

MethodPathDescription
GET/api/albumsList albums
POST/api/albumsCreate album
GET/api/albums/[albumId]

API keys (session)

MethodPathDescription
GET/api/keysList keys (metadata only)
POST/api/keysCreate key (secret returned once)
DELETE/api/keys/[keyId]

Upload (session and guest)

MethodPathDescription
POST/api/uploadSigned-in multipart (files, optional albumId, isPublic)
POST/api/upload/presign

Multipart rows above delegate to storeImageFromBuffer (see Upload flows compared). Presign + complete routes use runPresignUpload and the direct-upload completion module instead.


Operator API (admin only)

Reserved for accounts with the admin role.

MethodPathDescription
GET/api/admin/statsAggregated statistics
GET/api/admin/usersUser list / search
PATCH/api/admin/users/[userId]
/api/images/[imageId]
Soft delete; owner session or ?token=<delete_token> from a delete_url (rate limited)
Album detail
PATCH/api/albums/[albumId]Update album
DELETE/api/albums/[albumId]Delete album
Revoke key
Presign for signed-in user
POST/api/upload/completeComplete after PUT (session)
POST/api/upload/guestPublic multipart upload
POST/api/upload/guest/presignGuest presign
POST/api/upload/guest/completeGuest complete after PUT
Update user (role, active state, quota, etc.)