PRODA Webhooks
Overview
Webhooks allow your application to react to changes on PRODA in near real-time.
Subscribing to webhook events
To subscribe to webhook events you have to provide a URL and indicate which event types you are interested in.
See the PUT subscription endpoint for details.
PRODA will make HTTPS POST requests to the provided URL, with a body content described in Section Webhook event details.
Any PRODA user can subscribe to webhook events. Typically you would use an account set up for machine-to-machine authentication, so you can easily query the API for extra information relating to an event.
Event visibility & filters
Which events are potentially visible depends on user permissions and database membership.
- Regular users see their own events and events relating to databases they are members of.
- Admin users see their own events, events relating to users in their company, and events relating to databases that belong to their company.
A webhook subscription additionally includes an event type filter. You should only subscribe to events that you intend to handle to speed up delivery and to reduce load on your servers. See Section Webhook event details for a list of event types.
Webhook event details
A webhook event is a JSON object with following structure.
interface EventCommon {
: number; // Unique event identifier
audit_event_lsn: string; // ISO8601 date & time
event_time
}
interface DatabaseEvent extends EventCommon {
: number;
object_database_id
}
interface UserEvent extends EventCommon {
: number;
object_user_id
}
interface ExtractionCompleted extends DatabaseEvent {
: "extraction-completed";
event_type: {
details: number;
extraction_id: string; // ISO8601 date
rentroll_date: { property_id: number; rentroll_id: number }[];
rentrolls;
}
}
interface ExtractionStatusSetToIncomplete extends DatabaseEvent {
: "extraction-status-set-to-incomplete";
event_type: {
details: number;
extraction_id: string; // ISO8601 date
rentroll_date: { property_id: number; rentroll_id: number }[];
rentrolls;
}
}
interface ExtractionDeleted extends DatabaseEvent {
: "extraction-deleted";
event_type: {
details: number;
extraction_id: string; // ISO8601 date
rentroll_date: { property_id: number; rentroll_id: number }[];
rentrolls;
}
}
interface ProdaAssistantDatabaseAvailability extends DatabaseEvent {
: "proda-assistant-database-availability";
event_type: {
details: "Available" | "Removed";
availability;
}
}
interface UserAccessStatusChanged extends UserEvent {
: "user-access-status-changed";
event_type: {
details: "Granted" | "Revoked";
access: "Audit" | "ProdaAssistant" | "Odin";
accessType;
}
}
interface PropertyCreated extends DatabaseEvent {
: "property-created";
event_type: {
details: number;
property_id: string;
property_name;
}
}
interface PropertyUpdated extends DatabaseEvent {
: "property-updated";
event_type: {
details: number;
property_id: string;
property_name;
}
}
interface PropertyDeleted extends DatabaseEvent {
: "property-deleted";
event_type: {
details: number;
property_id: string;
property_name;
}
}
type Event =
| ExtractionCompleted
| ExtractionStatusSetToIncomplete
| ExtractionDeleted
| ProdaAssistantDatabaseAvailability
| UserAccessStatusChanged
| PropertyCreated
| PropertyUpdated
| PropertyDeleted;
Log sequence number (LSN)
Every webhook event has a unique, typically non-decreasing log sequence number, except the test event (which has LSN 0 and varying contents).
If you have multiple subscriptions with the same target URL and they
have access to the same events, you may receive the same event
multiple times, potentially even out of order. You can use the
X-Webhook-Subscription-UserId
header to identify the
source of the event.
Otherwise, the most common reason for receiving duplicate events (same log sequence number) is a failure to respond promptly to events, see Section Responding to webhook events.
Only in exceedingly rare circumstances will PRODA send an event with a smaller log sequence number than that of any event sent before to the same subscription. (If you use the same URL in multiple subscriptions, this can happen regularly.)
For the most part you can assume that events happen approximately in order of their log sequence numbers. However, log sequence numbers do not strictly reflect any semantic order. Two events can occur simultaneously or even in reverse order of what their log sequence numbers indicate.
Note that there will usually be gaps in the observed log sequence numbers. This alone should not cause alarm. If you still suspect you have missed an event, double check your event type filters, see Section Subscribing to webhook events.
Event time
This is the approximate time the event was processed by PRODA. It does not precisely correspond to either the start nor the end of a user action.
Event time will not be strictly increasing. There may be duplicates and events may appear out of (event time) order.
Object meta data
The object_database_id
field indicates which company
database the event relates to, if any.
The object_user_id
field indicates which user the event
relates to, if any.
Responding to webhook events
You should acknowledge event reception quickly by responding with an HTTP status code of 200 and no body content.
We recommend your webhook event handler perform no work before acknowledging receipt, except writing the event to a queue. You can then drain the queue at your leisure. This avoids duplicated event deliveries and unneccessary delays. PRODA will consider failure to respond promptly as an error and will attempt to redeliver the event after some time has passed, see Section Errors.
PRODA will not follow redirects. If you need to change your webhook subscription URL, see Section Subscribing to webhook events.
Security
Webhook listeners must support TLS (HTTPS). Self-signed certificates are not accepted.
Given that your webhook listener is accessible to the internet at large, you should not blindly trust any incoming event. PRODA signs webhook events. To verify authenticity you must follow these steps:
- Retrieve the PRODA public keys for webhook signing from the jwks.json endpoint. You should cache this for up to one hour.
-
The
X-Proda-Signature
header contains a signed JSON Web Token (JWT). Verify the signature using a JWT library. The key IDkid
must match one of PRODA's public keys. Reject the webhook event if the signature is invalid. -
You can check the
iat
(issued at) claim inside the the JWT against the current, nominal POSIX time. Reject the webhook event if the discrepancy is greater than, e.g., five minutes to guard against replay attacks. -
Hash the raw body of the webhook request using SHA256. Compare the
result to the hex-encoded
body_sha256
field in the payload of the signed JWT. Reject the webhook event if the body checksums do not match.
Errors
PRODA will retry a failed webhook event delivery with exponential backoff.
The most common source of errors is failure to respond to events promptly and properly. See Section Responding to webhook events for how to do so.
If you have scheduled downtime, you can pause webhook delivery, see Section Pausing webhook delivery. Doing so ensures prompt resumption of webhook event delivery once you unpause.
Pausing webhook delivery
You can pause and resume webhook delivery at any time using the pause endpoint.
This is not necessary. You can simply not acknowledge events and PRODA will keep trying to redeliver them indefinitely with exponential backoff, see Section Errors.
However, this can be useful if you expect (or even unexpectedly experience) extended downtime. PRODA will not attempt to deliver events while paused, which avoids increasing the exponential backoff wait time. If the error retry interval expires during the pause, PRODA will attempt redelivery immediately upon unpausing. If the pause duration is shorter than the error retry interval, unpausing will not immediately retry.
In summary, if you expect or experience downtime, you can
- pause
- perform maintenance
- unpause
Once again: doing so is not necessary. PRODA will keep all events and reattempt delivery, unless the subscription itself is cancelled.