Why use webhooks
Every delivery is a signed JSON body your application can act on:- Publish a product image the second its render lands
- Alert on a failed render while the order is still open
- Keep your own record of every job the account ran
- Drive a queue of PSD uploads from one route instead of many status calls
How to receive webhooks
1
Create an endpoint in your app
Add a route that accepts POST requests and answers Any status other than
200 once the body is
safely stored.app/api/sudomock/route.js
2xx, and any timeout, counts as a failed delivery.2
Register the endpoint
- Open Dashboard, Webhooks
- Add your public HTTPS URL
- Pick the events you want, or leave the selection empty for all of them
- Copy the signing secret before you close the dialog
whsec_ and is shown in full only when it is
created and when it is rotated. Every later read masks it as
whsec_****<last4>.Endpoints can also be managed from your own backend. See Create a new
webhook
endpoint.
3
Send a test event
Send a test delivery from the panel, or call Send a test
event. It travels the
same signed path as a real one, so verification that passes here passes in
production.A finished render arrives in this shape:
Every event is listed in Events, and every field of the body in
The payload.
4
Verify the signature, then handle the event
Check the signature before you act on the body, then branch on Verifying signatures carries the full
verification function in Node.js and Python.
event.app/api/sudomock/route.js
5
Move the endpoint to production
Deploy the handler, then register the production URL the same way. Each
endpoint has its own secret, so the development one can stay registered
beside it.
Events
Leave
event_types empty to subscribe to every event, including ones added
later. A failed upload is delivered as render.failed, so subscribe to
render.failed if you ingest PSDs.
The payload
Every delivery opens with the same envelope. A render, an upload, a video and a photo mockup render carry the fields below. The threephoto_mockup.*
creation events carry the mockup’s own fields instead, and Photo
mockups covers them.
string
The event that fired, spelled exactly as in the table above.
string
The job this event belongs to. It is the id you pass to
GET /api/v1/jobs/{job_id}, and half of the idempotency key.string
The job family behind the event, for example
render, upload or video.
An endpoint subscribed to everything can filter on it without parsing the
event name.succeeded | failed | ready | rejected
The final state the job reached. It matches the second half of the event
name.
string | null
The finished file for a render or a video, and the new
mockup_uuid for
upload.succeeded. It is null on a failure, and it can be null on a
delivery that was replayed.object | null
null on success. On a failure it carries the same structured error the API
returns, with error_code and message. See Errors.string
ISO 8601 timestamp of the moment the event was created.
POST with Content-Type: application/json, and two
more headers travel with it, X-SudoMock-Signature and
X-SudoMock-Timestamp. Verifying
signatures shows what to compute from them.
FAQ
What happens when a delivery fails?
What happens when a delivery fails?
Failed deliveries are retried automatically. Every attempt is logged with
the HTTP status your server returned, the attempt count and the last error,
and you can send one again yourself once the server is back.From the panel:
- Open Dashboard, Webhooks
- Open the endpoint
- Open the delivery you want to send again
- Replay it
How do I keep from acting on one event twice?
How do I keep from acting on one event twice?
Treat
job_id plus the event name as the delivery’s idempotency key,
persist it before applying side effects, and return a 2xx response only
after processing succeeds. A replayed delivery can arrive with result_url
set to null; fetch the result by polling GET /api/v1/jobs/{job_id} when
that happens.Do webhooks replace polling?
Do webhooks replace polling?
No.
GET /api/v1/jobs/{job_id} stays the source of truth for a job, and a
webhook is the notification that saves you from asking on a timer.How do I page through deliveries and events?
How do I page through deliveries and events?
The delivery and event feeds page with an opaque cursor. Make the first
request without
cursor. When another page exists, the response carries
X-Webhook-Next-Cursor, and you send that exact value as the next
request’s cursor. When the header is absent, the list is complete.
Pagination covers the other list endpoints.Which endpoints receive the earlier photo mockup names?
Which endpoints receive the earlier photo mockup names?
Endpoints created before the
photo_mockup names were introduced are
pinned to the earlier spelling of the same five events:
2d_mockup.ready, 2d_mockup.rejected, 2d_mockup.failed,
2d_render.succeeded and 2d_render.failed, with kind spelled
2d_create or 2d_render. They keep receiving them unchanged. The
endpoint’s event_naming field reads legacy or current and says which
spelling it receives; Create a new webhook
endpoint
covers how a new endpoint is pinned. Either spelling is accepted in
event_types. Move an existing endpoint with PATCH { "event_naming": "current" } once your handler reads the new names.Verifying signatures
Node.js and Python you can paste into your handler.
Webhook endpoints
Create, update, rotate and test an endpoint from your backend.
Webhook deliveries
Read every attempt, and replay the ones that failed.
Watch deliveries from the panel
Success rate, delivery log and the account-wide event feed.