Skip to content

Webhooks

When an async inference request finishes, Meshive can POST the result to your server instead of making you poll. Every delivery is signed so you can verify it came from Meshive.

There is one delivery engine with two ways to register where events go:

MethodWhere you set itBest for
Inline callbackwebhook_url field on a single async request (API or Playground)“Tell me when this job is done.”
Subscription endpointServerless › Webhooks in the console — register a URL and pick event types”Send all matching events for this workspace here.”

Both methods use the same signature, payload schema, and retry behavior. If an inline webhook_url and a subscription endpoint resolve to the same URL for the same event, you receive the event once (deduplicated).

Add a webhook_url to any async image or video request:

Terminal window
curl "https://<your-deployment>.inference.meshive.ai/v1/images/generations?async=true" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $MESHIVE_API_KEY" \
-d '{
"model": "<model-id>",
"prompt": "A sunset over the ocean",
"size": "1024x1024",
"webhook_url": "https://your-server.com/webhooks/meshive"
}'

The URL must be HTTPS and resolve to a public address — see Security. Invalid URLs are rejected at submit time with HTTP 422.

  1. Open Serverless › Webhooks in your workspace console.

  2. Click Add endpoint, paste your HTTPS URL, and select which events to receive (default: all).

  3. Use Test to send a sample event and confirm your server responds with a 2xx.

Subscription endpoints receive every matching event for the workspace, so you don’t have to set webhook_url on each request. You can enable/disable them and inspect deliveries (status, attempts, and the exact body sent) under Deliveries.

TypeWhen
request.completedAn async request finished successfully. Result is in output_object_key / result_payload.
request.failedThe request failed. Inspect error_code / error_message.
request.canceledThe request was canceled (by you or by the sweeper).

Terminal states only — there are no intermediate-progress events. To observe progress, poll GET /v1/requests/{id}.

Every delivery has a JSON body with this envelope:

{
"id": "evt_3f9c1a2b4d5e6f70",
"type": "request.completed",
"created_at": 1780000000,
"data": {
"id": "req_abc123",
"status": "succeeded",
"modality": "image",
"namespace_name": "my-workspace",
"registration_id": 42,
"created_at": 1779999970,
"completed_at": 1779999998,
"output_object_key": "serverless/requests/req_abc123/result_0.png",
"output_bucket": "meshive-r2",
"result_payload": { "images": 1 },
"error_code": null,
"error_message": null
}
}
  • id — the event id (evt_…). All deliveries of one event share it — use it as your idempotency key (see below).
  • data.id — the request id (req_…).
  • A large result_payload is omitted (replaced with {"_truncated": true}); fetch the full result via GET /v1/requests/{id}.

Headers on each delivery:

HeaderMeaning
X-Meshive-Signaturet=<unix>,v1=<hmac-sha256> — verify this (generic endpoints only).
X-Meshive-EventThe event type.
X-Meshive-Delivery-IdIdentifies one delivery to one destination (stable across its retries).
User-AgentMeshive-Webhook/1.0

For generic endpoints, verify X-Meshive-Signature against the raw request body using your signing secret (Serverless › Webhooks → Signing secret). The signed payload is "{t}." + raw_body.

import hmac, hashlib, os
from flask import Flask, request
SECRET = os.environ["MESHIVE_WEBHOOK_SECRET"]
app = Flask(__name__)
@app.post("/webhooks/meshive")
def handler():
header = request.headers.get("X-Meshive-Signature", "")
try:
parts = dict(p.split("=", 1) for p in header.split(","))
payload = f'{parts["t"]}.'.encode() + request.get_data()
expected = hmac.new(SECRET.encode(), payload, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, parts.get("v1", "")):
return "bad signature", 401
except (ValueError, KeyError):
# malformed / missing signature header → 401 (not 500)
return "bad signature", 401
# optional but recommended: reject stale timestamps (e.g. > 5 minutes old)
event = request.get_json()
print(event["type"], event["data"]["id"], event["data"]["status"])
return "", 200
  • At-least-once. Each delivery is attempted up to 3 times with backoff (2s, 4s, 8s) on any non-2xx response or network error. An event can also legitimately arrive at your server more than once (e.g. inline callback + subscription endpoint with slightly different URLs). Dedupe on the event id (evt_…) — every delivery of the same event carries the same one.
  • Respond fast. Each attempt times out after 5 seconds — return 2xx quickly and do heavy work asynchronously, or the delivery counts as failed and is retried.
  • Auto-disable. A subscription endpoint that fails many times in a row (currently 20 consecutive deliveries) is automatically disabled, with the reason shown in the console. Re-enabling it resets the failure counter. Test sends never count toward auto-disable.
  • Email fallback. If an inline callback can’t be delivered after all retries, Meshive sends you a notification email once.

Test sends a sample event (X-Meshive-Event: webhook.test, body marked "_meshive_test": true) and shows the response code immediately. Tests are recorded in Deliveries like real events, so you can inspect exactly what was sent.

The Deliveries log shows the most recent deliveries (up to 200), filterable by endpoint or request id — each with event type, target URL, platform, delivered status, HTTP status code, attempt count, error string, and a link to the request.

The signing secret is one per workspace, shared by all endpoints. Rolling it (Serverless › Webhooks → Signing secret → Roll) invalidates the old secret immediately — deploy the new secret to all of your receivers first, then roll.

  • HTTPS only. http:// and other schemes are rejected.
  • No private targets. URLs that resolve to private, loopback, link-local, or cloud-metadata addresses are rejected (SSRF protection), both when you save and again right before each delivery. For local development, use a tunnel (e.g. ngrok) to get a public HTTPS URL.
  • No redirects. Meshive does not follow redirects when delivering.