Picsha AI

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 TypeTrigger Condition
asset.queuedA new asset has been successfully saved to S3 and is waiting for a Queue Worker.
asset.activeThe worker node has picked up the asset and begun the AI ingestion pipeline.
asset.processedAll AI analysis, transcription, and multimodal embeddings have completed successfully.
asset.failedAn unrecoverable error occurred during the ingestion pipeline.
asset.infectedThe ClamAV sidecar detected malware or a virus; the asset is quarantined.
asset.pending_moderationAWS Rekognition flagged the asset for unsafe content pending manual review.
asset.rejectedThe asset was manually rejected during moderation review.

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 FlagTypeDefaultDescription
include_embeddingsbooleanfalseWhen enabled, attaches the raw 1024-dimensional Titan Multimodal embedding float array directly to the payload (data.embedding).
include_textbooleanfalseWhen 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_.

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 secret when 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",
    "cost": "$0.0250"
  }
}

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 DataCloudinaryUploadcareBytescalePicsha AI (Agentic)
Technical Metadata (Size, Mime, Dims)YesYesYesYes
Basic Text Tags (e.g., ["car"])YesNoNoYes
HMAC Security SignaturesYesYesNoYes
Antivirus Scan StatusNoYesNoYes ($1.00 / 1k scans)
Claude Visual Summary (Visual Context)NoNoNoYes (Enriched)
Document OCR Text ExtractNoNoNoYes (Enriched)
A/V Speech-to-Text TranscriptsNoNoNoYes (Enriched)
Geocoded Location StringsNoNoNoYes (Enriched)
Multimodal Vector Embedding (1024d)NoNoNoYes (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.