Skip to Content
APIAPI Endpoints Reference

API Endpoints Reference

Complete reference for all public Pichr API endpoints accessible with API keys. All requests should be made to https://api.pichr.io/api/v1.

Base URL

https://api.pichr.io/api/v1

Authentication

All endpoints support authentication via API keys:

Authorization: Bearer pk_your_api_key_here

Learn more in the Authentication Guide.


Upload Endpoints

Base path: /upload

POST /upload/presign

Request presigned URL for file upload.

Headers: Authorization: Bearer {api_key} (optional for anonymous uploads)

Request Body:

{ "filename": "image.jpg", "mime": "image/jpeg", "bytes": 524288, "sha256": "abc123...", "title": "My Image", "description": "Image description", "visibility": "public", "expiresIn": 24 }

Response:

{ "uploadId": "upl_xyz789", "uploadUrl": "https://api.pichr.io/api/v1/upload/direct/{fileId}", "fileId": "file_abc123", "r2Key": "uploads/2025-11-13/file_abc123/image.jpg", "message": "File record created..." }

Error Responses:

  • 413 Payload Too Large: File exceeds size limit for plan
  • 402 Payment Required: Storage quota exceeded
  • 429 Too Many Requests: Rate limit exceeded

PUT /upload/direct/:fileId

Upload file data directly to R2.

Headers:

  • Authorization: Bearer {api_key}
  • Content-Type: {mime-type}

Body: Binary file data

Response:

{ "fileId": "file_abc123", "url": "https://i.pichr.io/file_abc123", "mime": "image/jpeg", "bytes": 524288, "status": "ready" }

POST /upload/finalize

Finalize upload and trigger NSFW detection.

Headers: Authorization: Bearer {api_key}

Request Body:

{ "uploadId": "upl_xyz789", "fileId": "file_abc123", "r2Key": "uploads/2025-11-13/file_abc123/image.jpg", "r2Etag": "etag-value", "width": 1920, "height": 1080, "phash": "abc123", "nsfwScore": 0.05 }

Response:

{ "fileId": "file_abc123", "url": "https://i.pichr.io/file_abc123", "cdnUrl": "https://cdn.pichr.io/...", "mime": "image/jpeg", "bytes": 524288, "width": 1920, "height": 1080, "nsfwScore": 0.05, "ageRestricted": false, "visibility": "public", "expiresAt": null, "phash": "abc123", "duplicates": [] }

POST /upload/multipart/init

Initialize multipart upload for large files.

Headers: Authorization: Bearer {api_key}

Request Body:

{ "filename": "large-file.jpg", "mime": "image/jpeg", "totalBytes": 52428800, "partSize": 5242880 }

Response: Upload ID and part upload URLs

POST /upload/multipart/complete

Complete multipart upload.

Headers: Authorization: Bearer {api_key}

Request Body:

{ "uploadId": "upl_xyz789", "fileId": "file_abc123", "r2Key": "uploads/...", "parts": [ { "partNumber": 1, "etag": "etag1" }, { "partNumber": 2, "etag": "etag2" } ] }

Response: File ID and ETag


File Management Endpoints

Base path: /files

GET /files

List your uploaded files.

Headers: Authorization: Bearer {api_key}

Query Parameters:

  • limit (int): Max results (1-100, default: 50)
  • offset (int): Pagination offset (default: 0)
  • sort (enum): Sort field - created, views, size (default: created)
  • order (enum): Sort order - asc, desc (default: desc)
  • visibility (enum): Filter by visibility - public, unlisted, private
  • excludeNsfw (boolean): Exclude NSFW content (default: true)

Response:

{ "files": [ { "id": "file_abc123", "url": "https://i.pichr.io/file_abc123", "thumbnailUrl": "https://cdn.pichr.io/t/file_abc123", "title": "My Image", "mime": "image/jpeg", "bytes": 524288, "width": 1920, "height": 1080, "viewCount": 42, "createdAt": "2025-11-13T10:00:00Z" } ], "pagination": { "total": 25, "limit": 50, "offset": 0, "hasMore": false } }

GET /files/:id

Get file metadata and details.

Headers: Authorization: Bearer {api_key} (required for private files)

Response:

{ "id": "file_abc123", "url": "https://i.pichr.io/file_abc123", "cdnUrl": "https://cdn.pichr.io/...", "title": "My Image", "description": "Image description", "mime": "image/jpeg", "bytes": 524288, "width": 1920, "height": 1080, "visibility": "public", "viewCount": 42, "downloadCount": 5, "nsfwScore": 0.05, "ageRestricted": false, "tags": ["nature", "landscape"], "createdAt": "2025-11-13T10:00:00Z", "expiresAt": null }

