Skip to main content

Webhooks

IndReelForge can push real-time notifications to your server when uploads complete or fail. Configure a webhook URL once and receive signed HTTP POST payloads for every event.


How It Works​

  1. Configure your webhook endpoint via POST /api/webhooks/config.
  2. IndReelForge sends a POST request to your URL with a JSON payload whenever an upload event occurs.
  3. Every delivery includes an X-IndReelForge-Signature header — verify it to confirm the request is genuine.
  4. Failed deliveries are retried up to 3 times with exponential back-off (0 s → 2 s → 5 s).

Configure Webhook​

POST https://api.indreelforge.com/api/webhooks/config
Authorization: Apikey YOUR_API_KEY
Content-Type: application/json

Request body​

FieldTypeRequiredDescription
channels.webhookbooleanYesEnable/disable webhook delivery
channels.telegrambooleanNoEnable/disable Telegram notifications
webhook_urlstringIf webhook enabledYour HTTPS endpoint URL
telegram_chat_idstringIf telegram enabledTelegram chat ID
{
"channels": { "webhook": true, "telegram": false },
"webhook_url": "https://your-server.com/hooks/indreelforge"
}

Response​

{
"success": true,
"channels": { "webhook": true, "telegram": false },
"webhook_url": "https://your-server.com/hooks/indreelforge",
"webhook_secret": "a1b2c3d4e5f6..."
}

Save the webhook_secret — you need it to verify request signatures. The secret is generated once and never changes unless you regenerate it.

Security note: The URL must be publicly reachable HTTPS. Private/intranet IPs (RFC 1918, loopback, link-local) are rejected to prevent SSRF attacks.


Get Current Config​

GET https://api.indreelforge.com/api/webhooks/config
Authorization: Apikey YOUR_API_KEY

Response​

{
"channels": { "webhook": true, "telegram": false },
"webhook_url": "https://your-server.com/hooks/indreelforge",
"telegram_chat_id": null,
"webhook_secret": "a1b2c3d4e5f6..."
}

Send a Test Webhook​

Triggers a single test delivery to your configured URL.

POST https://api.indreelforge.com/api/webhooks/test
Authorization: Apikey YOUR_API_KEY

Response​

{
"success": true,
"message": "Test webhook sent",
"response_status": 200
}

Event Payloads​

All events share a common envelope:

{
"event": "upload.completed",
"upload_id": "abc123",
"user_id": "u_xyz",
"timestamp": "2024-01-15T10:30:00.000Z",
"data": { ... }
}

upload.completed​

Fired when an upload finishes processing on all platforms.

{
"event": "upload.completed",
"upload_id": "abc123",
"user_id": "u_xyz",
"timestamp": "2024-01-15T10:30:00.000Z",
"data": {
"title": "My Video",
"upload_type": "video",
"platforms": ["instagram", "youtube", "tiktok"],
"platform_statuses": {
"instagram": "posted",
"youtube": "posted",
"tiktok": "posted"
},
"profile": "my-brand"
}
}

upload.partial​

Fired when the upload succeeded on at least one platform but failed on others.

{
"event": "upload.partial",
"upload_id": "abc123",
"user_id": "u_xyz",
"timestamp": "2024-01-15T10:31:00.000Z",
"data": {
"title": "My Video",
"upload_type": "video",
"platforms": ["instagram", "youtube", "tiktok"],
"platform_statuses": {
"instagram": "posted",
"youtube": "posted",
"tiktok": "failed"
},
"profile": "my-brand"
}
}

upload.failed​

Fired when an upload cannot be delivered to any platform.

{
"event": "upload.failed",
"upload_id": "abc123",
"user_id": "u_xyz",
"timestamp": "2024-01-15T10:31:00.000Z",
"data": {
"title": "My Video",
"upload_type": "video",
"platforms": ["instagram"],
"error": "Instagram token expired"
}
}

test​

Sent when you call POST /api/webhooks/test.

{
"event": "test",
"message": "This is a test webhook from IndReelForge",
"timestamp": "2024-01-15T10:00:00.000Z"
}

Verifying Signatures​

Every delivery includes the header:

X-IndReelForge-Signature: sha256=<hex>

The signature is HMAC-SHA256(webhook_secret, raw_request_body). Always verify it before processing the payload.

Node.js​

const crypto = require('crypto');

function verifySignature(secret, rawBody, signatureHeader) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}

// Express example
app.post('/hooks/indreelforge', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-indreelforge-signature'];
if (!verifySignature(process.env.WEBHOOK_SECRET, req.body, sig)) {
return res.status(401).send('Invalid signature');
}
const payload = JSON.parse(req.body);
console.log('Event:', payload.event);
res.sendStatus(200);
});

Python​

import hmac
import hashlib

def verify_signature(secret: str, raw_body: bytes, signature_header: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)

# Flask example
from flask import Flask, request, abort
import json

app = Flask(__name__)

@app.route('/hooks/indreelforge', methods=['POST'])
def webhook():
sig = request.headers.get('X-IndReelForge-Signature', '')
if not verify_signature(WEBHOOK_SECRET, request.data, sig):
abort(401)
payload = request.json
print('Event:', payload['event'])
return '', 200

Important: Use a timing-safe comparison (crypto.timingSafeEqual / hmac.compare_digest) to prevent timing attacks.


Retry Policy​

If your endpoint does not return a 2xx status code within 10 seconds, IndReelForge retries the delivery:

AttemptDelay
1 (initial)0 s
22 s
35 s

After 3 failed attempts the delivery is marked as failed and recorded in the delivery log. You can inspect failed deliveries via GET /api/webhooks/deliveries.

Endpoint requirements​

  • Must respond with HTTP 2xx within 10 seconds.
  • Must be a publicly reachable HTTPS URL.
  • Redirects are not followed (use the final destination URL directly).

Delivery Logs​

GET https://api.indreelforge.com/api/webhooks/deliveries
Authorization: Apikey YOUR_API_KEY

Query parameters​

ParameterDefaultDescription
page1Page number
limit20Results per page (max 100)

Response​

{
"deliveries": [
{
"id": "del_abc123",
"upload_id": "abc123",
"event_type": "upload.completed",
"response_status": 200,
"delivered_at": "2024-01-15T10:30:01.000Z",
"created_at": "2024-01-15T10:30:00.000Z"
}
]
}

Best Practices​

  • Respond quickly — return 200 immediately and process the payload asynchronously. This avoids timeouts and unnecessary retries.
  • Verify every signature — never trust a payload without checking X-IndReelForge-Signature.
  • Handle duplicates — retries may deliver the same event more than once. Use upload_id + event as an idempotency key.
  • HTTPS only — HTTP endpoints are rejected in production.