JsonCut

Render webhook handling: verify, accept and replay

Build reliable render webhook handling: verify JsonCut signatures, acknowledge durable receipt, prevent duplicate delivery and replay dead-letter events safely.

Abstract geometric illustration for Render webhook handling: verify, accept and replay

Reliable render webhook handling separates a finished render from a successfully delivered result. This guide shows developers how to verify JsonCut events, accept them durably and recover failed deliveries without rendering the same creative again.

Render webhook handling starts with two separate outcomes

A completed video is not the same as a delivered video. Your renderer can finish successfully while your callback endpoint is restarting, your database is unavailable or your notification worker is stuck. Creating another render does not repair any of those failures.

Reliable render webhook handling verifies the signed request, stores the event durably, acknowledges receipt quickly and processes downstream work asynchronously. Deduplicate repeated events, make business actions idempotent and recover delivery failures through replay or bounded reconciliation—not by generating the same image or video again.

The general video API guide covers the integration architecture. This guide concentrates on the receiver and recovery path after work has been submitted.

Subscribe only to the outcomes you need

JsonCut's documented webhook events include render.completed, render.failed and render.cancelled. Register an HTTPS endpoint for the outcomes your application actually handles. A completion-only listener leaves you without the failure signals needed to close pending jobs.

Store your application's business identifier alongside the render ID when submitting work. For example, a campaign variant could be identified by campaign, product and locale. That mapping belongs in your application; do not assume an undocumented event field will carry it for you.

Keep the endpoint signing secret in server-side secret storage. JsonCut returns it once when the endpoint is created. It is not a browser credential, and it should never appear in logs or a support screenshot.

Verify the original bytes before parsing

The signed-webhook documentation defines three headers:

HeaderReceiver responsibility
X-JsonCut-Event-IdTrack event identity for deduplication
X-JsonCut-TimestampInclude the original value in signature verification and reject stale deliveries
X-JsonCut-SignatureVerify the v1= signature using the endpoint secret

The signing input is <timestamp>.<raw-body>, authenticated with HMAC-SHA256. Preserve the request's raw body bytes. Parsing JSON and serializing it again can change whitespace or formatting, producing different signed input even when the object looks equivalent.

At the receiver, reject missing or malformed verification inputs, compute the expected signature and compare it in constant time. Check lengths before calling a comparison primitive that requires equal-length buffers. Validate timestamp freshness against a deliberate, documented local policy; the public JsonCut guide does not specify a numeric tolerance, so do not silently import one from another provider.

Mount raw-body handling before middleware that consumes or rewrites the body. Parse and validate the event only after authentication succeeds. Apply body-size limits and reject unsupported event shapes rather than letting an unexpected payload reach business logic.

Acknowledge durable receipt, not completed processing

JsonCut recommends a quick 2xx response and asynchronous processing. The important word is durable: returning success while the event exists only in application memory creates a loss window during a crash.

A practical design is a durable inbox that a worker reads independently:

  1. Authenticate the request and validate its event structure.
  2. Insert an inbox record using a unique event identity scoped to the endpoint.
  3. Commit the record, then return a successful response.
  4. Let a worker claim pending inbox records and perform downstream work.
  5. Record processing completion or a retryable failure separately.

Use an atomic insert or equivalent constraint, not a read-then-insert check that two concurrent requests can both pass. A known duplicate already stored durably can receive success without starting another job.

If storage is unavailable, do not acknowledge an event you cannot retain. If a separate queue is involved, use a transactional outbox or a worker that scans the inbox so a crash between database commit and queue publication cannot strand accepted work. These are application design recommendations, not claims about JsonCut's internal architecture.

Event deduplication is not business idempotency

These protections solve different problems:

ProtectionWhat it identifiesExample purpose
Render submission idempotencyOne logical render requestAvoid duplicate render creation after a submission timeout
Event deduplicationOne received event identityAvoid processing the same callback twice
Business-action idempotencyOne intended downstream actionAvoid delivering the same campaign variant twice

