A webhook can tell a publishing workflow that something happened, but receiving the message is not the same as completing the work it describes. The receiver may need to validate the event, identify the affected content, prepare a job, contact a destination, and confirm the result. Treating all of that as one synchronous action makes the system harder to recover when a request is repeated, delayed, or interrupted.
This guide proposes an event-handling design for publishing systems you operate or are authorized to integrate. It is not a live webhook endpoint supplied by PublishAPI.com. The focus is on meaningful state, duplicate handling, and operator visibility. The objective is not to promise perfect delivery; it is to make uncertainty visible and give the workflow a deliberate way to resolve it.
Define what each event actually means
Start with an event vocabulary that reflects the source system. A draft saved event is not necessarily an approval, and an approval is not necessarily evidence that content is public. Document the meaning of each event before connecting it to an action with external side effects.
Include the relevant content identifier and revision in the job context your application creates. A worker should process the intended revision, not whichever draft happens to be newest when it eventually runs. Otherwise a delayed event can accidentally publish edits that did not belong to the original approval decision.
Keep the event record separate from the delivery job. One event may produce no work, one job, or several destination-specific jobs. Recording that relationship makes it possible to explain what the system did without pretending every inbound message maps neatly to one publication.
Validate before accepting authority
Confirm that an event comes through the authentication or signature mechanism documented by the sender. A payload that looks like an approval should not gain authority merely because it contains the right words. Use the sender’s actual verification rules rather than inventing a generic signature check and assuming it applies everywhere.
GitHub’s webhook best-practices guide recommends using a webhook secret, responding promptly, processing asynchronously where appropriate, and using the delivery identifier to help protect against replayed deliveries. These are useful concrete practices for GitHub integrations. Other senders have their own contracts, identifiers, and retry behavior, which must be verified separately.
Reject unsupported event types clearly. A permissive receiver that tries to interpret every incoming shape increases the chance of an unintended action. Keep the accepted event set small until you have a defined workflow for each additional type.
Acknowledge receipt, then track processing
For a workflow that uses a queue, acknowledge the accepted event only after the receiver has recorded enough information to process it according to your durability requirements. Keep expensive publishing work outside the immediate inbound request when the sender’s contract and your architecture support that design.
Expose the distinction in the operator interface. Received, queued, processing, failed, and confirmed are more informative than one vague success flag. The person managing the publication should know whether the system has accepted responsibility for a job or actually verified the destination result.
Decide what happens when the queue is unavailable. Silently accepting an event that has nowhere to go creates a misleading record. The appropriate response depends on the sender’s contract, but your own application should not claim durable acceptance unless it has evidence for it.
Handle duplicates as an ordinary condition
Repeated events should be part of your test plan, not treated as an exceptional surprise. Use the sender’s stable delivery identity where available and keep a record of previously handled deliveries within the retention policy your project needs. Also consider the business operation: two different events may still refer to the same approved content revision.
Do not confuse event deduplication with destination duplicate prevention. A receiver can correctly ignore a repeated event while a worker still repeats a remote create operation after an uncertain timeout. Those are separate boundaries. The destination job needs its own identity and reconciliation strategy.
The Publish API workflow guide explains why content identity, revision, and destination references should be kept distinct. That model gives duplicate handling something more reliable than a comparison of article titles.
Design retries around the failure
Classify failures in terms an operator can act on. Invalid content usually needs correction, missing permission needs an access review, and a temporary connectivity problem may justify another attempt. A single retry policy applied to every failure can waste resources while hiding the real cause.
Use a bounded retry policy and record each attempt’s result. Avoid repeatedly sending the same rejected content without a change. For uncertain outcomes, reconcile with the destination before issuing a new create operation. The exact mechanism depends on what the destination exposes and must be tested in that environment.
Make manual retry meaningful. The interface should show which revision and destination will be used and whether the previous attempt might already have created a record. A button labeled retry is not enough when the operator cannot tell whether pressing it could produce a duplicate publication.
Consider delayed and out-of-order work
Imagine an approved revision followed by a correction and then a delayed event for the older revision. Decide whether the older job should be cancelled, superseded, or processed under a specific policy. Do not let arrival order become an undocumented editorial decision.
Compare each job with the current release state before performing a public side effect. The check should use the approved revision and destination context, not merely the latest modification timestamp. Timestamps can help diagnosis, but a clear revision relationship is easier to reason about when several edits occur close together.
Keep superseded jobs visible with an explanation. Deleting them without a trace can make the event history appear incomplete. An operator should be able to understand that the system intentionally skipped an older release rather than assuming work disappeared.
Build an operator-friendly failure record
A useful job detail includes the source identifier, approved revision, destination, event reference, attempt history, and current next action. Keep error messages specific enough to distinguish a mapping problem from an unavailable destination. Redact credentials and avoid exposing a private article body in routine operational screens.
Provide a way to identify the remote record when one exists. If the destination accepted a post but later verification failed, the operator needs a path to inspect that post rather than starting from scratch. Keep the destination reference even when the overall job remains unresolved.
The credentials and permissions guide explains why operational visibility should not become unrestricted access to secrets. Design diagnostic information as a product surface with clear boundaries, not a raw dump of request data.
Rehearse the uncomfortable cases
Test the same event twice, a delayed older revision, an invalid signature, an unsupported event type, and an interrupted destination request. Include a case in which the remote action succeeds but the client does not receive the response. That last scenario is particularly valuable because it exposes whether your workflow understands uncertainty.
Ask an operator to recover each case using the documented interface and procedure. Record which steps required guesswork. Improve the job model and messages until the person can explain what happened, what remains unknown, and why the proposed next action is safe enough for the project’s requirements.
Make duplicate delivery an acceptance test
In a controlled fixture, represent one approved source revision with one event identifier. Deliver that event twice to your test receiver. Record the outcome you expect: both deliveries can be acknowledged, but they must not create two intended destination publications.
Then simulate the destination accepting an operation while the worker fails before saving its result. This is a different problem from receiving a duplicate before any work has started. The next attempt needs a reconciliation path that can establish what already happened rather than assuming the first operation failed.
Finally, deliver an older revision after a newer one has completed. Confirm that your revision policy prevents an accidental rollback. Capture the event identity, source revision, destination identity, and resolution in the fixture notes. The aim is not to promise exactly-once delivery; it is to make uncertain outcomes understandable and recoverable.
Conclusion: make uncertainty manageable
A reliable webhook workflow is not defined by the absence of retries. It is defined by a clear event contract, verified authority, durable job context, deliberate duplicate handling, and honest destination confirmation. Keep receipt separate from completion and keep retries tied to the actual failure. Begin with one event and one destination, then expand only after the uncomfortable cases are understandable to the people responsible for the publication.



