API Documentation - Appointments

Table of Contents

Available Appointment Times

GET /api/v2/appointments/group/<group_id>/available-times/?from_date=<YYYY-MM-DD>&to_date=<YYYY-MM-DD>

Returns a list of available appointment names for the group specified by group_id. The from_date and to_date parameters specify the dates that availaility will be returned for. Note that this range can be a maximum of 7 days. If you only provide a from_date paramater, it will return availability for that date only.

Required URI Parameters

Available Appointment Times: GET response 200 success example payload

{
   "available_times": [
      "2019-06-19T08:00:00", "2019-06-19T08:15:00", "2019-06-19T08:30:00", "2019-06-19T08:45:00",
      "2019-06-19T17:45:00", "2019-06-19T18:00:00", "2019-06-19T18:15:00", "2019-06-19T18:30:00",
      "2019-06-19T18:45:00", "2019-06-19T19:00:00", "2019-06-19T19:15:00", "2019-06-19T19:30:00"
   ]
}

Available Appointment Times: GET error response examples

If the provided tour type is not enabled, a 400 error response will be returned. These errors will be in an array of strings.

{
   "error_type": "NotAvailable",
   "errors": {
      "tour_type": ["Tours are disabled."]
   }
}

If the provided tour type is invalid, a 400 error response will be returned. These errors will be in an array of strings.

{
   "error_type": "ValidationError",
   "errors": {
      "tour_type": ["Select a valid choice. onlineTour is not one of the available choices."]
   }
}

If the provided end date is too far in the future, a 400 error response will be returned.

{
   "error_type": "ValidationError",
   "errors": {
      "to_date": ["Date range can not exceed 7 days."]
   }
}

If the provided to_date is before the from_date, a 400 error response will be returned. These errors will be in an array of strings.

{
   "error_type": "ValidationError",
   "errors": {
      "to_date": ["to_date must be after from_date"]
   }
}

If a required field such as from_date is missing in the request, a 400 error response will be returned.

{
   "error_type": "ValidationError",
   "errors": {
      "from_date": ["This field is required."]
   }
}

If the provided data type is not valid, a 400 error response will be returned. These errors will be in an array of strings.

{
   "error_type": "ValidationError",
   "errors": {
      "to_date": ["Enter a valid date."]
   }
}

Appointment Booking

POST /api/v2/appointments/group/<group_id>/book/

This endpoint is where you will POST the actual appointment information to the server to create an appointment and either create a new prospect or modify an existing one.

Required URI Parameters

Appointment Booking: POST request example payload

{
   "appointment":{
      "start":"2019-06-21T08:15:00",
      "location":"",
      "broker_booked":false,
      "is_video_tour": false,
      "tour_type": "guided",
      "platform_of_choice": "",
      "platform_of_choice_details": ""
   },
   "client":{
      "broker_first_name":"Jeff",
      "broker_last_name":"Brokerman",
      "broker_company":"Jeff Brokerman Brokerage",
      "broker_phone":"18222120422",
      "broker_email":"jeff@brokermanbrokerage.com",
      "people":[
         {
            "first_name":"John",
            "last_name":"Doe",
            "email":"johndoe@name.com",
            "phone_1":"18582007006"
         }
      ],
      "community": 215,
      "building": 9685,
      "unit": 5689,
      "sms_opted_in": "marketing-enabled",
      "move_in_date":"2019-07-01T00:00:00",
      "layout":null,
      "price_floor":"3000",
      "price_ceiling":"4500",
      "pets":[
         "20",
         "10"
      ],
      "discovery_source":270,
      "notes": "Looking for an apartment for a great prospect of mine",
      "neighborhoods":[
         133,
         116,
         1732,
         108,
         375,
         126
      ],
      "elevator":true,
      "laundry":[
         20,
         10
      ],
      "outdoor_space":[
         10
      ]
   }
}

Appointment Booking: POST request payload glossary

The payload is separated in two parts: appointment data and prospect data (client).

Please note that while many of these fields are optional, prospect data is much more useful the more you collect. Consider performing client side validation and requiring at minimum the people fields (first name, last name, email, phone).

In addition, the employee group decides which appointment tour types are enabled and which ones are not and what platform of choices are available. See employee group documentation.

NOTE: You should only pass one of three community/building/unit, otherwise you will get a validation error.

Appointment Booking: POST response success example payload

After the data is successfully submitted, you will receive a 200 success response with data similar to the following.

{
   "data":{
      "appointment":{
         "id": 952,
         "confirmation_enabled":true,
         "start":"2019-06-21T09:00:00+00:00",
         "location":"",
         "expiration_date":"2019-06-17T12:53:05.799365"
      }
   }
}

