Skip to main content
Webhooks deliver HTTP POST callbacks to your server when order processing completes or fails. Use webhooks instead of polling the Get Order endpoint — your server gets notified the moment a result is ready.

Setting up webhooks

1

Register a webhook endpoint

You can create a webhook endpoint via the API or the BIZ MORI Dashboard. To create one via the API, use the Create Webhook endpoint:
curl -X POST https://api.bizmori.com/api/v2/orders/webhooks \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Webhook",
    "url": "https://your-server.com/webhook"
  }'
Response:
{
  "data": {
    "id": 1,
    "name": "My Webhook",
    "secret": "whsec_xxxxxxxxxxxxxxxxxx"
  }
}
Save the secret immediately — it is shown only once and cannot be retrieved again. You need it to verify every incoming webhook signature.
2

Implement your endpoint

Your webhook handler must:
  • Accept POST requests with a JSON body
  • Respond with a 2xx status code within 5 seconds
  • Verify the X-MoriBiz-Signature header before processing
3

Verify signatures

Every request includes an X-MoriBiz-Signature header. See Signature Verification below for implementation in your language.

Event types

Event TypeDescription
order.antiAi.completedAnti-AI processing completed successfully
order.antiAi.failedAnti-AI processing failed
order.watermarkEmbed.completedWatermark embedding completed successfully
order.watermarkEmbed.failedWatermark embedding failed
order.watermarkExtract.completedWatermark extraction completed successfully
order.watermarkExtract.failedWatermark extraction failed
order.aiDetection.completedAI Detection completed successfully
order.aiDetection.failedAI Detection failed

Webhook payload

All webhook payloads follow this structure:
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "eventType": "order.antiAi.completed",
  "occurredAt": "2026-02-19T12:00:00.000Z",
  "data": {
    "orderId": "123456789",
    "orderName": "anti_ai_2026-02-19",
    "createdAt": "2026-02-19T11:50:00.000Z",
    "updatedAt": "2026-02-19T12:00:00.000Z",
    "completedAt": "2026-02-19T12:00:00.000Z",
    "status": "complete"
    // ...service-specific fields
  }
}

Completed event — common fields

FieldTypeDescription
orderIdstringOrder ID
orderNamestringOrder name
createdAtstringOrder creation time (ISO 8601)
updatedAtstringOrder last updated time (ISO 8601)
completedAtstringProcessing completion time (ISO 8601)
statusstringAlways complete

Failed event — common fields

FieldTypeDescription
orderIdstringOrder ID
orderNamestringOrder name
createdAtstringOrder creation time (ISO 8601)
updatedAtstringOrder last updated time (ISO 8601)
failedAtstringProcessing failure time (ISO 8601)
statusstringAlways failed
errorCodestringError code
errorMessagestringError message

Anti-AI / Watermark Embed — additional fields (completed)

FieldTypeDescription
fileCountintegerNumber of processed files
downloadUrlstringResult file download URL (valid for 1 hour)

Watermark Extract — additional fields (completed)

The status field is always complete. Use statusCode to determine the detection result.
FieldTypeDescription
statusCodestringdetected or undetected
watermarkFoundbooleanWhether a watermark was detected
watermarkInfo.textstringDetected watermark text (only when watermarkFound is true)

AI Detection — additional fields (completed)

FieldTypeDescription
probabilitynumberProbability of being AI-generated (0.0–1.0)
heatmapUrlstring | nullAI detection heatmap image download URL (only when generateHeatmap option was used)
overlayUrlstring | nullHeatmap overlay on original image download URL (only when generateOverlay option was used)

Signature verification

Verify webhook authenticity by checking the X-MoriBiz-Signature header. Always verify before processing the event.
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)          // use the raw request body string
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express handler
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-moribiz-signature'];

  if (!verifyWebhookSignature(req.body.toString(), signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const { eventType, data } = JSON.parse(req.body);
  console.log(`Received ${eventType} for order ${data.orderId}`);
  res.sendStatus(200);
});

Retry policy

BIZ MORI uses a multi-layered retry system to ensure reliable webhook delivery.

Initial retry

If your endpoint doesn’t return a 2xx status code, BIZ MORI immediately retries:
AttemptDelay
1st retry1 second
2nd retry2 seconds
3rd retry4 seconds

Scheduler-based retry

If all initial retries fail, the event enters a scheduler-based retry queue with increasing intervals:
AttemptDelay
4th retry30 minutes
5th retry2 hours
6th retry4 hours
After all scheduler-based retries are exhausted, the event is marked as FAILED. You can view failed events using the List Webhook Events endpoint.

Manual resend API

Regardless of the automatic retry process, you can manually resend webhooks at any time using the resend APIs:
# Retry a single event
curl -X POST https://api.bizmori.com/api/v2/orders/webhooks/{webhookId}/events/{eventId}/retry \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Retry all failed events in a date range
curl -X POST https://api.bizmori.com/api/v2/orders/webhooks/{webhookId}/events/retry-failed \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fromDate": "2026-01-01",
    "toDate": "2026-01-07"
  }'

Failure notification email

When initial webhook delivery fails, BIZ MORI sends a failure notification email to the account owner. This email is sent at most once per day to avoid excessive notifications.

Managing webhooks

ActionEndpoint
List all webhooksGET /webhooks
Create a webhookPOST /webhooks
Get webhook detailsGET /webhooks/
Update a webhookPUT /webhooks/
Delete a webhookDELETE /webhooks/
View delivery eventsGET /webhooks//events
Retry a single eventPOST /webhooks//events//retry
Retry failed eventsPOST /webhooks//events/retry-failed