Webhooks
Webhooks allow you to receive real-time notifications when specific events occur in your account, such as when a video upload is completed or when a connected account requires re-authentication.
Base URL
https://api.multi-upload-tool.com/api/v1
Authentication
All requests require an API Token in the header:
x-api-key: YOUR_API_TOKEN
Supported Events
The following events can trigger a webhook notification:
| Event Name | Description |
|---|---|
upload.completed | Triggered when a video or post is successfully published to a platform. |
upload.failed | Triggered when a publication fails. |
upload.scheduled | Triggered when a post is scheduled for later. data includes uploadId, platform, accountId and scheduledFor. |
upload.cancelled | Triggered when a scheduled post is cancelled before it went out. Same data as upload.scheduled. |
upload.changes_requested | A post awaiting approval was sent back to draft, by your client (review link) or an owner/admin. data includes uploadId, platform, reviewedBy (client or team) and comment. |
upload.approved | A post awaiting approval was approved and is now scheduled or publishing. data includes uploadId, platform, reviewedBy, scheduledFor. |
connected_account.connected | Triggered when a new social media account is connected. |
connected_account.disconnected | Triggered when a social media account is disconnected. |
connected_account.expired | Triggered when an account’s access token expires and requires reconnection. |
connected_account.refresh_failed | Triggered when the system fails to refresh an expired access token automatically. |
subscription.created | Triggered when a new subscription is created. |
subscription.updated | Triggered when a subscription is updated (e.g. plan change). |
subscription.cancelled | Triggered when a subscription is cancelled. |
subscription.expired | Triggered when a subscription expires. |
suggestion.created | Triggered when a new suggestion or feedback item is created. |
suggestion.updated | Triggered when the status of a suggestion is updated (e.g. approved, implemented). |
security.login | Triggered when a user logs in to the account (security audit). |
team.invite | Triggered when a new member is invited to the team. |
Payload Structure
All webhook requests are sent as POST requests with a JSON body. The payload follows a standard envelope format:
{
"id": "evt_V1StGXR8_Z5jdHi6B-myT",
"event": "upload.completed",
"createdAt": "2026-01-01T12:00:00.000Z",
"data": {
// Event-specific data
}
}Example: Upload Completed Payload
{
"id": "evt_abc123",
"event": "upload.completed",
"createdAt": "2026-01-01T12:00:00.000Z",
"data": {
"uploadId": 123,
"platform": "tiktok",
"status": "completed",
"metadata": {
"videoId": "73123456789",
"shareUrl": "https://www.tiktok.com/@user/video/73123456789"
}
}
}Delivery & Retries
- Your endpoint must answer with a
2xxstatus within 10 seconds. Anything else (a4xx, a5xx, a redirect, a timeout) is a failed attempt. - A failed attempt is retried 5 more times: after 30 seconds, 2 minutes, 10 minutes, 1 hour and 6 hours (about 7 hours in total).
- Every attempt carries the same
X-Webhook-ID. Use it to ignore an event you already processed: a retry or a replay can reach you after a success you did not acknowledge in time. - A webhook is disabled only after 3 events in a row failed all their attempts. You get an email, and you can enable it again with
PATCH /webhooks/:id. - Every attempt is recorded in the delivery log for 30 days.
Security & Verification
To ensure that the webhook requests are coming from us, we include a signature in the headers. You should verify this signature using your webhook secret.
Headers
| Header | Description |
|---|---|
X-Webhook-Event | The name of the event (e.g., upload.completed). |
X-Webhook-ID | The unique ID of the event. |
X-Webhook-Timestamp | The timestamp of the request. |
X-Webhook-Signature | The HMAC SHA-256 signature, computed with the secret current when the attempt is sent. |
Verifying the Signature
The signature is generated using HMAC SHA-256 with your webhook secret. The data to sign is constructed as:
timestamp + "." + JSON.stringify(payload)
Node.js Example
const crypto = require('crypto');
function verifySignature(payload, signature, secret, timestamp) {
const data = `${timestamp}.${JSON.stringify(payload)}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(data)
.digest('hex');
return signature === expectedSignature;
}Python Example
import hmac
import hashlib
def verify_signature(payload, signature, secret, timestamp):
data = f"{timestamp}.{payload}"
expected_signature = hmac.new(
secret.encode(),
data.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)Manage Webhooks
List Webhooks
Retrieve all configured webhooks for your account.
Endpoint
GET /webhooks
Example Request
curl -X GET "https://api.multi-upload-tool.com/api/v1/webhooks" \
-H "x-api-key: YOUR_API_TOKEN"Example Response
{
"success": true,
"data": [
{
"id": 1,
"url": "https://your-api.com/webhooks",
"events": ["upload.completed", "upload.failed"],
"isActive": true,
"failureCount": 0,
"createdAt": "2026-01-01T10:00:00.000Z",
"updatedAt": "2026-01-01T10:00:00.000Z"
}
]
}Create Webhook
Register a new webhook endpoint to receive event notifications.
Endpoint
POST /webhooks
Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The HTTPS URL where the webhook payloads will be sent. |
events | string[] | Yes | Array of event names to subscribe to (e.g., upload.completed). |
secret | string | No | Optional custom secret for signature verification. If omitted, one will be generated for you. |
Example Request
curl -X POST "https://api.multi-upload-tool.com/api/v1/webhooks" \
-H "x-api-key: YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-api.com/webhooks",
"events": ["upload.completed", "upload.failed", "connected_account.expired"],
"secret": "my-custom-secret-key"
}'Example Response
{
"success": true,
"data": {
"id": 2,
"url": "https://your-api.com/webhooks",
"events": ["upload.completed", "upload.failed", "connected_account.expired"],
"secret": "my-custom-secret-key",
"isActive": true,
"createdAt": "2026-01-01T12:00:00.000Z"
}
}Test Webhook
Trigger a test event to verify your endpoint configuration. This sends a mock ping event to your webhook URL.
Endpoint
POST /webhooks/:id/test
Example Request
curl -X POST "https://api.multi-upload-tool.com/api/v1/webhooks/2/test" \
-H "x-api-key: YOUR_API_TOKEN"Example Response
{
"success": true,
"message": "Test webhook sent successfully"
}Delete Webhook
Remove a webhook configuration.
Endpoint
DELETE /webhooks/:id
Example Request
curl -X DELETE "https://api.multi-upload-tool.com/api/v1/webhooks/2" \
-H "x-api-key: YOUR_API_TOKEN"Example Response
{
"success": true,
"message": "Webhook deleted"
}List Deliveries
Every delivery attempt, newest first. An event that failed twice then succeeded shows 3 rows with the same eventId.
Endpoint
GET /webhooks/:id/deliveries?limit=50
limit is at most 200.
Example Response
{
"success": true,
"data": [
{
"id": 812,
"eventId": "evt_V1StGXR8_Z5jdHi6B-myT",
"event": "upload.completed",
"attempt": 3,
"success": true,
"statusCode": 200,
"error": null,
"durationMs": 184,
"payload": { "id": "evt_V1StGXR8_Z5jdHi6B-myT", "event": "upload.completed", "createdAt": "2026-09-23T10:00:00.000Z", "data": { "uploadId": 123 } },
"createdAt": "2026-09-23T10:02:31.000Z"
},
{
"id": 811,
"eventId": "evt_V1StGXR8_Z5jdHi6B-myT",
"event": "upload.completed",
"attempt": 2,
"success": false,
"statusCode": 502,
"error": "502 Bad Gateway",
"durationMs": 97,
"createdAt": "2026-09-23T10:00:31.000Z"
}
]
}Replay a Delivery
Sends an event again, with its original id — for example after fixing your endpoint. The replay gets its own attempts and retries.
Endpoint
POST /webhooks/:id/deliveries/:deliveryId/replay
Returns 409 if the webhook is disabled: enable it first.
curl -X POST "https://api.multi-upload-tool.com/api/v1/webhooks/2/deliveries/811/replay" \
-H "x-api-key: YOUR_API_TOKEN"{ "success": true, "data": { "eventId": "evt_V1StGXR8_Z5jdHi6B-myT" } }Rotate the Secret
Generates a new signing secret and returns it. It applies immediately, including to retries already queued: update your endpoint with the new secret right away.
Endpoint
POST /webhooks/:id/rotate-secret
{ "success": true, "data": { "secret": "5f0c2a8e7d1b4c3e9a612b8f4e1d9c07..." } }Enable or Disable a Webhook
Enable a webhook that was disabled after repeated failures, or pause one without deleting it.
Endpoint
PATCH /webhooks/:id
curl -X PATCH "https://api.multi-upload-tool.com/api/v1/webhooks/2" \
-H "x-api-key: YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"isActive": true}'Team members with the MEMBER role cannot replay, rotate or enable webhooks.