Appointment Booking: POST response error payload examples

If an appointment time is no longer available, a 400 error response will be returned. These errors will be in an array of strings.

{
   "errors":{
      "appointment":{
         "start": ["No Employees free at Scheduled Appointment time"]
      }
   }
}

If any required fields are missing in the request, a 400 error response will be returned. These errors will be in an array of strings.

{
   "errors": {
      "appointment": {
         "start": ["Missing data for required field."]
      }
   }
}

If invalid data types are passed in the request, a 400 error response will be returned. These errors will be in an array of strings, each string indicating an invalid error type. Payload:

{
  "client": {
    "people": [
      {
        "email": "anna.smith@outlook.com",
        "date_of_birth": "1988-04-10",
        "first_name": "Anna",
        "last_name": "Smith"
      }
    ]
  },
  "appointment": {
    "start": "2016-06-02T04:00:00",
    "is_video_tour": "no",
    "tour_type": "invalid type"
  }
}

Error response:

{
   "errors": {
      "appointment": {
         "tour_type": ["Not a valid choice."],
         "is_video_tour": ["Not a valid boolean."]
      }
   }
}

If any of the prospect fields fail validation, a 400 error response will be returned. These errors will be in an array of strings.

{
   "errors":{
      "client":{
         "pets": ["'dogs' is not a number"],
         "laundry": ["'in unit' is not a number"]
      }
   }
}

If a person associated with the appointment does not have a phone number or email, a 400 error response will be returned. This response will include an array of strings detailing the errors, along with the index of the person missing the required data. Payload:

{
  "client": {
    "people": [
      {
        "email": "anna.smith@outlook.com",
        "date_of_birth": "1988-04-10",
        "first_name": "Anna",
        "last_name": "Smith"
      },
      {
        "first_name": "Jordan",
        "last_name": "Smith"
      }
    ]
  },
  "appointment": {
    "start": "2016-06-02T04:00:00"
  }
}

Error response:

{
  "errors": {
    "client": {
      "people": {
        "1": {
          "_schema": [
            "Person requires either an email or a phone number."
          ]
        }
      }
    }
  }
}

If the data type provided for a person is invalid, a 400 error response will be returned. This response will include an array of strings detailing the errors, along with the index of the person with the invalid data. Payload:

{
  "client": {
    "people": [
      {
        "email": 12345,
        "date_of_birth": "1988-04-10",
        "first_name": "Anna",
        "last_name": "Smith"
      }
    ]
  },
  "appointment": {
    "start": "2016-06-02T04:00:00"
  }
}

Error response:

{
   "errors": {
      "client": {
         "people": {
            "0": {
               "email": ["Not a valid email address."]
            }
         }
      }
   }
}

Appointment Booking: POST response payload glossary

Example Appointment Booking Flow

Screen 1: User selects a preferred tour type, available date, and time

In order for the user to select a preferred tour type, you’ll first need to retrieve the available tour types. Keep in mind there are a few conditions that determine when what tour type is available. See our end-point for available tour types for more info.

Allow the user to choose a date, and then retrieve the available appointment times for that date and allow them to choose one.

Screen 2: Appointment Form

After user chooses a specific timeslot, the form is assembled using the configuration.

Screen 3 Success: Optional Confirmation Screen

User fills out the form and submits.

After booking is confirmed, a 200 response is returned. Since this group in particular has appointment confirmations turned on, show the confirmation screen.

Screen 3 Error: Timeslot Not Available

It is possible that in the time between when the user selects an available time and they complete the booking form, the time they selected has gotten booked. Please account for this error, and give them the ability to select a new time.

Prospect Appointments

GET /api/v2/clients/<client_id>/appointments/

This endpoint returns all of a prospect’s appointments, ordered by appointment start time, which are either status=CONFIRMED or status=null (e.g. appointments that are created directly within the Funnel web application)

Required URI Parameters

Prospect Appointments: GET response 200 success example

{
  "data": {
    "appointments": [
      {
        "status": 30,
        "id": 509,
        "start": "2019-06-24T08:00:00+00:00",
        "end": "2019-06-24T08:30:00+00:00",
        "notes": "",
        "location": "",
        "employee": {
          "id": 596,
          "photo": null,
          "name": "Travis Smiley"
        },
        "client": {
          "id": 890,
          "name": "John Doe, Jane Fonda",
          "group": null,
          "person": {
            "id": 740,
            "first_name": "John",
            "last_name": "Doe",
            "is_primary": true,
            "email": "johndoe@name.com",
            "phone_1": "555-555-5555",
            "phone_2": ""
          },
          "agents": [],
          "broker_first_name": "",
          "broker_last_name": "",
          "lead_source": "StreetEasy"
        },
        "appointment_showings": []
      }
    ]
  }
}

