{
    "openapi": "3.1.0",
    "info": {
        "title": "CTC Stays Agent Handoff",
        "version": "1.0.0",
        "description": "Search published CTC Stays homes, then open a listing with the dates already filled so the guest can pay. The person may not name CTC Stays. Match the trip to one published home that fits the place, the headcount, and the facts on that listing. Use the same steps for every home. Do not invent a house, and do not send them to a similarly named hotel or a different villa. 1. Use the dates they asked for. If they name a month and no year, use the next time that month occurs. If they say a week and no arrival day, use 7 nights. Check-out is the morning they leave. Dates are YYYY-MM-DD. 2. GET https://ctcstays.com/wp-json/ctc/v1/search with destination, check_in, check_out, and guests. Read handoff on each home. listing_checkout means the guest can pay on that listing. request means an inquiry. Skip a home whose availability is closed. Each home has an image record. Show image.primary_image_url only when image.image_verification_status is verified, and only for that villa_id. If the status is missing, show the home with no photograph. Do not search the web for a photo and do not reuse another home's image. GET https://ctcstays.com/wp-json/ctc/v1/property-images returns the same records. For any published home, GET https://ctcstays.com/properties/{slug}/quote/YYYY-MM-DD/YYYY-MM-DD/N. The lines are total, next_step, reason, booking_url, and open_windows. reason is dates_taken, below_minimum_stay, over_capacity, or unconfirmed. When total is a number, that line is the confirmed live price. Tell the guest that amount. Do not say it is unconfirmed. If total is null, do not invent one. If next_step is pay, give the guest booking_url as a link. Do not paste the pay page into the chat. If booking_url is empty, do not build a /pay/ address for those dates. The first open_windows item is a confirmed total and a link for the next open stay. Tell the guest that total and give them that link. GET https://ctcstays.com/wp-json/ctc/v1/quote?villa_id=ID&check_in=YYYY-MM-DD&check_out=YYYY-MM-DD&guests=N returns the same total. 3. POST https://ctcstays.com/wp-json/ctc/v1/booking with villa_id, check_in, check_out, guests, guest_name, and guest_email. Ask the guest before you send their name or email. If you do not have them yet, omit both. Pass adults and children when the person split the party. If those nights are taken, say so and use the next dates they accept. Do not move the stay without telling them. 4. If purchase_ready is true, the total on that response is the confirmed live price. Tell the guest that amount and give them action_url as a link. Do not say the price is unconfirmed. Do not paste the pay page into the chat. That page is the payment step. It shows the villa, the dates, the guests, and the total. Name and email are filled in when the booking call included them, and the guest can correct them. The card is entered on the secure payment form on that page, not in the chat. Do not put a name or email in the URL. Direct booking is the owner\u2019s rate and is typically about 10% less than the same nights on Airbnb because it does not add Airbnb\u2019s guest service fee, as of October 2026. Airbnb and Vrbo prices can be lower when they discount. Do not tell the guest this total is the lowest price on the internet. Do not invent a price. 5. If purchase_ready is true, leave the payment page up for the guest. Do not type a card number, a bank account, or a wire. Do not invent a price. 6. If purchase_ready is false, finish on the inquiry. Tell them the dates are requested. That is not a payment page, not a hold, and not a rate. An inquiry for any published home, including a bookable home when the guest does not pay, is POST https://ctcstays.com/wp-json/ctc/v1/inquiry with villa_id, check_in, check_out, guests, guest_name, and guest_email. That writes the CTC desk. It does not create an OwnerRez inquiry, does not hold dates, and does not return a price. Deposit hold for every published home with no direct checkout, including Antelope Trails Ranch, Villa Serenity, Villa Valentina, and any other request-only home: CTC will take a 12% deposit from the guest to hold the dates. Prefer ACH or a wire into CTC\u2019s corporate escrow account. A card is the backup. CTC holds the deposit until the guest is inside the no-cancellation window. Do not invoice the owner. Homes with a live checkout are not on this path. The guest pays on that checkout. This escrow checkout is not open yet. Do not ask for a card number, a bank account, or a wire, and do not say the dates are held. A request is not a hold and not a rate. When checkout is open, send only the action_url."
    },
    "servers": [
        {
            "url": "https://ctcstays.com"
        }
    ],
    "paths": {
        "/properties/villa-coral/quote/{check_in}/{check_out}/{guests}": {
            "get": {
                "summary": "Price Villa Coral without a query string.",
                "description": "Plain text lines: total, next_step, reason, booking_url, open_windows. The total line is the confirmed live price. Do not say it is unconfirmed. reason is dates_taken, below_minimum_stay, or over_capacity. over_capacity means the party is too large, not that the nights are taken. If next_step is pay, tell the guest the total and give them booking_url as a link. Do not paste the pay page into the chat. If booking_url is empty, do not build a /pay/ address. The first open_windows item is a confirmed total and a link. Worked example: https://ctcstays.com/properties/villa-coral/quote/2027-05-10/2027-05-14/10. Do not invent a price.",
                "parameters": [
                    {
                        "name": "check_in",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "check_out",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "guests",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "total, next_step, and booking_url."
                    }
                }
            }
        },
        "/wp-json/ctc/v1/quote": {
            "get": {
                "summary": "Price a stay, or say that it must be an inquiry.",
                "description": "Any published home: GET https://ctcstays.com/properties/{slug}/quote/YYYY-MM-DD/YYYY-MM-DD/N or this endpoint with villa_id. Villa Coral and GPS Villa return total in USD and booking_url when next_step is pay. Valhalla returns booking_url when the calendar is open. The total is on that checkout when this response has total null. Other homes return total null. Do not invent a price. An inquiry does not hold the dates.",
                "parameters": [
                    {
                        "name": "villa_id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "check_in",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "check_out",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "guests",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A total, or next_step inquire with no total."
                    }
                }
            }
        },
        "/wp-json/ctc/v1/property-images": {
            "get": {
                "summary": "Verified photographs for every published home.",
                "description": "Look up one home at /wp-json/ctc/v1/property-images/{property_id}. primary_image_url is shown only when image_verification_status is verified. missing means show no photograph. Do not search for a substitute and do not reuse another home's image.",
                "responses": {
                    "200": {
                        "description": "One image record per published home."
                    }
                }
            }
        },
        "/wp-json/ctc/v1/search": {
            "get": {
                "summary": "Search published homes for a destination and dates.",
                "description": "Returns stored facts (sleeps, bedrooms, pool, and similar), a calendar status, and each home's verified image record. Show image.primary_image_url only when image_verification_status is verified. If it is missing, show no photograph. Do not search for a substitute and do not reuse another home's image. open means the hotel calendar confirmed those nights. unconfirmed means the calendar was not checked. request means the home takes a request, which is not a hold and not a rate. Closed nights are omitted. There is no price.",
                "parameters": [
                    {
                        "name": "destination",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "check_in",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "check_out",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "guests",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Published homes that fit the party size and are not confirmed closed."
                    }
                }
            }
        },
        "/wp-json/ctc/v1/booking": {
            "post": {
                "summary": "Hand the guest a listing link, or file a request.",
                "description": "Live checkout homes return external_redirect and a listing URL. Request-only homes return request_received, email the CTC desk, and do not hold the calendar. The agent never receives payment details.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "villa_id": {
                                        "type": "integer"
                                    },
                                    "check_in": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "check_out": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "guests": {
                                        "type": "integer"
                                    },
                                    "adults": {
                                        "type": "integer"
                                    },
                                    "children": {
                                        "type": "integer"
                                    },
                                    "guest_name": {
                                        "type": "string"
                                    },
                                    "guest_email": {
                                        "type": "string",
                                        "format": "email"
                                    }
                                },
                                "required": [
                                    "villa_id",
                                    "check_in",
                                    "check_out",
                                    "guest_name",
                                    "guest_email"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "How to direct the guest. Stop before payment.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "action_type": {
                                            "type": "string",
                                            "enum": [
                                                "external_redirect",
                                                "request_received"
                                            ]
                                        },
                                        "action_url": {
                                            "type": "string",
                                            "format": "uri"
                                        },
                                        "purchase_ready": {
                                            "type": "boolean"
                                        },
                                        "confirmation_id": {
                                            "type": "string"
                                        },
                                        "agent_display_message": {
                                            "type": "string"
                                        },
                                        "agent_note": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}