API Reference

V3 Order Status Webhook

Overview

Subscribe to the Order Statuses Webhook to get real-time updates on the status of your PlanOmatic order. Think of the webhook as a push notification! Get started by getting access to our integration in PlanOintegrate: email [email protected] to request access.

👍

Improved V3 Order Object

We have cut out what is no longer needed from the order object that is included in our webhooks, and added new elements that are relevant to our industry today. For example, the V3 order object now includes photo URLs! No need to use an additional API for photo asset retrieval. Photo URLs are now included in webhooks when ready.

Stay Up to Date on the Status of Your Orders

By subscribing to the webhook, your team will immediately be alerted of any issues on-site and be notified within seconds of the photos being delivered. Store these updates in your system to create transparency throughout your marketing/leasing teams. Order Statuses and Events >

Order Status Webhook Features

FeatureV3V2Description
Receive Real Time Updates on the Status of Your Orders✅✅Stay in the loop throughout the life cycle of your order with live updates.
Receive 3D Tours Links As Soon As They Are Available✅✅Once an order's 3D tour becomes available, a link to the tour can be found in the webhook payload.
Learn more.
Receive Photo and Floor Plan Assets As Soon As They Are Available✅Once an order's photo and floor plan assets become available, you can grab links to them in the V3 Order Status Webhook. Learn more.
Receive Custom Metadata About the Order✅Receive the metadata you sent with the order request (up to 4 key/value pairs). Read more in the metadata param in the Order API.

Important Webhook Payload Data

The webhook body is the PlanOmatic order object. The same object is returned in the data field of every Create Order and Retrieve Order response, so everything described on this page is also available on demand through Retrieve Order. The only difference is the wrapper: API responses look like { "code": 200, "status": "action-successful", "data": { ...order object... }, "message": "Order Retrieved." }, while the webhook POST body is the order object itself with no wrapper. The majority of the data has the same structure as the parameters of the Create Order API; the sections below cover the data that appears as the order progresses.

Event That Triggered the Webhook

Every time an order status webhook is sent, it is because the order experienced an event. The events indicate an order has been scheduled, or the visit could not be completed, or the requested assets have been delivered, and more. Order Statuses and Events >

"order_status": "completed",
"event": "order.delivered"

Links

The links object carries the URLs that exist for the order. It is empty ({}) until delivery. A delivered order carries tour_link and tour_mls_link. The 3D tour key depends on the service ordered: a Zillow 3D Home Tour arrives as zillow_3d_link.

"links": {
  "tour_link": "https://tours.planomatic.com/865496",
  "tour_mls_link": "https://tours.planomatic.com/mls865496",
  "zillow_3d_link": "https://www.zillow.com/view-imx/XXXXXXXXXX"
}
KeyWhen it appears
tour_linkEvery delivered order. The PlanOmatic tour page for the property.
tour_mls_linkEvery delivered order. The unbranded version of the tour page for MLS use.
zillow_3d_linkA Zillow 3D Home Tour was ordered and published.
matterport_3d_link, video_slideshow_link, video_walkthrough_link, home_measurements_linkLegacy products. Rarely present; none of the services in the current catalog produce them.

Only the keys that exist for the order are present, so read them defensively. Photos are not managed through a link in the payload; your team manages photos in Connect at app.planomatic.com.

Photo and Floor Plan Links

Photo and floor plan data can be found in the photos array. It is an empty array until order.delivered. Below is a description of the photo attributes and an example.

"photos": [
  {
    "sequence": 1,
    "caption": "Front View",
    "full_size_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo}/fullSize.jpg",
    "full_size_watermarked_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo}/wm/fullSize.jpg",
    "uploaded_at": "2026-10-16T16:23:11.000Z",
    "modified_at": "2026-10-17T17:54:46.000Z"
  }
]
Attributes Details
AttributeDescription
sequenceNumerical sequence of the photo based on PlanOmatic's sorting pattern. Please consult [email protected] before building any logic based on this field.
captionHuman readable text describing the photo. Please consult [email protected] before building any logic based on this field.
full_size_urlURL to the full sized version of the photo. Generally at the aspect ratio of (3600 x 2400).
full_size_watermarked_urlURL to the full sized watermarked version of the photo. Generally at the aspect ratio of (3600 x 2400). null when your account has no watermark on file, and on older orders delivered before your watermark was set up.
uploaded_atUTC datetime when the photo was uploaded.
modified_atUTC datetime when the photo was last modified.

