Enriched Agentic Webhooks
Traditional webhooks are purely passive notifications—they send a lightweight payload containing nothing more than an ID and a status (e.g. {"assetId": "as_123", "status": "completed"}). For AI agents operating in autonomous frameworks like LangGraph, AutoGen, or CrewAI, this passive approach forces the agent to make multiple sequential API round-trips to pull technical metadata, visual tags, textual summaries, and vector embeddings.
Picsha AI solves this bottleneck with Enriched Agentic Webhooks. When an ingestion pipeline completes, Picsha constructs and dispatches a fully enriched cognitive package containing geocoded location strings, technical details, raw EXIF metadata, AI safety moderation labels (if moderation is enabled), Claude-generated visual summaries, and 1024-dimensional vector embeddings directly to your agent's receiver endpoint.
This enables downstream AI agents to reactively reason over visual and auditory media assets with zero subsequent API round-trips.
1. Supported Webhook Events
Picsha AI triggers webhooks based on the asset lifecycle. You can subscribe to one or more of the following event types:
| Event Type | Trigger Condition |
|---|---|
asset.processed | The ingest pipeline finished for an asset — successfully or not. Fires for every ingested asset, including URL ingest and text-to-image generation (POST /v1/assets/generate). Always branch on data.status. |
face.propagation.started | A face-name assignment has begun propagating across the organization's photo library. |
face.propagation.completed | Face-name propagation finished; matching assets have been updated. |
face.propagation.failed | Face-name propagation encountered an unrecoverable error. |
[!IMPORTANT]
asset.processedis a terminal event, not a success event. Until the dedicated failure events ship, pipeline failures arrive on this same event with a reduced payload:{ "event": "asset.processed", "data": { "assetId": "...", "status": "failed", "error": "Unsupported codec" } }
statusis"failed"for pipeline errors and"infected"when the ClamAV scan quarantined the file. Checkdata.status === "completed"before treating a payload as a finished asset.
[!NOTE] Deduplicated uploads emit a smaller payload. When you upload bytes Picsha already stores, the upload short-circuits and the notification identifies the asset with
data.idrather thandata.assetId, and carries noaiAnalysis,rawExif, orembedding(the existing asset already has them — fetch it withGET /assets/{id}). Read the id defensively:const assetId = data.assetId ?? data.id.
[!NOTE] Dedicated lifecycle events (
asset.queued,asset.active,asset.failed,asset.infected,asset.pending_moderation,asset.rejected) are on the roadmap and will be added to this table as they ship. Subscribing to*receives every current and future event.
2. Selective Enrichment Configuration
To protect client network bandwidth, safeguard user privacy, and prevent serverless gateway payload failures (e.g. AWS API Gateway limits), Picsha implements a Selective Enrichment architecture.
By default, outgoing webhooks include technical specifications, geocoding, visual tags, and Claude summaries. Developers can explicitly toggle the inclusion of large text blocks and float32 vector arrays during webhook registration:
| Configuration Flag | Type | Default | Description |
|---|---|---|---|
include_embeddings | boolean | false | When enabled, attaches the raw 1024-dimensional Titan Multimodal embedding float array directly to the payload (data.embedding). |
include_text | boolean | false | When enabled, attaches untruncated visual summaries. When disabled, the long summary is truncated to 500 characters. Note: Extracted OCR and transcript data are bound by a hard safety ceiling of 10,000 characters to prevent endpoint timeouts. |
3. Registering a Webhook
You can register a webhook programmatically via our Fastify API gateway. If you register a webhook without providing a custom secret, Picsha automatically generates a cryptographically secure signing secret prefixed with wh_sec_.
[!NOTE] Webhook subscriptions are keyed on the pair of your organization and the
x-external-user-idyou register with (defaulting tosystemwhen omitted).GET /v1/webhooks,PATCH, andDELETEonly ever see subscriptions registered under the same pair — send the samex-external-user-idyou used at registration time, or you will get an empty list.
Endpoint
POST /v1/webhooks
Request Headers
Authorization: Bearer sk_live_your_key
x-external-user-id: usr_dev_456
Content-Type: application/json
Request Body
{
"url": "https://api.yourdomain.com/agents/media-receiver",
"events": ["asset.processed"],
"config": {
"include_embeddings": true,
"include_text": true
}
}
Response
{
"id": 42,
"url": "https://api.yourdomain.com/agents/media-receiver",
"events": ["asset.processed"],
"secret": "wh_sec_d83e1c9f824a73b9d0e1f2a3b4c5d6e7f8",
"config": {
"include_embeddings": true,
"include_text": true
}
}
[!IMPORTANT] Write down your generated signing
secretwhen you receive the creation response. For security reasons, the secret is only returned in full upon registration and cannot be retrieved later in plaintext.
4. Cognitive Payload Structure
Below is an example of a fully enriched asset.processed event payload delivered to a client receiver when both include_embeddings and include_text are enabled:
{
"event": "asset.processed",
"timestamp": "2026-06-02T03:00:00.000Z",
"data": {
"assetId": "123e4567-e89b-12d3-a456-426614174000",
"orgId": "org_default",
"userId": "usr_dev_456",
"originalName": "cambridge_meeting.jpg",
"mimeType": "image/jpeg",
"size": 2451092,
"width": 4032,
"height": 3024,
"captureDate": "2026-05-24T18:45:00.000Z",
"cameraMake": "Apple",
"cameraModel": "iPhone 15 Pro",
"status": "completed",
"fileHash": "sha256_b2c4d6...",
"url": "https://cdn.picsha.ai/usr_dev_456/123e4567-e89b-12d3-a456-426614174000/source.jpg",
"tags": ["meeting", "indoors", "whiteboard", "laptop", "office"],
"locationString": "Cambridge, MA, USA",
"hlsStream": null,
"aiAnalysis": {
"summaryShort": "A team meeting in a well-lit office space with whiteboards.",
"summaryLong": "A detailed shot of a collaborative workspace in Cambridge. There are three individuals seated around a conference table looking at a laptop. The background features a glass whiteboard covered with architectural diagrams and flowchart structures. Lighting is bright and even, indicating daytime office work.",
"truncated": false
},
"rawExif": {
"FocalLength": "6.86 mm",
"FNumber": 1.78,
"ExposureTime": "1/60",
"ISO": 80
},
"embedding": [
-0.012495,
0.048291,
-0.082491,
0.001924,
0.081726
// ... 1024-float32 vector elements
],
"createdAt": "2026-06-02T02:58:00.000Z",
"updatedAt": "2026-06-02T02:59:30.000Z"
}
}
5. Secure Signature Verification
To guarantee that incoming webhook payloads originate exclusively from Picsha AI, each tailored payload is cryptographically signed before dispatch using the webhook’s distinct secret.
Picsha attaches the following headers to each outgoing POST request:
X-Picsha-Event: The event type (e.g.asset.processed).X-Picsha-Signature: The computed HMAC SHA-256 signature of the raw request body.
Node.js / TypeScript Verification Example
Below is a standard Express or Fastify middleware code snippet to securely verify the signature on your receiving backend:
import crypto from 'crypto';
import express from 'express';
const app = express();
function verifyPicshaSignature(
secret: string,
signature: string,
rawBody: Buffer
): boolean {
const computed = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(computed, 'hex')
);
}
// Usage inside an Express Route:
// IMPORTANT: You must use express.raw() to capture the exact raw bytes sent by Picsha
app.post(
'/webhooks/picsha',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-picsha-signature'] as string;
const secret = process.env.PICSHA_WEBHOOK_SECRET!; // Your wh_sec_... key
if (!signature) {
return res.status(401).send('Missing signature header');
}
// Verify using the raw buffer, NOT a parsed JSON object
const isValid = verifyPicshaSignature(secret, signature, req.body);
if (!isValid) {
return res.status(403).send('Invalid signature verification');
}
// Now that it's verified, we can safely parse the JSON payload
const payload = JSON.parse(req.body.toString('utf8'));
const { assetId, aiAnalysis, embedding } = payload.data;
console.log(`Received secure update for asset: ${assetId}`);
res.status(200).send({ received: true });
}
);
Python Verification Example
Below is a standard Python / Flask implementation to verify the payload signature using the raw request bytes:
import hmac
import hashlib
import json
from flask import Flask, request, abort
app = Flask(__name__)
def verify_signature(secret: str, signature: str, raw_body: bytes) -> bool:
computed = hmac.new(
secret.encode('utf-8'),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, computed)
@app.route('/webhooks/picsha', methods=['POST'])
def picsha_webhook():
signature = request.headers.get('X-Picsha-Signature')
secret = "wh_sec_your_key_here"
if not signature:
abort(401, description="Missing signature header")
# Verify using the raw bytes, NOT the parsed JSON dictionary
raw_body = request.get_data()
if not verify_signature(secret, signature, raw_body):
abort(403, description="Invalid cryptographic signature")
# Signature is valid. Parse and hand off the data block directly to your AI agent!
payload = request.get_json()
data_block = payload.get('data', {})
data = payload['data']
print(f"Verified secure cognitive package for asset: {data['assetId']}")
return {"status": "success"}, 200
6. Webhooks Feature Comparison
The table below contrasts Picsha AI's Enriched Agentic Webhooks with major competitors—Cloudinary, Uploadcare, and Bytescale:
| Feature / Payload Data | Cloudinary | Uploadcare | Bytescale | Picsha AI (Agentic) |
|---|---|---|---|---|
| Technical Metadata (Size, Mime, Dims) | Yes | Yes | Yes | Yes |
Basic Text Tags (e.g., ["car"]) | Yes | No | No | Yes |
| HMAC Security Signatures | Yes | Yes | No | Yes |
| Antivirus Scan Status | No | Yes | No | Yes ($1.00 / 1k scans) |
| Claude Visual Summary (Visual Context) | No | No | No | Yes (Enriched) |
| Document OCR Text Extract | No | No | No | Yes (Enriched) |
| A/V Speech-to-Text Transcripts | No | No | No | Yes (Enriched) |
| Geocoded Location Strings | No | No | No | Yes (Enriched) |
| Multimodal Vector Embedding (1024d) | No | No | No | Yes (Enriched) |
By combining cryptographically secure delivery, multi-tenant safety boundaries, and highly customized cognitive summaries, Picsha AI's Enriched Agentic Webhooks establish the premier standard for building high-performance, event-driven media intelligence systems.