Skip to main content

listing.section_modified

Atomic update to a listing section (gallery, home, features, documents, matterport, floorplan)

Category: Listing Lifecycle

Emitted when: After sections_atomic handler commits a section change

Envelope

Every delivery wraps the event-specific data block in the canonical envelope documented on the webhook overview page. The body carries SIX keys; the HMAC signature is delivered as the X-Webhook-Signature request header on the inbound POST to your endpoint (NOT as a body field; including it in the body would make the HMAC a function of its own output).

FieldTypeDescription
event_idstringULID; globally unique. Safe to persist as the dedup key.
event_typestringAlways listing.section_modified for this event.
api_versionstringPayload schema version (YYYY-MM-DD).
timestampintegerUnix epoch seconds at dispatch time.
noncestringULID; unique per delivery, used for replay rejection.
dataobjectEvent-specific payload (see below).

Delivery also sets three HTTP headers on the inbound POST:

HeaderMeaning
X-Webhook-Event-IdMirrors event_id; cheaper than parsing the body to dedup.
X-Webhook-TimestampMirrors timestamp for replay-window checks.
X-Webhook-Signaturesha256=<hex> HMAC over timestamp.body.

Data schema

FieldTypeRequiredDescription
agency_idstringyesAgency Id
listing_numberstringyesPublic listing number, 7-char lowercase nanoid ([a-z0-9]{7})
sectionstringyesSection that mutated. Expected values: gallery, home, features, documents, matterport, floorplan.
operation"set" | "replace" | "append" | "remove"yesOperation
summaryobjectyesSection-shaped counts / flags attached to every event. Every field is Optional so the same envelope serialises cleanly for any section type. Callers populate only the fields that apply to their section; the rest round-trip as None. Fields ------ images_added: Optional[int] Count of NEW image ids in the after-state (gallery only). images_removed: Optional[int] Count of image ids present in the before-state but not in the after-state (gallery only). images_total: Optional[int] len(after["images"]) after the update (gallery only). url_set: Optional[bool] True when the matterport URL ends up non-empty post- update, False when cleared (matterport only). floors_count_new: Optional[int] Positive delta in the floor list length (floorplan only). Zero when the mutation was a swap with equal length. floors_count_removed: Optional[int] Inverse of the above - counts floors removed (floorplan only). Zero when none were removed.
changed_bystringyesActor token: 'apikey:' for API calls, 'user:' for dashboard

Sample payload

The sample below is a live fixture. Feed the exact body bytes shown plus the timestamp into the HMAC-SHA256 recipe from the webhook overview using the documented test-vector secret (test_secret_001 ) and you will recover the signature header value printed below.

Body (delivered as the HTTP request body):

{
"event_id": "evt_4PBDEEMC8YPQB8X4KB5B3XW2G4",
"event_type": "listing.section_modified",
"api_version": "2026-04-17",
"timestamp": 1745339401,
"nonce": "2RSNGEZF5W4BW628A0HCHAPZS6",
"data": {
"agency_id": "user_01HXAGENCY0000000000000",
"listing_number": "abc1234",
"section": "gallery",
"operation": "set",
"summary": {
"images_added": 0,
"images_removed": 0,
"images_total": 0,
"url_set": true,
"floors_count_new": 0,
"floors_count_removed": 0
},
"changed_by": "apikey:key_01HXAPIKEY000000000000"
}
}

Signature header (delivered as X-Webhook-Signature on the same request):

sha256=b3913529065a729e35267d1709a591ee91d5de6e836893e696aac21f93322c39

Retry behaviour

Failed deliveries retry on the sequence 2, 4, 8, 16, 32 seconds (five attempts plus the initial call for a total of six over approximately 62 seconds of wall clock). After the final attempt the delivery lands in the dead-letter queue and the dashboard operator can replay it from Settings > API Keys > Webhook Endpoint > Deliveries. See the webhook overview for the full rules.

Verification

Every receiver MUST verify the X-Webhook-Signature header using the recipe in the webhook overview. Rejecting deliveries whose timestamp is more than 5 minutes off your wall clock (after NTP correction on your side) or whose nonce has already been consumed in the last 10 minutes is part of the contract.