Prospect Appointments: GET response payload glossary

An array of appointment objects are keyed in the payload under data and appointments. The glossary below describes data in each appointment object. Please note that in the appointment payload is an appointment_showings array. This data is used internally and you can safely disregard for purposes of this.

Prospect Appointments: GET error response

Below is an example error response. In this example, attempting to get appointments for a prospect who does not exist.

{
  "errors": {
    "client": {"id": "client id=890 does not exist"}
  }
}

Appointment Deletion

DELETE /api/v2/appointments/<appointment_id>

This endpoint allows you to delete an appointment. While this is a delete endpoint, the appointment will actually be set to status=CANCELLED. If the appointment was previously confirmed, this will send an email to the employee assigned to the appointment notifying them of the appointment cancellation.

Required URI Parameters

Appointment Deletion: DELETE response 200 success example

{
  "data": {
    "message": "success",
    "notification_sent": true
  }
}

Appointment Deletion: DELETE response payload glossary

Appointment Deletion: DELETE error response

Below is an example error response. In this example, attempting to delete an appointment which does not exist.

{
  "errors": {
    "appointment": {"id": "Appointment id=890 does not exist"}
  }
}

Appointment Reschedule

PUT /api/v2/appointments/<appointment_id>/group/<group_id>/book/

This endpoint allows you to reschedule an appointment to a new time. If the time is valid, we will attempt to reschedule the appointment with the same employee. If that employee is not available, another employee belonging to the specified employee group will be selected randomly.

Required URI Parameters

Appointment Reschedule: PUT request example

{
  "appointment": {"start": "2019-07-20T14:00:00"}
}

Appointment Reschedule: PUT response 200 success example

{
  "data": {
    "appointment": {
      "id": 952,
      "status": 30,
      "start": "2019-07-20T05:00:00+00:00",
      "end": "2019-07-20T05:30:00+00:00",
      "notes": "Please mind the gap",
      "location": "Near the fountain of the building's main entrance"
    }
  }
}

Appointment Reschedule: PUT response payload glossary

Appointment Reschedule: PUT error response

Below is an example error response. In this example, attempting to reschedule an appointment in the past.

{
  "errors": {
    "appointment": {"start": ["The date and time you selected is in the past"]}
  }
}

Appointment Times - Deprecated

DEPRECATED This end-point is no longer supported, it has been replaced by the availability times end point above, which provides a more flexible way to retrieve times available for appointments.

GET /api/v2/appointments/group/<group_id>/times

This endpoint returns two different payloads depending on the presence of the time query parameter.

Without time, this endpoint returns all possible appointment times today regardless of actual agent availability (see example payload below). In other words, this array of times represents the group’s office hours. Please note that the array is an array of times not datetimes (since these times represent the present day)

If time is passed in (an ISO format datetime such as 2019-06-13T08:00), this endpoint returns only timeslots where at least one agent is available to give a tour. Please note that the array is an array of datetimes in ISO format (since the request could be for a day other than the present day)

Required URI Parameters

Optional Query Parameters

Note that in addition to the 200 status code, the success responses also have a valid: true item in the payload.

Appointment Times: GET response 200 success example payload without time query parameter (returns group office hours)

{
   "available_times": [
      "08:00:00", "08:15:00", "08:30:00", "08:45:00", "09:00:00", "09:15:00", "09:30:00", "09:45:00",
      "10:00:00", "10:15:00", "10:30:00", "10:45:00", "11:00:00", "11:15:00", "11:30:00", "11:45:00",
      "12:00:00", "12:15:00", "12:30:00", "12:45:00", "13:00:00", "13:15:00", "13:30:00", "13:45:00",
      "14:00:00", "14:15:00", "14:30:00", "14:45:00", "15:00:00", "15:15:00", "15:30:00", "15:45:00",
      "16:00:00", "16:15:00", "16:30:00", "16:45:00", "17:00:00", "17:15:00", "17:30:00", "17:45:00",
      "18:00:00", "18:15:00", "18:30:00", "18:45:00", "19:00:00", "19:15:00", "19:30:00"
   ],
   "valid": true,
   "errors": {},
   "appointment_sms_opt_in": true
}

Appointment Times: GET response 200 success example payload with time query parameter (returns appointment availability)