Appointment Rescheduled

From time to time a PlanOtech will need to reschedule an appointment because of weather, sickness, or other event. When this happens, PlanOmatic will broadcast a appointment.awaiting_reschedule webhook event to subscribers. This event will contain details about the reason for the rescheduling and a new appointment. Below is an example of an appointments array upon a appointment.awaiting_reschedule event.

"appointments": [
  {
    "appointment_id": 3760017,
    "start_datetime": "2026-10-17T09:01:00.000+00:00",
    "end_datetime": "2026-10-17T10:01:00.000+00:00",
    "duration_m": 60,
    "planotech_name": "Bobby",
    "cancelation_reason": null,
    "cancelation_notes": null,
    "canceled": null
  },
  {
    "appointment_id": 3759878,
    "start_datetime": "2026-10-16T12:45:00.000+00:00",
    "end_datetime": "2026-10-16T13:45:00.000+00:00",
    "duration_m": 60,
    "planotech_name": "Bobby",
    "cancelation_reason": "Weather does not allow for outdoor photography",
    "cancelation_notes": "Roads too icy",
    "canceled": true
  }
]

You can pull a lot of useful information from an order's appointments object such as the time and date of the appointment start_datetime in Coordinated Universal Time (UTC). This time is an estimate until the PlanOtech is on site.

You can also note why a reschedule has taken place by observing the canceled appointment attribute and pulling the cancelation_reason and cancelation_notes.

Attributes Details
AttributeDescription
appointments.appointment_idPlanOmatic appointment id (integer).
appointments.start_datetimeDate time of the start of the appointment. Estimate prior to the actual appointment.
appointments.end_datetimeDate time of the end of the appointment.
appointments.duration_mPlanned duration in minutes.
appointments.planotech_nameThe PlanOtech assigned to the appointment.
appointments.cancelation_reasonReason for the reschedule, as a category chosen by the PlanOtech.
appointments.cancelation_notesAdditional notes on cancelation from PlanOtech
appointments.canceledtrue when this specific appointment (not the order) has been canceled; false or null otherwise.

Unable To Complete Appointment Details

From time to time you may send an order to PlanOmatic when the property is not ready for the services requested. For example, if there is no lockbox for our photographer to use to access the property, our photographer will call our client's on-site contact and if there is no response the PlanOtech will submit the order as appointment.unable_to_complete and provide a reason and description.

"unable_to_complete_appt": true,
"unable_to_complete_appt_reason": "Non-Rently - Invalid lockbox code",
"unable_to_complete_appt_notes": "Tried the code several times, checked both doors and around the house. Texted the contact but received no response.",
Attributes Details
AttributeDescription
unable_to_complete_apptSimple true or false value to identify if the order resulted in an appointment that was unable to complete.
unable_to_complete_appt_reasonCategory of issue, chosen by the PlanOtech. null unless unable_to_complete_appt is true. The categories are subject to change; keep an "other" bucket.
unable_to_complete_appt_notesFree-text description of the issue written by the PlanOtech. null unless unable_to_complete_appt is true.

Order Cancelation Details

An order can be canceled by you (through the Cancel Order API or the Connect portal) or by PlanOmatic. The most common PlanOmatic-initiated reason is Out of Range: the property is outside our currently supported service areas. If your team still desires services for the property, then they may need to find another vendor to temporarily assist until PlanOmatic is able to expand into the new service area.

"order_status": "canceled",
"event": "order.canceled",
"order_cancelation_reason": "Client Requested Cancelation",
"order_cancelation_notes": "Property re-rented before the shoot.",

A cancelation you request through the API comes back with the display name of the reason you sent (Duplicate Order or Client Requested Cancelation) and your cancelation_notes.

Attributes Details
AttributeDescription
order_cancelation_reasonCategory of the cancelation. null unless the order is canceled.
order_cancelation_notesAdditional notes: yours for an API or portal cancelation, or our team's for a PlanOmatic cancelation.

Example Webhook Payload

Below is an example of PlanOmatic's order object. This is the structure of the order data used for webhook payloads and, inside the data wrapper, for API response payloads.

