imgpile API

Upload, share, and manage images and videos programmatically.

https://imgpile.com/api/v1 โ€” all endpoints

https://cdn.imgpile.com/api/v1/media โ€” file uploads only (see below)

Get an API token

Log in or register to generate an API token.

Concepts

imgpile has two core objects. Understanding the difference will save you time.

Media

A single file (image or video). Has a direct CDN URL โ€” ideal for hotlinking, embedding, or sharing.

Post

A shareable page containing one or more media items. Has a title, description, voting, comments, and tags.

Just need a direct image URL? Upload to /media. Use urls.original from the response. Done.
Want a shareable post with comments and voting? Upload media first, then call /posts with the media IDs.

Quick Start

Upload a single file and get a direct CDN URL. Perfect for ShareX, Discord bots, or any script that just needs to host an image.

Note: uploads go to cdn.imgpile.com, not imgpile.com.

curl -X POST https://cdn.imgpile.com/api/v1/media \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "[email protected]"

Response:

{ "message": "Media created successfully", "media": { "slug": "abc1234", "type": "image/jpeg", "urls": { "original": "https://cdn.imgpile.com/f/abc1234.jpg", ... } } }

Upload multiple files, then group them into a post with metadata, voting, and comments.

1. Upload each file to cdn.imgpile.com and keep the returned media ID:

curl -X POST https://cdn.imgpile.com/api/v1/media \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "[email protected]" # Returns: { "media": { "id": 12345, ... } }

2. Create a post with those IDs:

curl -X POST https://imgpile.com/api/v1/posts \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"media_ids": [12345, 12346]}' # Returns: { "post": { "slug": "xyz789", ... } }

3. (Optional) Add a title and description:

curl -X PATCH https://imgpile.com/api/v1/posts/xyz789 \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title": "My post", "description": "Summer 2026"}'

Your post is now live at https://imgpile.com/p/xyz789

Upload an image from a browser or Node.js:

const formData = new FormData(); formData.append('file', fileInput.files[0]); const response = await fetch('https://cdn.imgpile.com/api/v1/media', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', }, body: formData, }); const { media } = await response.json(); console.log(media.urls.original); // https://cdn.imgpile.com/f/abc1234.jpg

ShareX setup

Download our Custom Uploader config and import it into ShareX โ€” no manual JSON editing needed.

Download imgpile.sxcu

  1. Click the button above to download imgpile.sxcu.
  2. Double-click the file โ€” ShareX will import it and make imgpile an available uploader.
  3. Open Destinations โ†’ Custom uploader settings โ†’ Headers and replace YOUR_TOKEN_HERE with your API token (generate one in the Introduction).
  4. Set Destinations โ†’ Image uploader โ†’ imgpile. Capture a screenshot โ€” the URL will land on your clipboard as https://cdn.imgpile.com/f/โ€ฆ.

Authentication

Read endpoints (GET) are public and don't require authentication. All other endpoints require a bearer token.

curl https://imgpile.com/api/v1/posts

For authenticated requests, pass your token in the Authorization header:

curl -H "Authorization: Bearer YOUR_TOKEN" https://cdn.imgpile.com/api/v1/media -F "[email protected]"

File uploads target cdn.imgpile.com; see Media โ†’ Upload for details.

Generate a token in the Introduction section above.

Errors

The API returns standard HTTP status codes. Error responses include a JSON body with a message (or error) field describing what went wrong.

Status codes

CodeMeaning
200OK โ€” request succeeded
201Created โ€” resource was created
400Bad Request โ€” malformed request
401Unauthenticated โ€” missing or invalid token
403Forbidden โ€” you don't have permission for this action
404Not Found โ€” resource doesn't exist
422Validation failed โ€” request body has invalid fields
429Rate Limited โ€” too many requests, slow down
451Unavailable for Legal Reasons โ€” file matched a banned hash
500Server Error โ€” something went wrong on our end

Example error responses

401 Unauthenticated

{ "message": "Unauthenticated." }

403 Forbidden

{ "message": "This action is unauthorized." }

422 Validation failed

{ "message": "The file field is required.", "errors": { "file": ["The file field is required."] } }

429 Rate limited

{ "message": "Too Many Attempts." }

Check the Retry-After response header for seconds until the limit resets.

451 Banned content

{ "error": "This file is not allowed." }

API Pagination

List endpoints (GET /posts, GET /media) return paginated results. The default page size is 10; you can request up to 250 with ?limit=N.

Use ?page=N to navigate pages. The response includes pagination metadata:

{ "data": [ ... ], "links": { "first": "https://imgpile.com/api/v1/posts?page=1", "last": "https://imgpile.com/api/v1/posts?page=42", "prev": null, "next": "https://imgpile.com/api/v1/posts?page=2" }, "meta": { "current_page": 1, "from": 1, "to": 10, "per_page": 10, "total": 421, "last_page": 42 } }

When iterating, follow links.next until it's null, or check meta.current_page against meta.last_page.

Content Filtering

By default, list endpoints (GET /posts, GET /media) only return safe content (moderation status approved). To also include adult content (nsfw), pass ?nsfw=1:

curl https://imgpile.com/api/v1/posts?nsfw=1

Banned content (rejected, i.e. spam or abuse) is never returned to public feed endpoints regardless of the ?nsfw flag.

Every post and media response includes a moderation_status field so you can warn, blur, or hide flagged items in your client:

{ "moderation_status": "approved" | "pending" | "nsfw" | "rejected", ... }
  • approved โ€” safe for all audiences.
  • pending โ€” awaiting automated moderation.
  • nsfw โ€” adult content; only returned from public endpoints when ?nsfw=1.
  • rejected โ€” spam/abuse; never returned to public endpoints.

Hidden posts are accessible by their slug but never appear in feeds. Private posts require an ?key=xxx query parameter (the owner can find this in the post's share link).

Rate Limits

  • Public requests (no token): 30 requests/minute per IP
  • Authenticated requests: 120 requests/minute per user
  • File uploads: 1,000 files/day per user/IP
  • Max file size: 100 MB
  • Accepted types: image/* and video/*

Rate limit headers are included in every response (X-RateLimit-Limit, X-RateLimit-Remaining).

The Media object

Returned by media endpoints and embedded inside post responses.

FieldTypeDescription
slugstringUnique 7-character identifier. Used in URLs.
filenamestringStorage filename (same as slug).
titlestring|nullUser-provided title.
descriptionstring|nullUser-provided description.
typestringMIME type โ€” e.g. image/jpeg, video/mp4.
widthintegerPixel width.
heightintegerPixel height.
moderation_statusenumOne of approved, pending, nsfw, or rejected. See Content Filtering.
processedbooleanfalse while sized variants are being generated; true when ready.
created_attimestampISO 8601 timestamp.
urlsobjectCDN URLs at every available size โ€” see Direct Image URLs.
userobject|nullThe uploader (username, avatar). Null for guest uploads.

The Post object

A shareable container for one or more media items.

FieldTypeDescription
idintegerNumeric ID. Use slug for URLs.
slugstringUnique 7-character identifier. Used in URLs.
titlestring|nullPost title.
descriptionstring|nullPost description.
scoreintegerNet vote score (upvotes minus downvotes).
view_countintegerTotal page views.
media_countintegerNumber of media items in this post.
moderation_statusenumOne of approved, pending, nsfw, or rejected. See Content Filtering.
isUpvotedByUserbooleanWhether the authenticated user has upvoted this post.
isDownvotedByUserbooleanWhether the authenticated user has downvoted this post.
created_attimestampISO 8601 timestamp.
userobject|nullThe author (username, avatar). Null for guest posts.
mediaarrayArray of Media objects. Only included on single-post requests.
first_mediaobject|nullThe first media (preview). Only included in feed responses.
Owner-only fields (returned to the post's owner only):
visibilityenumpublic, hidden, or private.
access_keystring|nullRequired to view a private post. Append as ?key=xxx.

Media endpoints

Individual files (images or videos). Each media has a direct CDN URL you can hotlink or embed anywhere.

POST /media Auth required
Upload host

Send uploads to https://cdn.imgpile.com/api/v1/media โ€” not imgpile.com. Files are stored on a dedicated origin; POSTing to the main host will fail.

Every other endpoint uses imgpile.com/api/v1 as usual.

Upload an image or video. Send as multipart/form-data.

ParameterDescription
filerequired The file to upload. Max 100 MB. Accepts image/* and video/*.
post_idoptional Attach to an existing post.
Request
curl -X POST https://cdn.imgpile.com/api/v1/media \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "[email protected]"
Response 201
{ "message": "Media created successfully", "media": { "slug": "abc1234", "filename": "abc1234", "type": "image/jpeg", "width": 1920, "height": 1080, "moderation_status": "approved", "urls": { "original": "https://cdn.imgpile.com/f/abc1234.jpg", ... } } }
GET /media Public

List media items with filtering and pagination.

ParameterDescription
tagFilter by tag name
sortlatest (default) or random
periodday, week, month, year, all
limitResults per page (max 250, default 10)
usernameFilter by username
nsfwSet to 1 to include NSFW content. Default: SFW only.
Request
curl https://imgpile.com/api/v1/media?limit=20
Response 200
{ "data": [ { "slug": "abc1234", "type": "image/jpeg", "width": 1920, "height": 1080, "moderation_status": "approved", "urls": { ... } }, ... ], "links": { ... }, "meta": { "current_page": 1, "total": 421 } }
GET /media/{slug} Public

Get a single media item by its slug.

Request
curl https://imgpile.com/api/v1/media/abc1234
Response 200
{ "data": { "slug": "abc1234", "type": "image/jpeg", "width": 1920, "height": 1080, "moderation_status": "approved", "urls": { ... } } }
PATCH /media/{slug} Auth required

Update media you own.

ParameterDescription
titleMedia title
descriptionMedia description
Request
curl -X PATCH https://imgpile.com/api/v1/media/abc1234 \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title": "New title"}'
Response 200
{ "message": "Media updated successfully" }
DELETE /media/{slug} Auth required

Delete media you own.

Request
curl -X DELETE https://imgpile.com/api/v1/media/abc1234 \ -H "Authorization: Bearer YOUR_TOKEN"
Response 200
{ "message": "Media deleted successfully." }

Post endpoints

Shareable pages that contain one or more media items. Have a title, description, voting, comments, and tags.

GET /posts Public

List public posts with filtering and pagination.

ParameterDescription
tagFilter by tag name
sortlatest (default) or random
periodday, week, month, year, all
limitResults per page (max 250, default 10)
usernameFilter by username
nsfwSet to 1 to include NSFW content. Default: SFW only.
Request
curl https://imgpile.com/api/v1/posts?sort=latest
Response 200
{ "data": [ { "id": 30713, "slug": "MSGhYqy", "title": "Sunset photos", "score": 12, "view_count": 245, "media_count": 3, "moderation_status": "approved", "user": { "username": "alice", ... }, "first_media": { ... } }, ... ] }
GET /posts/{slug} Public

Get a single post with paginated media.

ParameterDescription
mediaPagePage number for media (default 1)
perPageMedia items per page (default 10)
keyRequired for private posts. The owner can find this in the share link.
Request
curl https://imgpile.com/api/v1/posts/MSGhYqy # Private post with key: curl "https://imgpile.com/api/v1/posts/xyz789?key=ab12cd34ef"
Response 200
{ "data": { "id": 30713, "slug": "MSGhYqy", "title": "Sunset photos", "description": "...", "score": 12, "view_count": 245, "moderation_status": "approved", "user": { "username": "alice", ... }, "media": [ ... ] } }
POST /posts Auth required

Create a new post from uploaded media.

ParameterDescription
media_idsrequired Array of media IDs to include in the post
Request
curl -X POST https://imgpile.com/api/v1/posts \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"media_ids": [12345, 12346]}'
Response 201
{ "message": "Post created successfully", "post": { "id": 30720, "slug": "rtWJdHr" } }
PATCH /posts/{slug} Auth required

Update a post you own.

ParameterDescription
titlePost title (max 255)
descriptionPost description
visibilitypublic, hidden, or private. Setting to private auto-generates an access_key.
is_nsfwBoolean. Mark the post as adult content so it's gated behind the viewer's NSFW toggle. Once set, the post will not auto-resolve below nsfw.
media_orderArray of media slugs in desired order
Request
curl -X PATCH https://imgpile.com/api/v1/posts/rtWJdHr \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title": "Updated title", "visibility": "private"}'
Response 200
{ "message": "Post updated successfully", "visibility": "private", "access_key": "ab12cd34ef" }
DELETE /posts/{slug} Auth required

Delete a post you own.

Request
curl -X DELETE https://imgpile.com/api/v1/posts/rtWJdHr \ -H "Authorization: Bearer YOUR_TOKEN"
Response 200
{ "message": "Post deleted successfully" }

Comments

POST /posts/{post}/comments Auth required

Add a comment to a post.

ParameterDescription
contentrequired Comment text (max 500 characters)
parent_idoptional Comment ID to reply to (for threaded replies)
Request
curl -X POST https://imgpile.com/api/v1/posts/MSGhYqy/comments \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"content": "Nice shot!"}'
Response 201
{ "success": true, "comment": { "id": 456, "content": "Nice shot!", "user_id": 1, "post_id": 12345 } }
DELETE /comments/{comment} Auth required

Delete a comment you own.

Request
curl -X DELETE https://imgpile.com/api/v1/comments/123 \ -H "Authorization: Bearer YOUR_TOKEN"
Response 200
{ "success": true, "message": "Comment deleted successfully" }

Users

GET /users/{username}/posts Public

Get a user's posts.

Request
curl https://imgpile.com/api/v1/users/alice/posts
Response 200
{ "data": [ { "id": 30713, "slug": "MSGhYqy", "title": "Sunset photos", "score": 12, "moderation_status": "approved", "first_media": { ... } }, ... ] }
GET /users/{username}/media Public

Get a user's media.

Request
curl https://imgpile.com/api/v1/users/alice/media
Response 200
{ "data": [ { "slug": "abc1234", "type": "image/jpeg", "moderation_status": "approved", "urls": { ... } }, ... ] }
GET /users/{username}/comments Public

Get a user's comments (paginated).

Request
curl https://imgpile.com/api/v1/users/alice/comments
GET /users/{username}/followers Public

Get a user's followers (paginated).

Request
curl https://imgpile.com/api/v1/users/alice/followers
GET /users/{username}/following Public

Get the users this user is following (paginated).

Request
curl https://imgpile.com/api/v1/users/alice/following
POST /users/{username}/follow Auth required

Follow a user.

Request
curl -X POST https://imgpile.com/api/v1/users/alice/follow \ -H "Authorization: Bearer YOUR_TOKEN"
Response 200
{ "message": "User followed." }
DELETE /users/{username}/follow Auth required

Unfollow a user.

Request
curl -X DELETE https://imgpile.com/api/v1/users/alice/follow \ -H "Authorization: Bearer YOUR_TOKEN"
Response 200
{ "message": "User unfollowed." }

Voting

POST /posts/{post}/upvote Auth required

Upvote a post. Calling again removes the upvote.

Request
curl -X POST https://imgpile.com/api/v1/posts/123/upvote \ -H "Authorization: Bearer YOUR_TOKEN"
Response 200
{ "message": "Post upvoted successfully", "score": 13 }
POST /posts/{post}/downvote Auth required

Downvote a post. Calling again removes the downvote.

Request
curl -X POST https://imgpile.com/api/v1/posts/123/downvote \ -H "Authorization: Bearer YOUR_TOKEN"
Response 200
{ "message": "Post downvoted successfully", "score": 11 }
POST /comments/{comment}/upvote Auth required

Upvote a comment. Calling again removes the upvote.

Request
curl -X POST https://imgpile.com/api/v1/comments/456/upvote \ -H "Authorization: Bearer YOUR_TOKEN"
POST /comments/{comment}/downvote Auth required

Downvote a comment. Calling again removes the downvote.

Request
curl -X POST https://imgpile.com/api/v1/comments/456/downvote \ -H "Authorization: Bearer YOUR_TOKEN"

Direct Image URLs

Every uploaded file is served via the CDN. The media response includes a urls object with all available sizes:

https://cdn.imgpile.com/f/{filename}.{ext} โ€” Original https://cdn.imgpile.com/f/{filename}_xs.{ext} โ€” Extra small https://cdn.imgpile.com/f/{filename}_sm.{ext} โ€” Small https://cdn.imgpile.com/f/{filename}_md.{ext} โ€” Medium https://cdn.imgpile.com/f/{filename}_lg.{ext} โ€” Large https://cdn.imgpile.com/f/{filename}_xl.{ext} โ€” Extra large https://cdn.imgpile.com/f/{filename}_thumb.jpg โ€” Thumbnail (videos)
storage.to Free file sharing
25GB files No signup Unlimited speed
Try free