API Docs
Base URL: https://putput-ala.pages.dev/api/v1 · Every endpoint below is live — hit "run" and see real responses.
Getting your guest token...
POST /api/v1/auth/guest — create guest token
No auth required. No request body. Returns a fresh guest token with storage limits.
| Auth | Body | Rate limit |
|---|---|---|
| None | None | 5 per IP per day |
POST /api/v1/upload/presign — get presigned URL
Requires auth. Sends file metadata, gets back a presigned URL for direct upload to R2.
| Field | Type | Value sent |
|---|---|---|
| filename | string | "api-docs-test.txt" |
| content_type | string | "text/plain" |
| size_bytes | number | 20 |
- Presigned URL expires in 1 hour
- Rate limit: 100 per token per hour
- Errors:
VALIDATION_ERROR400,FILE_TOO_LARGE413,STORAGE_LIMIT_EXCEEDED403,CONTENT_TYPE_BLOCKED403
Click run for just the presign step, or run full flow to presign → upload → confirm in one go and get a live CDN URL.
GET /api/v1/files — list your files
Requires auth. Returns your uploaded files with cursor pagination.
| Param | Type | Default | Description |
|---|---|---|---|
| cursor | string | (none) | Opaque cursor from previous response |
| limit | number | 50 | Items per page (max 100) |
DELETE /api/v1/files/:id — delete a file
Requires auth. Permanently removes a file from storage.
Run GET /files first to load your files, then pick one to delete.
File object
Every endpoint that returns file data uses this shape:
typescript
interface File {
id: string; // "file_xyz"
original_name: string; // "photo.jpg"
public_name: string; // "abc123/photo.jpg"
public_url: string; // full CDN URL
content_type: string; // "image/jpeg"
size_bytes: number; // file size in bytes
created_at: string; // ISO 8601 timestamp
}Error codes
All errors return:
json
{ "error": { "code": "SCREAMING_SNAKE", "message": "...", "hint": "..." } }| Code | HTTP | When |
|---|---|---|
| UNAUTHORIZED | 401 | Missing or invalid Bearer token |
| FORBIDDEN | 403 | IP banned or action not permitted |
| VALIDATION_ERROR | 400 | Invalid request body |
| UPLOAD_NOT_FOUND | 404 | Invalid, expired, or already-confirmed upload_id |
| FILE_NOT_FOUND | 404 | File doesn't exist or already deleted |
| FILE_NOT_UPLOADED | 400 | Confirm called before PUT completed |
| FILE_TOO_LARGE | 413 | Exceeds max file size for plan |
| FILE_LIMIT_EXCEEDED | 403 | File count limit reached |
| STORAGE_LIMIT_EXCEEDED | 403 | Storage quota exceeded |
| CONTENT_TYPE_BLOCKED | 403 | MIME type not allowed for guest tokens |
| RATE_LIMITED | 429 | Too many requests |
| SERVER_ERROR | 500 | Internal server error |
Rate limits
| Endpoint | Limit | Window | Key |
|---|---|---|---|
| POST /auth/guest | 5 | per day | per IP |
| POST /upload/presign | 100 | per hour | per token |
More resources
- Code Examples — curl, JavaScript, Python
- Next.js Guide — step-by-step integration
- docs.putput.io — plain-text docs for AI agents
- OpenAPI spec — machine-readable schema