Upload API
Get an API key from your account, then send images from any app.
One endpoint uploads an image from a file, a base64 string or a public URL, and returns its links and embed codes as JSON. It works with ShareX custom uploaders, n8n HTTP Request nodes, and any tool that can send a form upload.
Upload an image
POST https://pinpicx.app/v1/upload
key required your API key (or ?key=, X-API-Key header, or Bearer token)
image required a file, a base64 string, or an http(s) URL
name optional file name
expiration optional delete after N seconds (60 to 15552000)
album optional ID of one of your albums to put the image in
(the last part of the album link, /a/AbC12345)curl -X POST "https://pinpicx.app/v1/upload?key=YOUR_KEY" \ -F "[email protected]" \ -F "expiration=86400"
A successful upload returns HTTP 200:
{
"data": {
"id": "aB3xK9pQ",
"title": "photo",
"url_viewer": "https://pinpicx.app/aB3xK9pQ",
"url": "https://img.pinpicx.app/aB3xK9pQ/photo.jpg",
"display_url": "https://img.pinpicx.app/aB3xK9pQ/m/photo.jpg",
"width": 1920, "height": 1080, "size": 482113,
"time": 1761235200, "expiration": 86400,
"image": { "filename": "photo.jpg", "mime": "image/jpeg", "url": "…" },
"thumb": { "filename": "photo.jpg", "mime": "image/jpeg", "url": "…/t/photo.jpg" },
"medium": { "filename": "photo.jpg", "mime": "image/jpeg", "url": "…/m/photo.jpg" },
"delete_url": "https://pinpicx.app/aB3xK9pQ/delete/…",
"embed": { "html": "…", "html_full": "…", "bbcode": "…", "bbcode_full": "…", "markdown": "…" }
},
"success": true,
"status": 200
}If processing takes longer than a minute the response is HTTP 202 with the image's id; poll GET /v1/images/{id} until it returns 200.
Other endpoints
| Method and path | What it does |
|---|---|
GET /v1/images | Your uploads, newest first. Query: page, per_page (max 100). |
GET /v1/images/{id} | One image's links and details. |
DELETE /v1/images/{id} | Delete with your key, or with ?delete_token=… for a guest upload. |
POST /v1/reports | Report an image. Body: image_id, reason (illegal, nsfw, copyright, spam, other), details. |
Errors
Errors return { "success": false, "status": 413, "error": { "code": "file_too_large", "message": "…" } }.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_image | The file could not be read as an image. |
| 400 | invalid_expiration | Expiration is outside 60 to 15552000 seconds. |
| 401 | invalid_key | The API key is missing, unknown or revoked. |
| 413 | file_too_large | The image is over 32 MB. |
| 415 | unsupported_type | Not JPG, PNG, GIF, WebP, AVIF, BMP or TIFF. SVG and HEIC are not accepted. |
| 422 | blocked_content | This file was removed before and cannot be uploaded again. |
| 404 | not_found | The album doesn't exist or isn't yours. |
| 403 | storage_full | Your account has used its plan's storage. Delete images or upgrade, then try again. |
| 429 | rate_limited | Your account is over its plan's hourly upload limit; see the Retry-After header. |
| 502 | url_fetch_failed | The image URL could not be downloaded. |
Limits
Upload limits count across all of an account's keys and reset on a rolling one-hour window.
| Plan | API keys | API uploads per hour |
|---|---|---|
| Free | 1 | 10 |
| Pro | 5 | 500 |
| Business | 20 | 5,000 |
Versions
Every API path starts with its version: /v1/ is the current one. Changes that could break your code, such as renamed fields or a different response format, only ever come in a new version (/v2/), and /v1/ keeps working when it arrives. New optional fields may be added to /v1/ at any time, so ignore fields you don't use.
Integrations set up with the earlier /1/ paths (for example /1/upload) still work: they are the same as /v1/.
Get a key
Create an account, then open API keys and create a key for each app. Images uploaded with your key appear in My images.