Picsha AI

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-id header 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 /v1 operational 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, or 500 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.

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-data OR application/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=true to 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 uppy and picsha-uploader SDK.

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 of 1:1, 3:4, 4:3, 9:16, 16:9, 2:3, 3:2, 4:5, 5:4. Default 1:1.
  • quality (string, optional): lite | standard | 4k. Default standard.

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"
}