Webhooks
PropFit tells your server when something happens, with a signed HTTPS POST.
Add an endpoint
In PropFit, owners and admins open Settings → Integrations → Webhooks, add an HTTPS endpoint (public hosts only), pick the event types and copy the signing secret (whsec_…). The secret is shown once. Webhooks need a plan with API access.
Deliveries
Each delivery is a POST with a JSON body of ids and enums only. Call the API for details. Deduplicate on id, the event id.
{
"id": "01a1…",
"type": "offer_status_changed",
"schema_version": 1,
"occurred_at": "2026-11-05T21:04:11.120Z",
"organization_id": "01a0…",
"data": {
"offer_id": "01a1…",
"unit_id": "01a1…",
"from_status": "draft",
"to_status": "published"
}
}| Header | Value |
|---|---|
PropFit-Event-Id | The event id (the same as the body’s id). |
PropFit-Event-Type | The event type. |
PropFit-Delivery-Id | This delivery to this endpoint. |
PropFit-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
User-Agent | PropFit-Webhooks/1 |
Events
| Event | When | data keys |
|---|---|---|
offer_status_changed | Vacancy status changed | offer_idunit_idfrom_statusto_status |
property_created | Property added | property_idproperty_type |
qualification_link_shared | Qualification link created | link_idoffer_idproperty_idchannel |
criteria_created | Criteria activated | policy_idscope_typeversioncompliance |
potential_match | New potential match (state only) | offer_idstateprevious_stategroup |
verified_match | New verified match (state only) | offer_idstateprevious_stategroup |
listing_moderated | Listing moderated by PropFit | offer_idactionoffer_status |
lease_confirmed | Vacancy marked leased | offer_idlease_outcome_idconfirmationattributed |
tour_requested | Tour requested (ids and match state only) | offer_idslot_idmatch_stateinvited |
Match events carry the match state only, never a renter id. Read match summaries through the API for criterion results.
Verify the signature
The signature is an HMAC-SHA256 of <t>.<raw body> with your signing secret. Verify it against the raw request body before trusting a delivery, and reject timestamps more than five minutes old.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(secret: string, header: string, rawBody: string, now = Date.now() / 1000) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=') as [string, string]));
const t = Number(parts.t);
if (!t || Math.abs(now - t) > 300) return false; // replay window: five minutes
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return (
expected.length === parts.v1?.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
);
}Retries
- Answer with any 2xx within 10 seconds. Redirects count as failures.
- Failures retry with backoff: 1 minute, then doubling, at most 6 hours apart, for up to 8 attempts.
- After 15 failures in a row PropFit turns the endpoint off and shows why in Settings. Turn it back on there once it’s fixed.
- Deliveries can arrive more than once or out of order. Deduplicate on
idand fetch the current state from the API.