📬 Webhook
Webhook for Masked Image Delivery
The Maskit system processes image masking requests in batches and sends the masked images directly via webhook calls. This document describes the webhook interface, payload format, security (HMAC signatures), and provides example implementations in multiple programming languages.
📦 Webhook Overview
- Method: POST
- Content-Type: multipart/form-data
- Purpose: Deliver each processed masked image directly to the client’s callback URL, without storing the image permanently.
- Webhook called per image: The client receives an individual webhook POST for each processed image.
📝 Request Structure
The webhook request is a multipart/form-data POST with the following parts:
- Job ID (String)
- Field name: jobId
- Type: text/plain
- Description: The unique identifier assigned to the job when the process-image endpoint was called. Used to track and match webhook responses with specific processing requests.
- Metadata (String)
- Field name: metadata
- Type: text/plain
- Description: Arbitrary string originally provided in the batch request, used to correlate webhook calls.
- Masked Image File
- Field name: maskedImage
- Type: image/jpeg or image/png
- Description: The in-memory processed masked image.
- Security Header
- Header name: X-Signature
- Value: HMAC SHA-256 hex digest of the raw request body using your shared secret
📝 HMAC Signature
To ensure that incoming webhook requests are legitimate and unaltered, the Maskit system signs each request with an HMAC SHA-256 signature using a shared secret. This section explains how to validate the HMAC signature on your end to secure your integration.
- Header: X-Signature
- Algorithm: HMAC-SHA-256
- Shared Secret: your_shared_secret
- How to validate:
- Read the raw request body.
- Compute HMAC_SHA256(secret, body).
- Compare it to the value in X-Signature.
📂 Webhook Implementation Examples
Below are example webhook receiver implementations in common programming languages. These serve as reference code snippets to help you set up your own endpoint for receiving masked images and metadata from the Maskit system.
from flask import Flask, request, abort
import hmac
import hashlib
import os
app = Flask(__name__)
SHARED_SECRET = b'your_shared_secret'
@app.route('/webhook', methods=['POST'])
def receive_masked_image_webhook():
signature = request.headers.get('X-Signature')
if not signature:
abort(401, 'Missing signature')
# Read raw request body for signature verification
body = request.get_data()
computed_hash = hmac.new(SHARED_SECRET, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(computed_hash.lower(), signature.lower()):
abort(401, 'Invalid signature')
if 'maskedImage' not in request.files:
abort(400, 'No maskedImage file provided')
file = request.files['maskedImage']
metadata = request.form.get('metadata', '')
job_id = request.form.get('jobId', '')
print(f"Received image '{file.filename}' with metadata '{metadata}' and jobId '{job_id}'")
os.makedirs('ReceivedImages', exist_ok=True)
output_path = os.path.join('ReceivedImages', file.filename)
file.save(output_path)
return '', 200
if __name__ == '__main__':
app.run(port=3000)🔔 Example cURL Webhook Request
Use this curl command to test your webhook implementation. It mimics how the Maskit system will POST the masked image and metadata to your endpoint:
curl -X POST "https://client-app.com/webhook" \
-H "Content-Type: multipart/form-data" \
-H "X-Signature: <calculated_signature>" \
-F "metadata=your-custom-reference-id" \
-F "jobId=123e4567-e89b-12d3-a456-426614174000" \
-F "maskedImage=@/path/to/masked.jpg;type=image/jpeg"