Error Responses:

  • 403 Forbidden: Content restricted by safe mode
  • 404 Not Found: File doesn’t exist
  • 410 Gone: File was banned or deleted

PATCH /files/:id

Update file metadata.

Headers: Authorization: Bearer {api_key}

Request Body:

{ "title": "Updated Title", "description": "Updated description", "visibility": "unlisted", "hotlinkPolicy": "whitelist", "tags": ["updated", "tags"], "expiresIn": 168 }

Response: Success message with updated fields

DELETE /files/:id

Delete a file (soft delete).

Headers: Authorization: Bearer {api_key}

Response: Success message

Note: Queues file for cleanup from R2 storage.

GET /files/:id/download

Download file with Content-Disposition header.

Headers: Authorization: Bearer {api_key} (required for private files)

Response: Binary file data with download headers


Album Endpoints

Base path: /albums

POST /albums

Create a new album.

Headers: Authorization: Bearer {api_key}

Request Body:

{ "title": "My Album", "description": "Album description", "fileIds": ["file_abc123", "file_def456"], "visibility": "public", "password": "optional-password", "tags": ["vacation", "2025"] }

Response:

{ "id": "alb_xyz789", "title": "My Album", "description": "Album description", "visibility": "public", "tags": ["vacation", "2025"], "createdAt": "2025-11-13T10:00:00Z", "url": "https://pichr.io/a/alb_xyz789" }

GET /albums

List your albums.

Headers: Authorization: Bearer {api_key}

Query Parameters:

  • limit (int): Max results (1-100, default: 50)
  • offset (int): Pagination offset (default: 0)

Response: List of albums with file counts

GET /albums/:id

Get album details and files.

Headers:

  • Authorization: Bearer {api_key} (required for private albums)
  • X-Album-Password: {password} (if password-protected)

Response:

{ "id": "alb_xyz789", "title": "My Album", "description": "Album description", "visibility": "public", "tags": ["vacation", "2025"], "viewCount": 150, "fileCount": 25, "createdAt": "2025-11-13T10:00:00Z", "updatedAt": "2025-11-13T12:00:00Z", "files": [...] }

PATCH /albums/:id

Update album metadata.

Headers: Authorization: Bearer {api_key}

Request Body:

{ "title": "Updated Album", "description": "New description", "visibility": "unlisted", "password": "new-password", "tags": ["updated"], "coverImageId": "file_abc123" }

Response: Success message

DELETE /albums/:id

Delete an album (doesn’t delete files).

Headers: Authorization: Bearer {api_key}

Response: Success message

POST /albums/:id/files

Add files to an album.

Headers: Authorization: Bearer {api_key}

Request Body:

{ "fileIds": ["file_abc123", "file_def456", "file_ghi789"] }

Response:

{ "message": "Files added successfully", "added": 3, "requested": 3 }

DELETE /albums/:id/files/:fileId

Remove a file from an album.

Headers: Authorization: Bearer {api_key}

Response: Success message


Moderation Endpoint

Base path: /moderation

POST /moderation/report

Report content for moderation review.

Request Body:

{ "fileId": "file_abc123", "reason": "adult_content", "details": "This image contains inappropriate content", "email": "reporter@example.com" }

Reason Options: csam, terrorism, adult_content, violence, harassment, hate_speech, self_harm, spam, copyright, other

Response:

{ "message": "Report submitted successfully", "reportId": "rep_xyz789", "complianceMessage": "Thank you for reporting...", "status": "pending" }

Note: High-priority reports (CSAM, terrorism) trigger automatic actions and are escalated immediately. This endpoint does not require authentication.


Error Responses

All endpoints follow consistent error response format:

{ "error": "Error type", "message": "Human-readable error message", "details": {...} }

HTTP Status Codes

CodeMeaning
200Success
201Created
400Bad Request
401Unauthorized (Invalid or missing API key)
403Forbidden
404Not Found
413Payload Too Large
429Rate Limit Exceeded
500Internal Server Error
503Service Unavailable

Rate Limit Headers

All responses include rate limit headers:

X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 995 X-RateLimit-Reset: 1700000000

Rate Limits by Plan

PlanUploads/HourAPI Calls/Hour
Anonymous5100
Free201,000
Pro10010,000
Enterprise1,000100,000

What’s Not Included?

This documentation covers public endpoints accessible with API keys. The following features require web application login and are NOT accessible via API keys:

  • Account management (signup, login, logout)
  • API key management (create, list, revoke keys)
  • Subscription management (billing, upgrades)
  • GDPR data export and account deletion
  • Moderation queue management
  • Admin panel features

These features are available through the web application at pichr.io .

Next Steps

Last updated: 13 November 2025