Webhooks V2
Webhooks allow your application to be notified of changes in a transaction's state rather than requesting the state from the API directly.
Proof webhooks allow your application to be notified of changes in a transaction's status. The POST request sent from Proof contains a JSON body that describes the event and data relevant to the event.
Webhook Setup
To set up and modify your Proof webhooks, you can call our Webhook API endpoints from the command line, or tools like Postman.
What's New with Webhooks V2?
Webhooks V2 supports a number of enhancements from V1:
- Subscribe to individual webhook events
- Create multiple subscriptions
- Delete a webhook subscription
- List all events that've been sent for a given webhook subscription
- List all webhook subscriptions for your account
- List all webhook events that are available to subscribe to
Migrating to Webhooks V2
It is simple to move to Webhooks V2:
- Determine the specific events you would like to subscribe to
- Make a DELETE call to
/webhooks
to remove the V1 subscription - Make a POST call to
/v2/webhooks
to subscribe to V2 webhooks (see format here) - Edit any firewall restrictions on your network that may restrict our ability to send you webhook calls
Please note: a small number of events that were available in Webhooks V1 will no longer be available in Webhooks V2:
transaction.title_added
Webhook Subscriptions
Subscription | Description | Webhook Body |
---|---|---|
notary.* | This specific subscription string will subscribe the organization to all notary sub-events. | See individual notary event bodies below. |
notary.compliant | This event is triggered when a notary's profile is reviewed and marked compliant by our compliance team. | { event: 'notary.compliant' data: { notary_id: ID of notary status: status of event } } |
notary.created | This event is triggered when a new notary is created in your organization. | { event: 'notary.created' data: { notary_id: ID of notary status: status of event } } |
notary.needs_review | This event is triggered when a Notary has finished onboarding and needs to be reviewed by our compliance team. | { event: 'notary.needs_review' data: { notary_id: ID of notary status: status of event } } |
notary.non_compliant | This event is triggered when a notary is marked non-compliant after review by our compliance team. | { event: 'notary.non_compliant' data: { notary_id: ID of notary status: status of event } } |
notary.signer_ready | This event is triggered when a notary has been assigned to a transaction and signer has requested a meeting | { event: 'notary.signer_ready' data: { notary_id: ID of notary transaction_access_link: link to transaction } } |
transaction.* | This specific subscription string will subscribe the organization to all transaction sub-events. | See individual transaction event bodies below. |
transaction.created | This event triggers whenever a transaction is created. | { "event":"transaction.created","data":{"transaction_id":transaction ID (string)}} |
transaction.deleted | This event triggers whenever a transaction is deleted. | {"event":"transaction.deleted","data":{"transaction_id":transaction ID (string)}} |
transaction.expired | This event triggers whenever a transaction has passed a set expiration date. | {"event": 'transaction.expired',"data":{transaction_id:transaction ID (string)}} |
transaction.updated | This event triggers whenever a transaction is updated. | {"event":"transaction.updated","data":{"transaction_id":transaction ID (string)}} |
transaction.recalled | This event triggers whenever a transaction is recalled. | {"event":"transaction.recalled","data":{"transaction_id":transaction ID (string)}} |
transaction.document.upload | This event triggers whenever a document bundle is uploaded to a transaction. | {"event":"transaction.document.upload","data":{"transaction_id":transaction ID (string),"organization_name":name of org (string),"document": {"id":document ID (string),"name":document name (string)},"date_occurred":ISO8601 timestamp with timezone (string)}} |
transaction.document.processed | This event triggers when a document has finished processing. Any white text tags or template matching has finished and the transaction is safe to activate at this point. | {"event":"transaction.document.processed","data":{"transaction_id":transaction ID (string),"organization_name":name of org (string),"document": {"id":document ID (string),"name":document name (string)},"date_occurred":ISO8601 timestamp with timezone (string)}} |
transaction.reviewed (Lender only) | This event triggers whenever a title agency has finished reviewing a document in a collaborative transaction | {"event":"transaction.document.reviewed","data":{"transaction_id:transaction ID (string),"organization_name": name of org (string),"document":{"id":document ID (string),"name":document name (string)},"date_occurred": ISO8601 timestamp with timezone}} |
transaction.meeting.created | This event triggers anytime signer(s) join a meeting. This event can occur when a notary or trusted referee picks up a meeting, or when concurrent signers join an ongoing meeting. | { event: 'transaction.meeting.created', data: { transaction_id: "transaction ID", date_occurred: "ISO8601 timestamp with timezone", signers: [ { first_name: "first name", middle_name: "middle name", last_name: "last name", external_id: "signer external ID", signer_id: "signer ID" } ], meeting: { meeting_id: "meeting ID" } } } |
transaction.meeting.failed | This event triggers when a notary terminates a meeting with failure, or when a meeting is terminated after inactivity from participants (e.g. participants lost connection). | { event: 'transaction.meeting.failed', data: { transaction_id: "transaction ID", date_occurred: "ISO8601 timestamp with timezone", meeting: { meeting_id: "meeting ID" } } } |
transaction.meeting.requested | This event triggers anytime signer(s) request a meeting. It can include multiple signers if they are collocated. | { event: 'transaction.meeting.requested', data: { transaction_id: "transaction ID", date_occurred: "ISO8601 timestamp with timezone", signers: [ { first_name: "first name", middle_name: "middle name", last_name: "last name", external_id: "signer external ID", signer_id: "signer ID" } ] } } |
transaction.meeting.video.processed | This event triggers once the notary or trusted referee meeting has finished and the recording has finished processing. You can use this event to trigger a call to Retrieve Notarization Record to fetch the meeting video. | { event: 'transaction.meeting.video.processed' data: { date_occurred: ISO8601 timestamp with timezone, meeting: { meeting_id: meeting id api_url: "https://api.proof.com/v1/notarization_records/meeting_id" }, transaction_id: ID of transaction, }, event: "transaction.meeting.video.processing.complete" } |
transaction.notary.assigned | This event triggers anytime a notary is assigned to a transaction. | { event: 'transaction.notary.assigned' data: { transaction_id: ID of transaction organization_name: name of calling org date_occurred: ISO8601 timestamp with timezone } } |
transaction.sent_to_closing_ops | This event triggers whenever a transaction is sent to the Proof closing ops team. | { event: 'transaction.sent_to_closing_ops' data: { transaction_id: ID of transaction organization_name: name of calling org date_occurred: ISO8601 timestamp with timezone } } |
transaction.sent_to_signer | This event triggers whenever a transaction is sent to a signer. | { event: 'transaction.sent_to_signer' data: { transaction_id: ID of transaction organization_name: name of calling org date_occurred: ISO8601 timestamp with timezone } } |
transaction.sent_to_title_agency | This event triggers whenever a transaction is sent from a lender to a title agency in the real estate collab workflow. | { event: 'transaction.sent_to_title_agency' data: { transaction_id: ID of transaction organization_name: name of calling org date_occurred: ISO8601 timestamp with timezone } } |
transaction.signer.kba_failed | This event triggers when a signer failed KBA and is locked out due to too many failed attempts. | { event: 'transaction.signer.kba_failed', data: { transaction_id: "transaction ID", date_occurred: "ISO8601 timestamp with timezone", signers: [{ first_name: "first name", middle_name: "middle name", last_name: "last name", external_id: "signer external ID", signer_id: "signer ID" } ] } } |
transaction.signer.kba_passed | This event triggers when a signer passed KBA for the transaction. | { event: 'transaction.signer.kba_passed', data: { transaction_id: "transaction ID", date_occurred: "ISO8601 timestamp with timezone", signers: [{ first_name: "first name", middle_name: "middle name", last_name: "last name", external_id: "signer external ID", signer_id: "signer ID" } ] } } |
transaction.underwriter.not_available | This event triggers whenever an underwriter is not available for a transaction. | { event: 'transaction.underwriter.not_available' data: { id: ID of transaction } } |
transaction.partially_completed | This event triggers whenever a transaction is partially completed by a signer. The event re-triggers anytime another signer completes their portion of the document. Only applies to signers in separate signing sessions. | { event: 'transaction.partially_completed', data: { transaction_id: "transaction ID", date_occurred: "ISO8601 timestamp with timezone", signers: [{ first_name: "first name", middle_name: "middle name", last_name: "last name", external_id: "signer external ID", signer_id: "signer ID" } ] } } |
transaction.completed | This event triggers whenever a transaction moves into the completed state, following successful termination of the notary meeting or completion of the document signing. | {"event": "transaction.completed","data":{ transaction_id: ID of transaction}} |
transaction.completed (For Identify transactions only) | This event triggers whenever a transaction moves into the completed state, following completion of all identity verification steps (regardless of pass/fail status). Identify transactions include additional boolean values indicating if the identity verification steps passed or failed, as well as an overall pass/fail value. If an identity verification step is not included (such as KBA in an IAL2-level transaction), the value will default to true . | {"event": "transaction.completed","data": {"transaction_id": ID of transaction,"signers":[{"signer_id": ID of signer, "full_verification_process_passed": boolean,"kba_passed": boolean,"credential_analysis_passed": boolean,"selfie_passed": boolean}]}} |
transaction.released | This event triggers when the documents are released (available for download from the API). Please listen for this event when using a signer-paid workflow as documents may not be available when transaction.completed fires. | {"event":"transaction.released","data":{"transaction_id":"ot_XXXXXX"}} |
transaction.completed_with_rejections | This event triggers when a notarization transaction is completed but a subset of documents have been rejected for notarization by the notary. | { event: "transaction.completed_with_rejections", data: { transaction_id: ID of transaction } } |
Errors and Retries
The webhook expects the receiver to respond with a 200 response code. If for some reason Proof cannot reach the webhook URL or your application responds with any response code other than 200, Proof will retry the request
Retry Back Off
We recommend an idempotent webhook implementation. Our webhooks have a 30 second timeout - should we not receive a response in 30 seconds, we will retry the response. Requests that are retried for any reason use a back-off algorithm that will make up to 16 attempts across 48 hours.
Note that webhooks can be sent more than once and delivery is not guaranteed to be in order. The expected behavior is for your application to manage the state and skip to the latest status.
Security
Webhook messages are signed so your application can verify that the sender is Proof. Webhook requests contain an X-Notarize-Signature header with a hexadecimal HMAC signature of the request body, using your API key as the key and SHA256 as the hash function.
You can verify the authenticity of the webhook by computing the signature with your API key and request body, and comparing it to the value in the X-Notarize-Signature header.
Updated 15 days ago