A worker can crash after a destination accepted a file but before your database records success. When that worker restarts, the inbox record alone cannot prove whether delivery happened. Use a stable destination key or an idempotency mechanism offered by that destination, and reconcile uncertain outcomes before retrying.

Stripe's webhook guidance independently recommends duplicate-event tracking and asynchronous handling. Its retry schedules, signature format and timestamp defaults are Stripe-specific; they are not JsonCut settings.

Replay delivery failures without re-rendering

JsonCut documents bounded exponential delivery retries, but not a fixed attempt count or retention window in the public webhook guide. Build monitoring around observed delivery state rather than an invented schedule.

The documented operations are:

OperationPurpose
GET /api/v2/webhooks/{id}/deliveriesInspect recent safe delivery state
POST /api/v2/webhooks/{id}/testCreate one signed test event
POST /api/v2/webhooks/{id}/deliveries/{deliveryId}/replayRetry a dead-letter delivery while preserving event identity

Repair the cause before replaying: restore the receiver, fix its verification configuration or recover storage. Then replay the relevant dead-letter delivery and confirm that the receiver accepts it and the downstream worker finishes.

Preserved event identity is exactly why deduplication must remain enabled during recovery. If your inbox already accepted an event but its worker failed later, resume that existing inbox job instead of deleting the deduplication record to force another callback through.

Delivery inspection deliberately excludes downstream response bodies. Keep your own safe diagnostics: event ID, render ID, receipt time, verification outcome and worker status. Avoid logging secrets or full creative payloads by default.

Reconcile the renders that never reach a final local state

Maintain a bounded reconciliation job for renders your application still considers unresolved. Read the canonical render resource and compare it with local state. The render operations guide lists queued, rendering, completed, failed and cancelled; progress is presentation data, not the durable outcome.

If the resource is completed but local delivery is missing, recover the delivery path. If it failed, inspect the error and follow the documented retryable flag before considering another render. Do not turn a callback timeout into an automatic render retry.

Apply this distinction to bulk workflows too: input validation, rendering and delivery have separate recovery paths. A callback outage does not invalidate outputs that already completed.

Test the failure paths before increasing volume

Use a test endpoint and controlled failures to check the full receiver-to-worker path:

TestExpected application behavior
Change one byte in a signed bodyReject authentication
Send missing or malformed verification headersReject safely, without an uncaught exception
Deliver the same valid event concurrentlyOne durable inbox item, no duplicate action
Make storage unavailable before receiptDo not acknowledge unretained work
Crash after durable receiptWorker resumes pending work
Replay an eligible dead-letter deliveryPreserve deduplication and complete recovery
Complete a render without updating local stateReconciliation identifies the missing delivery

A signed test event checks connectivity and authentication. It does not replace a real end-to-end render with artifact handling and your actual downstream destination.

FAQ

Does a successful webhook response mean the file was delivered?

Not necessarily. In this architecture, it means the receiver durably accepted the event. Track worker completion and destination delivery separately.

Should I create a new render when a callback fails?

No—not solely because delivery failed. Inspect the existing render and repair or replay delivery first. Render retries address render failures, not receiver outages.

Can I disable deduplication for a replay?

Keep it enabled. JsonCut's documented dead-letter replay preserves event identity. Resume an existing failed inbox job when receipt already succeeded.

Start with one endpoint, one real render and the failure tests above. Keep authentication, durable receipt and business delivery as separate, observable steps.

Sources

https://jsoncut.com/docs/webhooks/ — JsonCut signed webhooks, signature scheme and delivery operations — accessed 2026-10-21.

https://jsoncut.com/docs/operations/ — JsonCut canonical render lifecycle and retry guidance — accessed 2026-10-21.

https://jsoncut.com/docs/ — JsonCut API loop and server-side credentials — accessed 2026-10-21.

https://docs.stripe.com/webhooks — Stripe webhook guidance, duplicate events and asynchronous processing; no Stripe-specific limits attributed to JsonCut — accessed 2026-10-21.

Your next post is one sentence away.Start free, no editing skills needed.