picsha.ai API Specification (v1)
1. Product Philosophy
"S3 with a Brain." Picsha.ai is a serverless, usage-based media backend designed for AI Agents and "Vibe Coders." It abstracts complex processing pipelines (TUS, Rekognition, LibreOffice, Vector Search) into simple, developer-friendly endpoints.
2. Base URL & Authentication
- Base URL:
https://api.picsha.ai/v1 - Authentication: Bearer Token via Header.
Authorization: Bearer sk_live_51Mx... - Multi-Tenant Scoping:
- Organizations: All requests are automatically scoped to the data silo of the Organization associated with your API Key.
- End-User Tracking: When uploading or querying assets on behalf of a user, you must pass their identifier using the
x-external-user-idheader to ensure strict tenant boundaries.
x-external-user-id: user_abc123- Organization-Wide Access: If you are building an internal tool or agent that genuinely requires cross-tenant access to the entire organization's library, you must explicitly bypass user-scoping by setting the admin header:
x-picsha-org-admin: true - Dynamic Transaction Cost Tracking:
- Automatic Cost Decoration: Every successful response from the
/v1operational API dynamically includes a"cost"attribute in standard currency format (e.g."$0.0050"), representing the standard retail value of that specific transaction. - No-Charge Error Guarantee: Any API transaction that results in an HTTP failure (status code
>= 300, e.g., validation errors,401 Unauthorized, or500 Server Error) is automatically overridden to a transaction cost of"$0.0000". You are never charged for failures. - Global Toggle Switch: Response cost tracking can be globally bypassed and disabled in your Organization Settings in the Picsha Dashboard.
- Automatic Cost Decoration: Every successful response from the
API Fundamentals
Rate Limits
Picsha AI enforces rate limits to ensure platform stability. If you exceed your organization's quota, the API will respond with a 429 Too Many Requests status code.
Standard rate limit headers are included in every response:
X-RateLimit-Limit: The maximum number of requests you're permitted to make per minute.X-RateLimit-Remaining: The number of requests remaining in the current rate limit window.
Idempotency
To safely retry requests without accidentally performing the same operation twice (and incurring double billing), you can attach an Idempotency-Key header to any POST or PATCH request.
Idempotency-Key: req_12345
Picsha will cache the resulting response for 24 hours. If a subsequent request is made with the same key, the cached response is returned without re-executing the operation.
Error Codes
When an error occurs, the API returns a structured JSON response:
{
"error": {
"code": "invalid_request_error",
"message": "The provided image format is not supported.",
"status": 400
}
}
- 400 Bad Request: Validation failed or invalid parameters were supplied.
- 401 Unauthorized: Invalid or missing API key.
- 403 Forbidden: The authenticated user lacks permission, or the asset is flagged by moderation.
- 404 Not Found: The requested resource does not exist.
- 422 Unprocessable Entity: The file payload was corrupt or unreadable.
- 429 Too Many Requests: Rate limit exceeded.
- 500 Internal Server Error: An unexpected error occurred on Picsha's end.
3. Core Endpoints
A. Ingest (The "Magic" Upload)
POST /assets
Handles all file ingestion types (Multipart, URL, Raw) and triggers the AI processing pipeline based on configuration.
Headers:
Content-Type:multipart/form-dataORapplication/json(for URL fetch)x-external-user-id:string(Required) - Unique identifier for the end-user uploading the asset.
Query Parameters:
?ephemeral=true: Marks the asset for automatic deletion after 24 hours. Ideal for temporary processing pipelines where you only need to extract AI summaries or metadata without incurring long-term storage costs.?expires_at=2026-12-31T23:59:59Z: Optional ISO-8601 timestamp for when the asset should be automatically deleted by our cleanup workers.
Parameters (JSON Body for URL / Config):
{
"url": "https://example.com/files/quarterly_report.docx",
"config": {
"auto_tag": false, // Vision AI (AWS Rekognition object and face detection). Defaults to false.
"auto_summarize": false, // Anthropic Claude on Amazon Bedrock for images and documents, Amazon Transcribe for audio/video. Defaults to false.
"vectorize": false, // Generates Titan multimodal embeddings for vector similarity search. Defaults to false.
"location_lookup": false, // Reverse geocodes EXIF coordinates via Google Maps API. Defaults to false.
"adaptive_stream": false, // Triggers an async AWS MediaConvert transcode job for videos. Defaults to false.
"content_moderation": false, // Runs AWS Rekognition Content Moderation safety check. Defaults to false.
"antivirus_scan": false, // Runs high-speed ClamAV sidecar malware/virus scanning. Defaults to false.
"remove_background": false, // Generates a background-removed alpha cutout at ingest for instant bg_rem / bg_asset rendering. One charge per unique image. Defaults to false.
"render_on_upload": "w=300&q=80; w=800&fit=cover", // Pre-warms dynamic delivery CDN cache with specific sizes
"expires_at": "2026-12-31T23:59:59Z" // ISO-8601 timestamp for automatic asset deletion
},
"tags": ["finance", "report", "q4"],
"metadata": {
"project_id": "my_replit_app_123"
}
}
Response (Success):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://picsha-assets.s3.us-east-1.amazonaws.com/org_abc/user_pete/550e8400-e29b-41d4-a716-446655440000/my_file.jpg",
"message": "Asset uploaded successfully",
"cost": "$0.0050"
}
Note: Ingestion processing runs asynchronously. You will receive an immediate response while the AI extraction, transcoding, and embedding run in the background. Subscribe to the asset.processed webhook to be notified when metadata and derivatives are ready.
B. Client-Side Presigned Upload URL
GET /assets/presigned
Generates a presigned S3 upload URL for direct client-side PUT uploading (e.g. for Uppy or other upload widgets).
Query Parameters:
filename:string(Required) - Original name of the file to be uploaded.contentType:string(Required) - MIME type of the file.
Response:
{
"method": "PUT",
"url": "https://picsha-ingress.s3.amazonaws.com/org_abc123/user_pete/550e8400-e29b-41d4-a716-446655440000/my_file.jpg?AWSAccessKeyId=...",
"headers": {
"Content-Type": "image/jpeg"
}
}
C. List Assets
GET /assets
Lists metadata and retrieval URLs for assets belonging to the authenticated Organization or User.
Query Parameters:
page:number(Default:1) - Pagination page index.limit:number(Default:20) - Number of assets to return per page (max 100).type:string(Optional) - Filter by mime-type prefix (e.g.,image,video,application).tag:string(Optional) - Filter by exact metadata tag.search:string(Optional) - Simple keyword search on the original filename.sort:string(Optional) - Sorting order. Available options:added-desc,added-asc,created-desc,created-asc,name-asc,name-desc.albumId:string(Optional) - Filter by exact album group identifier.
Response:
{
"cost": "$0.0005",
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"mimeType": "image/jpeg",
"originalName": "team-pic.jpg",
"url": "https://cdn.picsha.ai/...",
"thumbnailUrl": "https://cdn.picsha.ai/render/550e8400-e29b-41d4-a716-446655440000?w=600&fmt=webp&proxy=true",
"tags": ["team", "cambridge"],
"metadata": {
"project_id": "my_app_123"
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1
}
}
Asset Status Lifecycle
Because ingestion is heavily asynchronous, assets transition through several system states during their lifecycle. The status property will always reflect one of the following canonical enum values:
queued: The asset has been saved and is waiting for an available Queue Worker node to begin processing.active: The worker node has started the ingestion pipeline (derivative generation, metadata extraction, and AI processing).completed: All AI analysis, transcription, multimodal embeddings, and primary web proxies have been generated successfully. The asset is fully indexed and ready for dynamic CDN delivery.failed: An unrecoverable error occurred during the ingestion pipeline.infected: The ClamAV sidecar detected malware or a virus. The file is quarantined and blocked from CDN delivery.pending_moderation: (If enabled) AWS Rekognition Content Moderation flagged the asset for unsafe content. It is isolated pending manual review.rejected: The asset was manually rejected during moderation review.
D. Get Asset Details
GET /assets/{id}
Retrieves full details and signed URLs for a single asset.
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"cost": "$0.0002",
"status": "completed",
"mimeType": "image/jpeg",
"originalName": "team-pic.jpg",
"url": "https://cdn.picsha.ai/...",
"thumbnailUrl": "https://cdn.picsha.ai/render/550e8400-e29b-41d4-a716-446655440000?w=600&fmt=webp&proxy=true",
"tags": ["team", "cambridge"],
"metadata": {
"project_id": "my_app_123"
}
}
E. Update Asset Metadata
PATCH /assets/{id}
Partially updates an asset's title, tags, or custom metadata object.
Request Body:
{
"meta": {
"title": "New Title"
},
"tags": ["add_this_tag", "-remove_this_tag"],
"metadata": {
"project_id": "updated_project_id"
},
"expires_at": "2026-12-31T23:59:59Z",
"requiresSignature": true
}
Note: Prefixing a tag with a - sign (e.g. "-remove_this_tag") will remove it from the asset's tags list, while standard strings will append it. Pass null to expires_at to permanently remove an expiration date.
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"message": "Asset updated successfully",
"cost": "$0.0000"
}
F. Delete Asset
DELETE /assets/{id}
By default, this moves an asset and its variants into a 30-day "Trash" state (Soft Delete), preventing accidental or malicious permanent data loss.
Parameters:
force(boolean): Pass?force=trueto permanently and irreversibly destroy the asset. Requires an Organization Admin Secret Key.
Response:
{
"success": true,
"message": "Asset deleted",
"cost": "$0.0000"
}
G. Trigger AI Summarization
POST /assets/{id}/summarize
Manually triggers/re-runs the AI deep reasoning summarization pipeline for an asset. This is an asynchronous background process.
Response:
{
"success": true,
"jobId": 1045,
"cost": "$0.0050"
}
Note: Use the returned jobId to poll the GET /jobs/{id} endpoint for completion.
H. Resumable Uploads (TUS Protocol)
POST /upload/resumable
- Standard TUS 1.0 Protocol endpoint.
- Supports large files (>100MB) and unstable connections.
- Implementation: Wraps internal
tus-node-server. - SDK Support: Compatible with
uppyandpicsha-uploaderSDK.
I. Generate New Images (Text-to-Image)
POST /assets/generate
Generates a brand-new image from a natural language prompt via MIMI and ingests it as a normal asset (analysis, DAM, renders, and further MIMI edits all work on it).
{
"prompt": "a foggy pine forest at dawn",
"aspect_ratio": "16:9",
"quality": "standard"
}
prompt(string, required): Natural language description of the image to generate.aspect_ratio(string, optional): One of1:1,3:4,4:3,9:16,16:9,2:3,3:2,4:5,5:4. Default1:1.quality(string, optional):lite|standard|4k. Defaultstandard.
Response: 201 Created
{
"assetId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://cdn.picsha.ai/render/550e8400-e29b-41d4-a716-446655440000"
}
Billing: the same event/price as the corresponding MIMI mode (Lite 6.0¢, Standard 16.0¢, 4K 32.0¢).
4. Delivery & Transformation
GET /assets/{id}/render
GET /seo/{id}/{seoUrlString}
Dynamic, edge-cached image transformations. Note that the CDN (cdn.picsha.ai/render/:assetId) sits directly in front of the API (api.picsha.ai/v1/assets/:assetId/render). Both URL path shapes are valid and route to the exact same transformation engine. The /seo alias route functions exactly the same as /render but supports semantic URL crawlers.
Forced Downloads
You can force the browser to securely download an asset rather than displaying it by appending the dl parameter:
?dl=true(Uses auto-generated secure filename)?dl=custom_filename.webp(Uses the specified custom filename)
Signed Delivery URLs & Strict Transformations (Security)
To protect your account from generative billing abuse and Lambda exhaustion, Picsha AI supports Strict Transformations. When Strict Transformations are enabled globally in your Organization settings (or individually per-asset via requiresSignature: true), you must append a cryptographically valid ?sig= parameter to the delivery URL for any query permutation. This ensures that malicious users cannot artificially inflate your billing by enumerating generative parameters (e.g., ?mimi=<anything>).
You can generate a signed URL using the helper endpoint:
POST /assets/{id}/sign-delivery
{
"urlPath": "/v1/seo/123e4567-e89b-12d3-a456-426614174000/image.webp",
"queryParams": {
"w": 600,
"fit": "cover"
}
}
Response:
{
"signedUrl": "/v1/seo/123e4567-e89b-12d3-a456-426614174000/image.webp?fit=cover&w=600&sig=39950449a74b1306",
"signature": "39950449a74b1306"
}
Note: By default the API will generate a secure filename based on the original asset's name and format (e.g. original-altered.webp). You can override this by passing a custom filename string to the parameter, e.g., ?dl=custom.jpg.
For comprehensive details on standard parameters (dimensions, cropping, formats), smart AI cropping, watermarking, Background Operations (background removal/replacement), and the signature MIMI natural language generative editing capability (mimi, mimi_mode, upscale, mimi_bg, async), see the Transformations & Generative AI guide.
5. Search (Vector & Semantic)
Picsha provides hybrid searching combining Amazon Titan multimodal vectors with structural metadata filters.
A. Search via POST
POST /search
Query using a JSON body. Ideal for programmatic queries and complex filtering.
Request Body:
query:string(Default:"") - Conversational NLP search query.mode:"standard" | "ai"(Default:"standard") -"standard"performs pure text/keyword search."ai"performs vector-driven semantic search.threshold:number(Default:0.6) - Relevance confidence threshold (only for AI mode).sort:string(Optional) - Sorting order:relevance,added-desc,added-asc,created-desc,created-asc,name-asc,name-desc.limit:number(Default:40) - Number of assets to return per page (max 100).filters/advancedFilters:object(Optional) - Precise filter constraints:addedAfter/addedBefore:string(ISO date format) - Ingestion timestamp range.capturedAfter/capturedBefore:string(ISO date format) - EXIF photo capture date range.face:string- Filter by specific recognized human face name.object:string- Filter by specific auto-detected visual label/object.place:string- Filter by reverse-geocoded location label.ocr:string- Filter by text extracted via OCR.type:string- Filter by mime-type prefix (e.g.,image,video).style:string- Filter by custom style categorization tag.metadataField/metadataValue:string- Filter by specific custom/legacy metadata field and matching value.
Request JSON:
{
"query": "photos of dogs on the beach",
"mode": "ai",
"threshold": 0.65,
"advancedFilters": {
"type": "image",
"capturedAfter": "2026-01-01",
"metadataField": "pictures_meta_subject.value",
"metadataValue": "#special events"
}
}
Response:
{
"results": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"score": 0.92,
"url": "https://cdn.picsha.ai/123e4567-e89b-12d3-a456-426614174000/source.jpg"
}
],
"pagination": {
"page": 1,
"limit": 40,
"total": 1
},
"cost": "$0.0025"
}
B. Search via GET
GET /search
Deep-link search query using URL parameters. Perfect for rendering gallery collections and browser navigation.
Query Parameters:
query,mode,threshold,sort,page,limit(Same behavior as POST parameters).addedAfter,addedBefore,capturedAfter,capturedBefore,face,object,place,ocr,type,style,metadataField,metadataValue(Passed directly as flat query parameters).
Example Request:
GET https://api.picsha.ai/v1/search?query=team&mode=ai&face=John%20Doe&type=image&metadataField=pictures_meta_subject.value&metadataValue=%23special%20events
6. Billing & Usage
GET /usage
Returns your organization's usage and spend for the current billing period.
Response:
{
"period": "current_month",
"total_spend": "$4.12",
"currency": "USD",
"breakdown": {
"storage_gb": 10.5,
"ai_operations": 450,
"bandwidth_gb": 2.1
}
}
7. Digital Asset Management (DAM) Primitives
These endpoints support advanced DAM workflows like asset grouping, explicit 1-to-1 relationships (e.g., source RAW to web JPEG), and asset event/comment tracking.
- Base Prefix:
/v1/dam
A. Asset Events & Comments
Track comments, edits, status updates, or custom activities for specific assets.
POST /events
Create an asset event or user comment.
Request Body:
{
"assetId": "550e8400-e29b-41d4-a716-446655440000",
"eventType": "COMMENT_ADDED",
"eventData": {
"username": "Pete",
"comment": "Nice composition in this image!"
}
}
GET /:assetId/events
Fetch all events and comments for a specific asset.
Response (Success):
[
{
"id": "ev_0f92a1",
"assetId": "550e8400-e29b-41d4-a716-446655440000",
"eventType": "COMMENT_ADDED",
"eventData": {
"username": "Pete",
"comment": "Nice composition in this image!"
},
"createdAt": "2026-05-22T23:00:00Z"
}
],
"cost": "$0.0000"
B. Asset Relationships
Explicitly relate assets (e.g., versions, derivations, replacements).
POST /relationships
Create an explicit relationship between two assets.
Request Body:
{
"sourceAssetId": "222e8400-e29b-41d4-a716-446655440000",
"targetAssetId": "333e8400-e29b-41d4-a716-446655440000",
"relationshipType": "REPLACES"
}
C. Asset Groups & Collections
Logically bucket assets into folders or campaigns.
POST /groups
Create a new group.
Request Body:
{
"name": "Q3 Marketing Campaign",
"metadata": {
"project_id": "proj_123"
}
}
GET /groups/:id
Retrieve a specific group by ID.
8. Webhooks
Manage your Enriched Agentic Webhooks. Webhooks allow your system to receive rich, cognitive payloads asynchronously when assets finish processing. For full details on the payload structure and security signatures, please see the Enriched Agentic Webhooks guide.
A. List Webhooks
GET /webhooks
Retrieve all registered webhooks for the authenticated user/organization.
Response:
[
{
"id": 42,
"url": "https://api.yourdomain.com/receiver",
"events": ["asset.processed"],
"config": {
"include_embeddings": true,
"include_text": true
},
"createdAt": "2026-06-02T02:58:00.000Z"
}
]
B. Register Webhook
POST /webhooks
Register a new webhook subscription.
Request Body:
{
"url": "https://api.yourdomain.com/receiver",
"events": ["asset.processed"],
"config": {
"include_embeddings": true,
"include_text": true
}
}
C. Update Webhook
PATCH /webhooks/{id}
Update an existing webhook's endpoint URL, event subscriptions, or payload configuration.
Request Body (Partial updates allowed):
{
"events": ["asset.processed", "asset.failed"]
}
D. Delete Webhook
DELETE /webhooks/{id}
Permanently remove a webhook subscription.
Response:
{
"message": "Webhook deleted successfully"
}
9. Named Transformations
Named transformations allow you to save a complex set of rendering parameters (like smart cropping, watermarking, and format conversion) into a single alias. You can then apply all of these parameters to an asset delivery URL by simply appending ?tx=your_alias_name.
A. List Transformations
GET /transformations
Retrieve all named transformations for your organization.
Response:
[
{
"id": "tf_1a2b3c",
"name": "Social Media Auto Crop",
"alias": "social_square",
"commands": {
"w": 1080,
"h": 1080,
"fit": "cover",
"pos": "attention",
"fmt": "webp"
},
"createdAt": "2026-06-01T12:00:00.000Z"
}
]
B. Create Transformation
POST /transformations
Save a new rendering parameter configuration under a short alias.
Request Body:
{
"name": "Watermarked Thumbnail",
"alias": "thumb_watermark",
"commands": {
"w": 400,
"wm": "444e8400-e29b-41d4-a716-446655440000",
"wm_pos": "southeast"
}
}
C. Get Transformation
GET /transformations/{id}
Retrieve a specific transformation configuration by ID.
D. Update Transformation
PUT /transformations/{id}
Overwrite the commands or details for an existing transformation.
Request Body:
{
"name": "Updated Name",
"alias": "thumb_watermark",
"commands": {
"w": 500,
"wm": "444e8400-e29b-41d4-a716-446655440000"
}
}
E. Delete Transformation
DELETE /transformations/{id}
Permanently delete a transformation.
9b. Backgrounds Library
Backgrounds are org-scoped scene images used for cutout compositing: pair them with the render engine's bg_asset parameter to layer any asset's background-removed cutout over a stored scene — a pure-CPU operation that renders in milliseconds once cached. A background references an existing asset, so it inherits the full ingest pipeline (moderation, derivatives) automatically.
A. List Backgrounds
GET /backgrounds
B. Register Background
POST /backgrounds
Registers an already-uploaded image asset as a reusable compositing background.
Request Body:
{
"name": "Rainy London Street",
"assetId": "550e8400-e29b-41d4-a716-446655440000",
"metadata": { "weather": "rain", "region": "uk" }
}
Usage with the render engine:
GET /v1/assets/{productAssetId}/render?w=800&h=800&bg_asset={backgroundId}
The product's stored cutout is composited over the scene. If no cutout exists yet, one is generated and persisted on first request (billed once per unique image), and every subsequent render — any size, any background — is a fast, cached CPU composite.
C. Get Background
GET /backgrounds/{id}
D. Update Background
PATCH /backgrounds/{id}
Update the name or metadata of a background.
E. Delete Background
DELETE /backgrounds/{id}
10. Background Jobs
Some heavy operations, such as AWS MediaConvert video transcoding, are processed asynchronously by the Core API. When you trigger these workflows, you will receive an integer job ID that you can poll.
[!NOTE] CDN Render Jobs vs Core API Jobs The jobs discussed in this section (
api.picsha.ai/v1/jobs/:id) are for heavy background workflows (like transcoding). This is completely distinct from the ultra-fast edge polling pipeline used for Image Rendering and MIMI Generative AI (cdn.picsha.ai/render/status/:jobId). For generative polling documentation, see the Transformations & MIMI guide.
A. Check Job Status
GET /jobs/{id}
Retrieve the status and results of an asynchronous job.
Response:
{
"id": 1042,
"type": "mediaconvert",
"status": "completed",
"result": {
"outputUrl": "https://cdn.picsha.ai/assets/990e8400-e29b-41d4-a716-446655440000/stream.m3u8"
}
}
-----
## 11. Rekognition Face Indexing
Picsha natively integrates with AWS Rekognition to provide automatic biometric face indexing.
### A. Register a Known Face
**`PUT /v1/rekognition/faces/{face_id}`**
Registers a specific individual's face into your organization's Rekognition Collection. Any future (or past) media containing this face will automatically be tagged and grouped.
**Path Parameters:**
* `face_id`: A client-provided unique identifier (e.g., `face_id_12345` or `john-doe-01`) used to group this person across your library.
**Request Body:**
```json
{
"name": "John Doe"
}
Response:
{
"success": true,
"face_id": "face_id_12345",
"name": "John Doe",
"cost": "$0.0120"
}