{
  "order_id": 2120062,
  "external_property_id": "{property_id}",
  "external_order_id": "{external_order_id}",
  "created": "2026-10-14T10:40:23.000Z",
  "order_status": "completed",
  "event": "order.delivered",
  "billing_entity": {
    "slug": "investment_entity_1",
    "name": "Investment Entity Number 1"
  },
  "metadata": {
    "metadata_key1": "abc123",
    "metadata_key2": "wxyz987"
  },
  "property": {
    "location": {
      "address": "123 Fake St, Unit A, Denver, CO, 80205",
      "street": "123 Fake St",
      "street2": "Unit A",
      "city": "Denver",
      "state": "CO",
      "postal_code": "80205",
      "country": "US",
      "market": "Denver",
      "latitude": "39.739236",
      "longitude": "-104.990251"
    },
    "property_type": "single_family",
    "bedrooms": "3",
    "bathrooms": "2.5",
    "price": "3000",
    "square_footage": "1500"
  },
  "services": [
    {
      "slug": "photos",
      "quantity": 15,
      "name": "Photography",
      "price": "149.0"
    },
    {
      "slug": "zillow_3d_and_floor_plans",
      "quantity": 1,
      "name": "Zillow 3D",
      "price": "169.0"
    },
    {
      "slug": "ai_virtual_staging",
      "quantity": 3,
      "name": "AI Virtual Staging",
      "price": 0.0
    }
  ],
  "property_access": {
    "vacant": true,
    "method_of_access": "lockbox_code",
    "access_code": "4321",
    "lockbox_location": "Behind A/C Unit",
    "preferred_date": null,
    "onsite_contact_name": "Jane Doe",
    "onsite_contact_phone": "+1 555-555-5555"
  },
  "order_notes": "Some special instructions",
  "appointments": [
    {
      "appointment_id": 3760017,
      "start_datetime": "2026-10-16T15:00:00.000+00:00",
      "end_datetime": "2026-10-16T16:00:00.000+00:00",
      "duration_m": 60,
      "planotech_name": "Bobby",
      "cancelation_reason": null,
      "cancelation_notes": null,
      "canceled": null
    }
  ],
  "order_cancelation_reason": null,
  "order_cancelation_notes": null,
  "unable_to_complete_appt": false,
  "unable_to_complete_appt_reason": null,
  "unable_to_complete_appt_notes": null,
  "links": {
    "tour_link": "https://tours.planomatic.com/865496",
    "tour_mls_link": "https://tours.planomatic.com/mls865496",
    "zillow_3d_link": "https://www.zillow.com/view-imx/XXXXXXXXXX"
  },
  "photos": [
    {
      "sequence": 1,
      "caption": "Front View",
      "full_size_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo-1}/fullSize.jpg",
      "full_size_watermarked_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo-1}/wm/fullSize.jpg",
      "uploaded_at": "2026-10-16T16:23:11.000Z",
      "modified_at": "2026-10-17T17:54:46.000Z"
    },
    {
      "sequence": 2,
      "caption": "Floor Plan",
      "full_size_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo-2}/fullSize.jpg",
      "full_size_watermarked_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo-2}/wm/fullSize.jpg",
      "uploaded_at": "2026-10-17T17:49:37.000Z",
      "modified_at": "2026-10-17T17:54:45.000Z"
    },
    {
      "sequence": 3,
      "caption": "Living Room",
      "full_size_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo-3}/fullSize.jpg",
      "full_size_watermarked_url": "https://assets.app.planomatic.com/connect/photos/{property}/{photo-3}/wm/fullSize.jpg",
      "uploaded_at": "2026-10-16T16:22:53.000Z",
      "modified_at": "2026-10-17T17:49:43.000Z"
    }
  ],
  "legacy_order_id": 2120062
}

Field notes:

  • order_id and legacy_order_id are integers. On orders placed since 2022 they are the same number; orders before 2022 may have referenced a different id, which we call the legacy_order_id.
  • external_property_id and external_order_id are strings, exactly as you sent them.
  • property.bedrooms, bathrooms, price and square_footage come back as strings and may be "0", empty or null.
  • services[].price is the line total in US dollars: a decimal string ("149.0") for a priced line, the number 0.0 for a line with no separate charge, null when no price is configured. Prices in the payload >
  • metadata is null when none was sent with the order.
  • property_access.method_of_access comes back as the slug you sent for API orders (lockbox_code); for orders placed in the Connect portal it is the display label (Lockbox, Rently).
  • Order ids in requests (order_id, request_id, previous_order_id) are accepted as a number or as a numeric string.
  • unable_to_complete_appt_reason and unable_to_complete_appt_notes are null unless unable_to_complete_appt is true.