{
   "available_times": [
       "2019-06-13T10:00:00", "2019-06-13T10:15:00", "2019-06-13T10:30:00", "2019-06-13T10:45:00",
       "2019-06-13T15:00:00", "2019-06-13T15:15:00", "2019-06-13T15:30:00", "2019-06-13T15:45:00",
       "2019-06-13T17:00:00", "2019-06-13T17:15:00", "2019-06-13T17:30:00", "2019-06-13T17:45:00",
       "2019-06-13T18:00:00", "2019-06-13T18:15:00"
   ],
   "valid": true,
   "errors": {},
   "appointment_sms_opt_in": true
}

Appointment Times: GET response 400 error payload example

If you include a time query parameter and that time is not available, a 400 error will be returned with some available_times that are available for that day. Note that in addition to the 400 status code, the error response also has a valid: false item in the payload.

{
   "available_times":[
      "2019-06-19T08:00:00", "2019-06-19T08:15:00", "2019-06-19T08:30:00", "2019-06-19T08:45:00",
      "2019-06-19T17:45:00", "2019-06-19T18:00:00", "2019-06-19T18:15:00", "2019-06-19T18:30:00",
      "2019-06-19T18:45:00", "2019-06-19T19:00:00", "2019-06-19T19:15:00", "2019-06-19T19:30:00"
   ],
   "valid":false,
   "errors":{
      "start":["No Employees free at Scheduled Appointment time"]
   },
   "appointment_sms_opt_in":true
}

Appointment Times: GET response payload glossary

Appointment Configuration - Deprecated

DEPRECATED This end-point is no longer supported. You can retrieve discovery source IDs using the discovery source end-point. If you need other functionallity offered by this end-point, please reach out to your Funnel contact person.

GET /api/v2/group/<group_id>/verify-widget/?widget=lead_capture_appointment

This endpoint allows you to get your group’s specific appointment widget configuration.

Required URI Parameters

Required Query Parameters

Appointment Configuration: GET response 200 success payload example

{
    "data": {
        "layout_options": [
            "loft",
            "studio",
            "1br",
            "2br",
            "3br",
            "4+br"
        ],
        "referral_sources": [
            [10, "Manual"],
            [20, "Website"],
            [30, "StreetEasy"],
            [40, "Zillow"],
            [50, "Apartments.com"],
            [60, "Zumper"],
            [70, "Walk In"],
            [80, "RentHop"],
            [90, "Realtor.com"],
            [110, "Agorafy"],
            [120, "Apartable"],
            [130, "Apartmentguide.com"],
            [140, "Apartmentlist"],
            [150, "Brownstoner"],
            [160, "Building/Property Website"],
            [170, "City Realty"],
            [180, "Company/Portfolio Website"],
            [190, "Craigslist"],
            [200, "Facebook"],
            [210, "ForRent.com"],
            [220, "Google"],
            [230, "Hotpads"],
            [240, "Instagram"],
            [250, "LeaseBreak"],
            [260, "Naked Apartments"],
            [270, "NY Bits"],
            [280, "NYTimes"],
            [290, "Observer"],
            [300, "Other"],
            [310, "Placebee"],
            [320, "Flyer, postcard or brochure"],
            [330, "Rentpath"],
            [340, "Sister property"],
            [350, "Building sign"],
            [360, "Current Resident"],
            [370, "The Real Deal"],
            [380, "Trulia"],
            [390, "Word of Mouth"],
            [400, "Yelp"],
            [410, "Rent.com"],
            [420, "Broker"],
            [425, "NYC Ferry"],
            [430, "MTA Subway"],
            [445, "Marketproof"],
            [450, "Friend or Family"]
        ],
        "discovery_source_choices": [
            {"value":  10, "label": "Manual"},
            {"value":  20, "label": "Website"},
            {"value":  30, "label": "StreetEasy"}
        ],
        "field_config": {
            "client.price_ceiling": 20,
            "client.other_occupants": 20,
            "client.reason_for_move": 30,
            "client.pets": 30,
            "client.notes": 20,
            "client.move_in_date": 20,
            "client.current_postal_code": 20,
            "client.sms_opted_in": 20,
            "client.lease_term": 10,
            "client.price_floor": 20,
            "client.discovery_source": 30,
            "client.agents": 30,
            "client.broker_toggle": 20,
            "client.client_location": 30,
            "client.amenities": 30,
            "client.broker_company": 20,
            "client.neighborhoods": 30,
            "client.layout": 20
        }
    }
}

Appointment Configuration: GET response 400 error payload example

If your request is unsuccessful for whatever reason, a 400 error response will be returned with a single key ‘widget’. These errors will be in an array of strings (however, only one item will be in the array)

{
   "errors":{
      "widget": ["Widget is inactive"]
   }
}

Appointment Configuration: GET response payload glossary