/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.
group_id
from_date
to_date
parameter is provided, availability for the date provided will be returned.to_date
from_date
and to_date
can span a maximum of 7 days.tour_type
guided
or self-guided
– specifies which tour type to get availability. Note for virutal/video tours, use guided
. If not specified, defaults to returning guided tour availability.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"
]
}
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."]
}
}
/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.
group_id
{
"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
]
}
}
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.
appointment
start
location
broker_booked
broker_booked
to true
will validate make broker_email
a required field in the prospect data.tour_type
is_video_tour
is_video_tour
to true
will validate make platform_of_choice
and platform_of_choice_details
required fields in the appointment data.platform_of_choice
is_video_tour
is set to true
. This can be any string. It tells an agent what platform should be used during a video tour (e.g. “Google Hangouts” or “Apple Facetime”).platform_of_choice_details
is_video_tour
is set to true
. This can be any string. It tells an agent how a prospect can be reached during a video tour (e.g. “johndo@gmail.com” or “johndo@icloud.com”).client
people
first_name
last_name
phone_1
email
sms_opted_in
sms_opted_in
should NOT be sent. The available choices are:
'marketing-enabled'
: This prospect has opted into receiving all communication including automated marketing messages.'marketing-disabled'
: This prospect has opted into receiving communications, but not opted into receiving automated marketing messages. This is the default setting.'all-sms-disabled'
: This will disable the prospect from receiving any SMS communications. This setting can be updated via the Funnel app. Use this if you want to temporarily disable SMS communication with the prospect.'client-opted-out'
: The prospect has explicitly opted out of communication. This setting cannot be updated unless the prospect submits their information again. Use this if you want to permamently disable all SMS communication with the prospect.move_in_date
Layout
loft
studio
1br
2br
3br
4+br
price_floor
price_ceiling
pets
10
- Cats20
- Small Dogs30
- Large Dogsdiscovery_source
discovery_source_choices
in the Appointment Configuration payload abovelead_source
neighborhoods
notes
elevator
laundry
10
- Laundry In Unit20
- Laundry In Building30
- Laundry In Unit Connectionparking
10
- Has Parkingoutdoor_space
10
- Private Outdoor Space20
- Public Outdoor Spacebroker_first_name
broker_last_name
broker_company
broker_phone
broker_email
broker_booked
is set to true
, a valid email is required.community
building
unit
NOTE: You should only pass one of three community
/building
/unit
, otherwise you will get a validation error.
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"
}
}
}
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
confirmation_enabled
confirmation_enabled
is false
. If they must confirm, the value is true
.start
location
expiration_date
expiration_date
is exactly 1 hour after the booking has occurred. Represents how long the prospect has to confirm an appointment. expiration_date
is irrelevant if confirmation_enabled
is false
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.
/api/v2/group/123
- Available tour typesAllow the user to choose a date, and then retrieve the available appointment times for that date and allow them to choose one.
/api/v2/appointments/group/123/available-times/?from=2019-06-18
- Available Appointment TimesAfter user chooses a specific timeslot, the form is assembled using the configuration.
User fills out the form and submits.
/api/v2/appointments/group/123/book/
- Appointment BookingAfter booking is confirmed, a 200
response is returned. Since this group in particular has appointment confirmations turned on, show the confirmation screen.
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.
/api/v2/appointments/group/123/book/
- Appointment Booking/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)
client_id
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": []
}
]
}
}
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.
status
null
- Appointment was created by a user within the app and has not been toggled to any other status10
- Tentative (ie, appointment is scheduled but requires confirmation (if appointment confirmation is required by group))20
- Not Confirmed (ie, appointment was scheduled but not confirmed within the hour (if appointment confirmation is required by group))30
- Confirmed (ie, appointment is scheduled and either confirmed by prospect or confirmation is not required by group)40
- Cancelled50
- Completed60
- No Showid
start
end
notes
location
employee
id
photo
name
client
id
name
person
id
first_name
last_name
is_primary
email
phone_1
phone_2
agents
broker_first_name
broker_last_name
lead_source
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"}
}
}
/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.
appointment_id
200
success example{
"data": {
"message": "success",
"notification_sent": true
}
}
message
notification_sent
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"}
}
}
/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.
appointment_id
group_id
{
"appointment": {"start": "2019-07-20T14:00:00"}
}
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
status
null
- Appointment was created by a user within the app and has not been toggled to any other status10
- Tentative (ie, appointment is scheduled but requires confirmation (if appointment confirmation is required by group))20
- Not Confirmed (ie, appointment was scheduled but not confirmed within the hour (if appointment confirmation is required by group))30
- Confirmed (ie, appointment is scheduled and either confirmed by prospect or confirmation is not required by group)40
- Cancelled50
- Completed60
- No Showstart
end
notes
location
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"]}
}
}
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.
/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)
group_id
time
time
is included, endpoint returns employee group’s office hoursNote that in addition to the 200
status code, the success responses also have a valid: true
item in the payload.
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
}
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
}
400
error payload exampleIf 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
}
available_times
time
query param is added to the request) or times in 24-hour format.valid
errors
start
since that’s the bulk of the validation occurring in this request. See above example.appointment_sms_opt_in
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.
/api/v2/group/<group_id>/verify-widget/?widget=lead_capture_appointment
This endpoint allows you to get your group’s specific appointment widget configuration.
group_id
widget
lead_capture_appointment
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
}
}
}
400
error payload exampleIf 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"]
}
}
layout_options
loft
studio
1br
2br
3br
4+br
referral_sources
discovery_source_choices
insteaddiscovery_source_choices
. Please note
that the appointment booking endpoint expects the integer value to be submitted; the string is
merely for readability purposes.discovery_source_choices
id
value to be submitted; the
name is merely for readability purposes.field_config
client.price_ceiling
/client.current_postal_code
) represents a field that is validated during appointment booking. The value for each field key represents whether or not the field is REQUIRED
(10), Optional
(20), or HIDDEN
(30).field_config
Is not relevant for developers creating their own appointment widget. It’s primary purpose is to configure the Funnel-powered appointment widget by allowing groups to control which fields to display, which fields not to display, and which fields to perform client side validation on. However, if you are building your own appointment widget, you can choose freely to display whichever fields you wish. Server side validation remains the same no matter which fields are displayed on the frontend.