Completed or proof ready: which webhook your backend should wait for
Your product has a new flow that ends with a signature: a mandate, an onboarding contract, a consent. Your backend listens to IgniSign webhooks, and a few weeks after launch an auditor asks for the signed file behind one of your records. That is when a small choice in your webhook handler starts to matter: which event did your code treat as "done"? The signature request completing and the proof being ready are two separate events, and they do two different jobs.
The events on the way to done
For a signature request, IgniSign sends events under several topics. Three matter here:
SIGNATUREwith the actionFINALIZED: one signer has signed one document. The event carries the signer id, the document id and the signature id.SIGNATURE_REQUESTwith the actionCOMPLETED: the request has reached its end state. The event carries the signature request id and its status.SIGNATURE_PROOFwith the actionGENERATED: the proof exists. The event carries the signature request id and, for each document, the document id and a proof link with its token.
Webhooks are controlled per topic, so you choose which of these reach your endpoint. Every event also carries appId, appEnv and a verification token that your backend confirms with the API before acting.
Option 1: one handler, on completion
The shortest handler listens to COMPLETED, marks the record as signed and downloads the signed PDF in the same function.
It works in a demo. In production, the gap between the two moments is where it breaks. Completion tells you the signing is over. It does not tell you that the signed PDF, the signature files and the audit log have been generated. A download that runs inside the completion handler can find nothing to fetch yet, and the handler then grows its own waiting logic.
Option 2: two handlers, two jobs
Split the work by what each event says.
On COMPLETED, change your business state: mark the contract as signed, activate the account, move the deal forward. This event answers "has the user signed?".
On SIGNATURE_PROOF GENERATED, start the proof work: download the signed PDF for each document listed in the event, store the proof link next to your record, or both. With the Node SDK, the download is downloadSignatureByType(documentId, IGNISIGN_SIGNATURE_PROOF_TYPE.PDF_WITH_SIGNATURES), which returns a stream you write wherever your records live. This event answers "can I show the proof?".
If your application produces the advanced legal kit (the ZIP with the signature files and the audit log), the ADV_GENERATED action on the same topic tells you when it is ready. Treat it as a third, optional job, not as a condition for the first two.
What this changes in your data model
Two fields instead of one. signedAt comes from completion; proofStoredAt comes from the proof event. A record with the first and not the second is a clear state you can query: signed, proof pending. When an auditor asks for the signed file of a given record, you know whether you have it, and if not, which event you are missing.
That state also tells you where to look when something goes wrong. If the proof event arrives with an error nature, or never reaches you because your endpoint was down during a deploy, the record stays at "proof pending". Find the event in the webhook event log, resend it manually, and the same handler picks it up. Key both handlers on the signature request id and the document id, so a resent event does nothing when the work is already done.
Per-signer events are for progress
SIGNATURE FINALIZED is useful when a request has several signers and your interface shows progress, such as "two of three have signed". Use it to update that view. Do not use it to unlock the next step, and do not expect a proof from it.
The decision
Let completion move your business state and let the proof event move your files. The outcome reaches your product as soon as the signing is over, and your proof job runs only when there is a proof to fetch.
Try it in your development environment before you switch to production keys: create a request, sign it, and watch each of the three events land in the event log and in your two handlers.