{
  "openapi": "3.1.0",
  "info": {
    "title": "Realtor Flow Tool Kit API",
    "version": "1",
    "summary": "Listings, lead surveys, video articles and lead capture for any real estate website",
    "description": "Keep the website you have. Paste one line to put your listings, a lead-scoring survey or a contact form on any page, or call the API from your own code. The work runs on Realtor Flow. The full documentation is at https://api.realtorflow.ca/.",
    "contact": {
      "name": "Realtor Flow",
      "url": "https://www.realtorflow.ca",
      "email": "jarvis@realtorflow.ca"
    }
  },
  "externalDocs": {
    "description": "Documentation",
    "url": "https://api.realtorflow.ca/"
  },
  "servers": [
    {
      "url": "https://api.realtorflow.ca/v1"
    }
  ],
  "security": [
    {
      "key": []
    }
  ],
  "tags": [
    {
      "name": "Articles and translation"
    },
    {
      "name": "AI visibility and traffic"
    },
    {
      "name": "Bookings"
    },
    {
      "name": "Account"
    },
    {
      "name": "Videos"
    },
    {
      "name": "Surveys"
    },
    {
      "name": "Listings"
    },
    {
      "name": "Newsletter"
    },
    {
      "name": "Media"
    },
    {
      "name": "Leads"
    }
  ],
  "paths": {
    "/account": {
      "get": {
        "operationId": "account",
        "summary": "The account",
        "description": "Who the key belongs to, which tools are switched on and how much of the month's allowance is left. The call to make first: it says whether the key works.",
        "tags": [
          "Account"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-account"
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "account",
                  "name": "Harbour Realty",
                  "mode": "live",
                  "key": "Website server",
                  "language": "en",
                  "tools": {
                    "videos": true,
                    "surveys": true,
                    "leads": true,
                    "listings": true,
                    "bookings": true,
                    "newsletter": true,
                    "ai_visibility": true,
                    "ai_traffic": true,
                    "articles": true,
                    "translation": true,
                    "media": true
                  },
                  "usage": {
                    "resets_at": "2026-12-01T00:00:00.000Z",
                    "units": [
                      {
                        "unit": "video_article",
                        "label": "Video articles",
                        "used": 3,
                        "in_progress": 1,
                        "limit": 25,
                        "left": 21
                      },
                      {
                        "unit": "survey_draft",
                        "label": "Surveys drafted by AI",
                        "used": 2,
                        "in_progress": 0,
                        "limit": 50,
                        "left": 48
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "not_switched_on: The tool kit is not switched on for this account. Write to Realtor Flow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "usage",
        "summary": "The month's count",
        "description": "What has been counted this calendar month (UTC) and what is left.",
        "tags": [
          "Account"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-usage"
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "usage",
                  "resets_at": "2026-12-01T00:00:00.000Z",
                  "units": [
                    {
                      "unit": "video_article",
                      "label": "Video articles",
                      "used": 3,
                      "in_progress": 1,
                      "limit": 25,
                      "left": 21
                    },
                    {
                      "unit": "survey_draft",
                      "label": "Surveys drafted by AI",
                      "used": 2,
                      "in_progress": 0,
                      "limit": 50,
                      "left": 48
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/videos": {
      "post": {
        "operationId": "videoCreate",
        "summary": "Send a video",
        "description": "Send the address of a YouTube video and the words spoken in it. The answer comes back at once with the status writing; the article follows, usually in under two minutes.\n\nSending the same video again returns the same answer and is not counted twice. To have the article written again, send rewrite: true: that is counted as a new article.",
        "tags": [
          "Videos"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-videos"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "youtube_url": {
                    "type": "string",
                    "description": "The address of the video on YouTube."
                  },
                  "transcript": {
                    "type": "string",
                    "description": "The words spoken in the video: plain text, or the contents of a captions file (.srt or .vtt) as it is. At least 400 characters of speech. Not needed when the account already holds a transcript for this video."
                  },
                  "title": {
                    "type": "string",
                    "description": "The video's title. Up to 200 characters."
                  },
                  "description": {
                    "type": "string",
                    "description": "The video's description on YouTube. It is read for context."
                  },
                  "page_url": {
                    "type": "string",
                    "description": "The full address of the page the article will be on. It goes into the markup, so send it if you know it."
                  },
                  "duration": {
                    "type": "number",
                    "description": "The video's length in seconds."
                  },
                  "published_at": {
                    "type": "string",
                    "description": "When the video was published, as a date."
                  },
                  "rewrite": {
                    "type": "boolean",
                    "description": "true to have an article that already exists written again."
                  }
                },
                "required": [
                  "youtube_url"
                ]
              },
              "example": {
                "youtube_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
                "title": "Harbour district walk-through",
                "page_url": "https://www.example.com/videos/before-you-make-an-offer",
                "transcript": "Welcome to the harbour district. Today we walk through what to look at before you make an offer on a home here. First, look at the roof and ask how old it is. Second, read the condo minutes for the last two years. Third, ask what the seller is leaving behind. The best time to visit is the early morning, when the street is quiet. Thank you for watching, and write to us with your questions about buying in the harbour district."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "5d0c1c0e-8f0a-4a57-9f0e-2b7f6a1d3c11",
                  "object": "video",
                  "status": "writing",
                  "youtube_id": "dQw4w9WgXcQ",
                  "youtube_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
                  "title": "Harbour district walk-through",
                  "page_url": "https://www.example.com/videos/before-you-make-an-offer",
                  "headline": null,
                  "summary": null,
                  "created_at": "2026-11-12T15:04:05.000Z",
                  "updated_at": "2026-11-12T15:04:05.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_youtube_url: youtube_url is missing or is not the address of a YouTube video. no_transcript: No transcript was sent for a video that has none yet. bad_page_url: page_url is not a full address starting with https://.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "413": {
            "description": "transcript_too_long: The transcript is far beyond two hours of speech.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "422": {
            "description": "transcript_too_short: The transcript holds under 400 characters of speech, too little to write from.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "limit_reached: The month's allowance for this kind of work is used up. It starts again on the first of the month (UTC). slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "503": {
            "description": "ai_off: AI writing is not available right now. Try again later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "videoList",
        "summary": "List videos",
        "description": "The account's videos, newest first, in the short form (no article). A test key always gets an empty list.",
        "tags": [
          "Videos"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-videos"
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "How many to a page: 1 to 100. The default is 20."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Which page, from 1."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "5d0c1c0e-8f0a-4a57-9f0e-2b7f6a1d3c11",
                      "object": "video",
                      "status": "ready",
                      "youtube_id": "dQw4w9WgXcQ",
                      "youtube_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
                      "title": "Harbour district walk-through",
                      "page_url": "https://www.example.com/videos/before-you-make-an-offer",
                      "headline": "What to Check Before You Make an Offer in the Harbour District",
                      "summary": "Three things to look at before you make an offer on a home in the harbour district: the roof, the condo minutes and what the seller leaves behind.",
                      "created_at": "2026-11-12T15:04:05.000Z",
                      "updated_at": "2026-11-12T15:04:05.000Z"
                    }
                  ],
                  "page": 1,
                  "has_more": false
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/videos/{id}": {
      "get": {
        "operationId": "videoGet",
        "summary": "Get a video",
        "description": "Ask until status is ready. Every few seconds is enough. Until then the answer has the short form shown under Send a video; the article and its markup are added when it is ready. A video that is failed carries a note that says why; send it again to retry, and nothing was counted.",
        "tags": [
          "Videos"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-video"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          },
          {
            "name": "transcript",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Send 0 to leave the transcript out of html. It stays in transcript and in the markup."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "5d0c1c0e-8f0a-4a57-9f0e-2b7f6a1d3c11",
                  "object": "video",
                  "status": "ready",
                  "youtube_id": "dQw4w9WgXcQ",
                  "youtube_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
                  "title": "Harbour district walk-through",
                  "page_url": "https://www.example.com/videos/before-you-make-an-offer",
                  "headline": "What to Check Before You Make an Offer in the Harbour District",
                  "summary": "Three things to look at before you make an offer on a home in the harbour district: the roof, the condo minutes and what the seller leaves behind.",
                  "created_at": "2026-11-12T15:04:05.000Z",
                  "updated_at": "2026-11-12T15:05:12.000Z",
                  "search": {
                    "title": "Before You Make an Offer in the Harbour District",
                    "description": "The roof, the condo minutes and what stays with the home: what to check before you make an offer in the harbour district."
                  },
                  "topic": null,
                  "tags": [
                    "harbour district",
                    "making an offer",
                    "buying a home"
                  ],
                  "article": {
                    "intro": "Before you make an offer on a home in the harbour district, three checks are worth the time.",
                    "points": [
                      "Ask how old the roof is.",
                      "Read the condo minutes for the last two years.",
                      "Ask what the seller is leaving behind."
                    ],
                    "sections": [
                      {
                        "heading": "What should you look at first?",
                        "text": "Start with the roof and ask how old it is. ..."
                      }
                    ],
                    "quotes": [
                      {
                        "text": "The best time to visit is the early morning, when the street is quiet.",
                        "who": ""
                      }
                    ],
                    "faq": [
                      {
                        "question": "When is the best time to visit?",
                        "answer": "The early morning, when the street is quiet."
                      }
                    ],
                    "closing": "Write to us with your questions about buying in the harbour district."
                  },
                  "check": {
                    "numbers": [],
                    "quotes": []
                  },
                  "html": "<div class=\"rf-video-article\">\n<p class=\"rf-summary\">Three things to look at ...</p>\n...\n</div>",
                  "embed_html": "<div class=\"rf-video\" style=\"...\"><iframe src=\"https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ\" ...></iframe></div>",
                  "json_ld": [
                    {
                      "@context": "https://schema.org",
                      "@type": "VideoObject",
                      "name": "What to Check Before You Make an Offer in the Harbour District",
                      "...": "..."
                    },
                    {
                      "@context": "https://schema.org",
                      "@type": "FAQPage",
                      "...": "..."
                    }
                  ],
                  "transcript": [
                    {
                      "t": 0,
                      "h": "",
                      "text": "Welcome to the harbour district. Today we walk through ..."
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "videoDelete",
        "summary": "Delete a video",
        "description": "Removes a video that was added through the tool kit, with its article. A video the account added in its own dashboard is removed there.",
        "tags": [
          "Videos"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#delete-video"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "5d0c1c0e-8f0a-4a57-9f0e-2b7f6a1d3c11",
                  "object": "video",
                  "deleted": true
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "not_yours_to_delete: The video was added in the dashboard, not through the tool kit. Remove it there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/surveys/draft": {
      "post": {
        "operationId": "surveyDraft",
        "summary": "Draft a survey from a description",
        "description": "Say who the survey is for and what you want to find out. A complete survey comes back: questions, answers, points that add up to 100 and the three result messages. The call answers when the draft is written, which can take up to a minute.\n\nNothing is saved. Look the draft over, then send its survey to Create a survey. To change a draft, send it back as survey with a new prompt (\"make it shorter\", \"add a question about schools\"). To carry a longer conversation, send messages instead of prompt: a list of { \"role\": \"user\" | \"assistant\", \"text\": \"...\" } that ends with one from the user.\n\nEach draft that comes back is counted as one survey draft. A draft that fails is not counted.",
        "tags": [
          "Surveys"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-surveys-draft"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "What you want, in your own words. Up to 2,000 characters. Left out only when messages is sent."
                  },
                  "survey": {
                    "type": "object",
                    "description": "A draft to change, as it came back from this call."
                  },
                  "messages": {
                    "type": "array",
                    "description": "The whole conversation so far, instead of prompt. Up to 24 messages."
                  }
                }
              },
              "example": {
                "prompt": "A survey for first-time buyers in Halifax. I want to know how soon they plan to buy and where they are with financing."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "survey_draft",
                  "reply": "Here is a three-question survey for first-time buyers in Halifax. Timing and financing carry most of the points.",
                  "survey": {
                    "title": "Are you ready to buy in Halifax?",
                    "intro": "Three quick questions about your timing and your financing.",
                    "questions": [
                      {
                        "text": "When would you like to move?",
                        "type": "single",
                        "options": [
                          {
                            "label": "Within 3 months",
                            "points": 35
                          },
                          {
                            "label": "In 3 to 6 months",
                            "points": 25
                          },
                          {
                            "label": "In 6 to 12 months",
                            "points": 10
                          },
                          {
                            "label": "Just looking for now",
                            "points": 0
                          }
                        ]
                      },
                      {
                        "...": "two more questions"
                      }
                    ],
                    "results": {
                      "hot": {
                        "heading": "You are ready to buy",
                        "text": "Your timing and financing are in place. I will be in touch shortly to line up viewings."
                      },
                      "warm": {
                        "heading": "You are getting close",
                        "text": "A step or two is still open, usually financing or timing. I will follow up with what to do next."
                      },
                      "nurture": {
                        "heading": "You are at the start",
                        "text": "There is no rush. Reach out whenever you want to talk it through."
                      }
                    }
                  },
                  "problem": ""
                }
              }
            }
          },
          "400": {
            "description": "no_prompt: Nothing to draft from. Send a prompt, or messages that end with one from the user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "limit_reached: The month's allowance for this kind of work is used up. It starts again on the first of the month (UTC). slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "502": {
            "description": "draft_failed: The draft did not come back complete. Nothing was counted. Try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "503": {
            "description": "try_later: The account has reached the day's ceiling for AI work. It starts again the next day. ai_off: AI writing is not available right now. Try again later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/surveys": {
      "post": {
        "operationId": "surveyCreate",
        "summary": "Create a survey",
        "description": "Saves a survey, written by you or as a draft handed back. It is a draft until its status is live. An account holds up to 50 surveys.",
        "tags": [
          "Surveys"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-surveys"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "The survey's name, shown at its top. Up to 140 characters."
                  },
                  "intro": {
                    "type": "string",
                    "description": "A sentence or two under the title. Up to 600 characters."
                  },
                  "questions": {
                    "type": "array",
                    "description": "Up to 12 questions. See the shape of a question."
                  },
                  "results": {
                    "type": "object",
                    "description": "What a person reads at the end: hot, warm and nurture, each a heading and text."
                  },
                  "form": {
                    "type": "object",
                    "description": "The contact step: button_label, contact_heading, contact_text, ask_phone and require_phone."
                  },
                  "status": {
                    "type": "string",
                    "description": "draft (the default), live or archived. A live survey has to be complete."
                  },
                  "slug": {
                    "type": "string",
                    "description": "The short name used in the tag and in addresses. Made from the title when left out."
                  }
                },
                "required": [
                  "title",
                  "questions"
                ]
              },
              "example": {
                "title": "Are you ready to buy in Halifax?",
                "intro": "Three quick questions about your timing and your financing.",
                "questions": [
                  {
                    "text": "When would you like to move?",
                    "type": "single",
                    "options": [
                      {
                        "label": "Within 3 months",
                        "points": 35
                      },
                      {
                        "label": "In 3 to 6 months",
                        "points": 25
                      },
                      {
                        "label": "In 6 to 12 months",
                        "points": 10
                      },
                      {
                        "label": "Just looking for now",
                        "points": 0
                      }
                    ]
                  },
                  {
                    "text": "Where are you with financing?",
                    "type": "single",
                    "options": [
                      {
                        "label": "Pre-approved for a mortgage",
                        "points": 35
                      },
                      {
                        "label": "Paying cash",
                        "points": 35
                      },
                      {
                        "label": "Talking to a lender",
                        "points": 20
                      },
                      {
                        "label": "Not started",
                        "points": 0
                      }
                    ]
                  },
                  {
                    "text": "Do you have a home to sell first?",
                    "type": "single",
                    "options": [
                      {
                        "label": "No",
                        "points": 30
                      },
                      {
                        "label": "Yes, and it is on the market",
                        "points": 20
                      },
                      {
                        "label": "Yes, not listed yet",
                        "points": 5
                      }
                    ]
                  }
                ],
                "results": {
                  "hot": {
                    "heading": "You are ready to buy",
                    "text": "Your timing and financing are in place. I will be in touch shortly to line up viewings."
                  },
                  "warm": {
                    "heading": "You are getting close",
                    "text": "A step or two is still open, usually financing or timing. I will follow up with what to do next."
                  },
                  "nurture": {
                    "heading": "You are at the start",
                    "text": "There is no rush. Reach out whenever you want to talk it through."
                  }
                },
                "status": "live"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "0f6f4f0a-3c58-4b0e-9b7e-6f6c2f2a7d55",
                  "object": "survey",
                  "slug": "ready-to-buy",
                  "status": "live",
                  "title": "Are you ready to buy in Halifax?",
                  "intro": "Three quick questions about your timing and your financing.",
                  "questions": [
                    {
                      "id": "r53jk9om",
                      "text": "When would you like to move?",
                      "help": "",
                      "type": "single",
                      "maps": "",
                      "options": [
                        {
                          "id": "y179w03u",
                          "label": "Within 3 months",
                          "points": 35,
                          "value": ""
                        },
                        {
                          "id": "711toz20",
                          "label": "In 3 to 6 months",
                          "points": 25,
                          "value": ""
                        },
                        {
                          "id": "p0d3n7ra",
                          "label": "In 6 to 12 months",
                          "points": 10,
                          "value": ""
                        },
                        {
                          "id": "b6t1w9ze",
                          "label": "Just looking for now",
                          "points": 0,
                          "value": ""
                        }
                      ]
                    },
                    {
                      "...": "two more questions"
                    }
                  ],
                  "results": {
                    "hot": {
                      "heading": "You are ready to buy",
                      "text": "Your timing and financing are in place. I will be in touch shortly to line up viewings."
                    },
                    "warm": {
                      "heading": "You are getting close",
                      "text": "A step or two is still open, usually financing or timing. I will follow up with what to do next."
                    },
                    "nurture": {
                      "heading": "You are at the start",
                      "text": "There is no rush. Reach out whenever you want to talk it through."
                    }
                  },
                  "form": {
                    "button_label": "Start",
                    "contact_heading": "Almost done. Where can I reach you?",
                    "contact_text": "Enter your details to see your result.",
                    "ask_phone": true,
                    "require_phone": false
                  },
                  "max_score": 100,
                  "bands": {
                    "hot": 80,
                    "warm": 50
                  },
                  "stats": {
                    "starts": 41,
                    "responses": 28,
                    "hot": 9,
                    "warm": 12,
                    "nurture": 7
                  },
                  "embed_html": "<div data-rf-survey=\"ready-to-buy\"></div>",
                  "created_at": "2026-11-12T15:04:05.000Z",
                  "updated_at": "2026-11-12T15:04:05.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_survey: The survey sent is not complete. The sentence says which part: a missing title, a question with no wording, fewer than two answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "too_many_surveys: The account already holds 50 surveys. Delete or reuse one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "surveyList",
        "summary": "List surveys",
        "description": "Every survey on the account, each in full with its count of starts and finished responses.",
        "tags": [
          "Surveys"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-surveys"
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "0f6f4f0a-3c58-4b0e-9b7e-6f6c2f2a7d55",
                      "object": "survey",
                      "slug": "ready-to-buy",
                      "status": "live",
                      "title": "Are you ready to buy in Halifax?",
                      "intro": "Three quick questions about your timing and your financing.",
                      "questions": [
                        {
                          "id": "r53jk9om",
                          "text": "When would you like to move?",
                          "help": "",
                          "type": "single",
                          "maps": "",
                          "options": [
                            {
                              "id": "y179w03u",
                              "label": "Within 3 months",
                              "points": 35,
                              "value": ""
                            },
                            {
                              "id": "711toz20",
                              "label": "In 3 to 6 months",
                              "points": 25,
                              "value": ""
                            },
                            {
                              "id": "p0d3n7ra",
                              "label": "In 6 to 12 months",
                              "points": 10,
                              "value": ""
                            },
                            {
                              "id": "b6t1w9ze",
                              "label": "Just looking for now",
                              "points": 0,
                              "value": ""
                            }
                          ]
                        },
                        {
                          "...": "two more questions"
                        }
                      ],
                      "results": {
                        "hot": {
                          "heading": "You are ready to buy",
                          "text": "Your timing and financing are in place. I will be in touch shortly to line up viewings."
                        },
                        "warm": {
                          "heading": "You are getting close",
                          "text": "A step or two is still open, usually financing or timing. I will follow up with what to do next."
                        },
                        "nurture": {
                          "heading": "You are at the start",
                          "text": "There is no rush. Reach out whenever you want to talk it through."
                        }
                      },
                      "form": {
                        "button_label": "Start",
                        "contact_heading": "Almost done. Where can I reach you?",
                        "contact_text": "Enter your details to see your result.",
                        "ask_phone": true,
                        "require_phone": false
                      },
                      "max_score": 100,
                      "bands": {
                        "hot": 80,
                        "warm": 50
                      },
                      "stats": {
                        "starts": 41,
                        "responses": 28,
                        "hot": 9,
                        "warm": 12,
                        "nurture": 7
                      },
                      "embed_html": "<div data-rf-survey=\"ready-to-buy\"></div>",
                      "created_at": "2026-11-12T15:04:05.000Z",
                      "updated_at": "2026-11-12T15:04:05.000Z"
                    }
                  ],
                  "page": 1,
                  "has_more": false
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/surveys/{id}": {
      "get": {
        "operationId": "surveyGet",
        "summary": "Get a survey",
        "description": "By its id or by its slug. This is the owner's view, points included: call it from your server, never from a page.",
        "tags": [
          "Surveys"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-survey"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id or the slug."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "0f6f4f0a-3c58-4b0e-9b7e-6f6c2f2a7d55",
                  "object": "survey",
                  "slug": "ready-to-buy",
                  "status": "live",
                  "title": "Are you ready to buy in Halifax?",
                  "intro": "Three quick questions about your timing and your financing.",
                  "questions": [
                    {
                      "id": "r53jk9om",
                      "text": "When would you like to move?",
                      "help": "",
                      "type": "single",
                      "maps": "",
                      "options": [
                        {
                          "id": "y179w03u",
                          "label": "Within 3 months",
                          "points": 35,
                          "value": ""
                        },
                        {
                          "id": "711toz20",
                          "label": "In 3 to 6 months",
                          "points": 25,
                          "value": ""
                        },
                        {
                          "id": "p0d3n7ra",
                          "label": "In 6 to 12 months",
                          "points": 10,
                          "value": ""
                        },
                        {
                          "id": "b6t1w9ze",
                          "label": "Just looking for now",
                          "points": 0,
                          "value": ""
                        }
                      ]
                    },
                    {
                      "...": "two more questions"
                    }
                  ],
                  "results": {
                    "hot": {
                      "heading": "You are ready to buy",
                      "text": "Your timing and financing are in place. I will be in touch shortly to line up viewings."
                    },
                    "warm": {
                      "heading": "You are getting close",
                      "text": "A step or two is still open, usually financing or timing. I will follow up with what to do next."
                    },
                    "nurture": {
                      "heading": "You are at the start",
                      "text": "There is no rush. Reach out whenever you want to talk it through."
                    }
                  },
                  "form": {
                    "button_label": "Start",
                    "contact_heading": "Almost done. Where can I reach you?",
                    "contact_text": "Enter your details to see your result.",
                    "ask_phone": true,
                    "require_phone": false
                  },
                  "max_score": 100,
                  "bands": {
                    "hot": 80,
                    "warm": 50
                  },
                  "stats": {
                    "starts": 41,
                    "responses": 28,
                    "hot": 9,
                    "warm": 12,
                    "nurture": 7
                  },
                  "embed_html": "<div data-rf-survey=\"ready-to-buy\"></div>",
                  "created_at": "2026-11-12T15:04:05.000Z",
                  "updated_at": "2026-11-12T15:04:05.000Z"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "surveyUpdate",
        "summary": "Change a survey",
        "description": "Send only what changes. questions replaces the whole list: keep the id of each question and answer you keep, so the answers already collected still line up.",
        "tags": [
          "Surveys"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#patch-survey"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id or the slug."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "The survey's name, shown at its top. Up to 140 characters."
                  },
                  "intro": {
                    "type": "string",
                    "description": "A sentence or two under the title. Up to 600 characters."
                  },
                  "questions": {
                    "type": "array",
                    "description": "Up to 12 questions. See the shape of a question."
                  },
                  "results": {
                    "type": "object",
                    "description": "What a person reads at the end: hot, warm and nurture, each a heading and text."
                  },
                  "form": {
                    "type": "object",
                    "description": "The contact step: button_label, contact_heading, contact_text, ask_phone and require_phone."
                  },
                  "status": {
                    "type": "string",
                    "description": "draft (the default), live or archived. A live survey has to be complete."
                  }
                }
              },
              "example": {
                "status": "archived"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "0f6f4f0a-3c58-4b0e-9b7e-6f6c2f2a7d55",
                  "object": "survey",
                  "slug": "ready-to-buy",
                  "status": "archived",
                  "title": "Are you ready to buy in Halifax?",
                  "intro": "Three quick questions about your timing and your financing.",
                  "questions": [
                    {
                      "id": "r53jk9om",
                      "text": "When would you like to move?",
                      "help": "",
                      "type": "single",
                      "maps": "",
                      "options": [
                        {
                          "id": "y179w03u",
                          "label": "Within 3 months",
                          "points": 35,
                          "value": ""
                        },
                        {
                          "id": "711toz20",
                          "label": "In 3 to 6 months",
                          "points": 25,
                          "value": ""
                        },
                        {
                          "id": "p0d3n7ra",
                          "label": "In 6 to 12 months",
                          "points": 10,
                          "value": ""
                        },
                        {
                          "id": "b6t1w9ze",
                          "label": "Just looking for now",
                          "points": 0,
                          "value": ""
                        }
                      ]
                    },
                    {
                      "...": "two more questions"
                    }
                  ],
                  "results": {
                    "hot": {
                      "heading": "You are ready to buy",
                      "text": "Your timing and financing are in place. I will be in touch shortly to line up viewings."
                    },
                    "warm": {
                      "heading": "You are getting close",
                      "text": "A step or two is still open, usually financing or timing. I will follow up with what to do next."
                    },
                    "nurture": {
                      "heading": "You are at the start",
                      "text": "There is no rush. Reach out whenever you want to talk it through."
                    }
                  },
                  "form": {
                    "button_label": "Start",
                    "contact_heading": "Almost done. Where can I reach you?",
                    "contact_text": "Enter your details to see your result.",
                    "ask_phone": true,
                    "require_phone": false
                  },
                  "max_score": 100,
                  "bands": {
                    "hot": 80,
                    "warm": 50
                  },
                  "stats": {
                    "starts": 41,
                    "responses": 28,
                    "hot": 9,
                    "warm": 12,
                    "nurture": 7
                  },
                  "embed_html": "<div data-rf-survey=\"ready-to-buy\"></div>",
                  "created_at": "2026-11-12T15:04:05.000Z",
                  "updated_at": "2026-11-12T15:04:05.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_survey: The survey sent is not complete. The sentence says which part: a missing title, a question with no wording, fewer than two answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "surveyDelete",
        "summary": "Delete a survey",
        "description": "The leads it brought in stay in the inbox.",
        "tags": [
          "Surveys"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#delete-survey"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id or the slug."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "0f6f4f0a-3c58-4b0e-9b7e-6f6c2f2a7d55",
                  "object": "survey",
                  "deleted": true
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/surveys/{id}/responses": {
      "post": {
        "operationId": "surveyRespond",
        "summary": "Send a finished survey",
        "description": "For a site that draws the questions itself instead of using the pasted line. Send what the person chose and how to reach them. The score is worked out on our side, the lead lands in the account's inbox with its answers, the alert email goes out and any follow-up the account has set up starts.\n\nShow the person result. Keep score and temperature on your server: they are for the agent, not for the visitor.",
        "tags": [
          "Surveys"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-survey-responses"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id or the slug."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "answers": {
                    "type": "object",
                    "description": "Each question's id with the id of the answer chosen, or a list of ids where several can be chosen."
                  },
                  "name": {
                    "type": "string",
                    "description": "The person's name."
                  },
                  "email": {
                    "type": "string",
                    "description": "A valid email address."
                  },
                  "phone": {
                    "type": "string",
                    "description": "Required when the survey's form has require_phone set."
                  },
                  "page_url": {
                    "type": "string",
                    "description": "The page the survey was taken on."
                  },
                  "utm_source": {
                    "type": "string",
                    "description": "Also utm_medium and utm_campaign: where the visitor came from, kept with the lead."
                  }
                },
                "required": [
                  "answers",
                  "name",
                  "email"
                ]
              },
              "example": {
                "answers": {
                  "r53jk9om": "y179w03u",
                  "wunt43tg": "i5psby4o",
                  "k2m8xq4d": "q3f7j2nb"
                },
                "name": "Dana Whitfield",
                "email": "dana@example.com",
                "phone": "902-555-0142",
                "page_url": "https://www.example.com/ready-to-buy"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "survey_response",
                  "lead_id": "7c1d7f52-2a3e-4d8a-8a55-0d7c3f1e9b20",
                  "score": 100,
                  "temperature": "hot",
                  "result": {
                    "heading": "You are ready to buy",
                    "text": "Your timing and financing are in place. I will be in touch shortly to line up viewings.",
                    "button": null
                  },
                  "created_at": "2026-11-12T15:09:41.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_response: The answers do not belong to this survey, or the name, email or required phone number is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "survey_not_live: Real answers were sent to a survey that is not live. Set its status to live.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/leads": {
      "post": {
        "operationId": "leadCreate",
        "summary": "Send a lead",
        "description": "An enquiry from your own form. It lands in the account's lead inbox, the alert email goes out and any follow-up the account has set up starts, exactly as for a site hosted by Realtor Flow.",
        "tags": [
          "Leads"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-leads"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The person's name."
                  },
                  "email": {
                    "type": "string",
                    "description": "A valid email address."
                  },
                  "phone": {
                    "type": "string",
                    "description": "A phone number."
                  },
                  "message": {
                    "type": "string",
                    "description": "What they wrote. Up to 4,000 characters."
                  },
                  "page_url": {
                    "type": "string",
                    "description": "The page the form is on."
                  },
                  "listing": {
                    "type": "string",
                    "description": "For an enquiry about one of the account's listings: its id or slug. The lead is filed with the listing."
                  },
                  "utm_source": {
                    "type": "string",
                    "description": "Also utm_medium and utm_campaign: where the visitor came from, kept with the lead."
                  }
                },
                "required": [
                  "name",
                  "email"
                ]
              },
              "example": {
                "name": "Dana Whitfield",
                "email": "dana@example.com",
                "phone": "902-555-0142",
                "message": "Is the house on Tower Road still available?",
                "page_url": "https://www.example.com/contact"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "7c1d7f52-2a3e-4d8a-8a55-0d7c3f1e9b20",
                  "object": "lead",
                  "name": "Dana Whitfield",
                  "email": "dana@example.com",
                  "created_at": "2026-11-12T15:09:41.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_lead: A lead needs a name and a valid email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "leadList",
        "summary": "List leads",
        "description": "Every lead in the account's inbox, newest first, wherever it came from: a Realtor Flow site, the pasted line or your own server. Pull new ones into your own system with since.\n\nA lead from a survey carries its score out of 100, how ready the person is (hot, warm or nurture), every answer as worded when they answered, and the note written for the agent when the survey is set to write one. follow_ups lists the follow-up sequences the lead is going through, with how many emails went out and when the next one is due.\n\nLeads marked as spam are left out unless status asks for them.",
        "tags": [
          "Leads"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-leads"
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "new, contacted, qualified, closed or spam. Several, separated by commas."
          },
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "contact (a form), listing (a form about one listing) or quiz (a survey). Several, separated by commas."
          },
          {
            "name": "temperature",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Survey leads only: hot, warm or nurture. Several, separated by commas."
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only leads that came in at or after this date and time (ISO 8601)."
          },
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only leads that came in before this date and time."
          },
          {
            "name": "email",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only leads from this address (any case)."
          },
          {
            "name": "listing",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only leads about this listing (its id or slug)."
          },
          {
            "name": "survey",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only leads from this survey (its id or slug)."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Up to 200. The default is 50."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Which page of results, from 1."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "7c1d7f52-2a3e-4d8a-8a55-0d7c3f1e9b20",
                      "object": "lead",
                      "kind": "listing",
                      "status": "new",
                      "name": "Dana Whitfield",
                      "email": "dana@example.com",
                      "phone": "902-555-0142",
                      "message": "Is the house on Tower Road still available?",
                      "listing": {
                        "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                        "slug": "tower-road-family-home",
                        "title": "Tower Road family home"
                      },
                      "survey": null,
                      "brief": null,
                      "survey_email": null,
                      "follow_ups": [
                        {
                          "id": "b71f0c2e-5d4a-4c38-9e61-2a8f7d3c1b90",
                          "sequence": {
                            "id": "e3c9a1d4-7b2f-4e8a-b5c6-1d0f9a8e7c21",
                            "name": "New enquiries"
                          },
                          "status": "active",
                          "stop_reason": null,
                          "emails_sent": 1,
                          "next_email_at": "2026-11-15T15:09:41.000Z",
                          "started_at": "2026-11-12T15:09:41.000Z"
                        }
                      ],
                      "page_url": "https://www.example.com/contact",
                      "utm": {
                        "utm_source": "newsletter"
                      },
                      "language": null,
                      "notes": null,
                      "alert_sent": true,
                      "created_at": "2026-11-12T15:09:41.000Z",
                      "updated_at": "2026-11-12T15:09:41.000Z"
                    },
                    {
                      "id": "2f8e4b61-9c3a-4d7e-8b15-6a0c9e2d4f73",
                      "object": "lead",
                      "kind": "quiz",
                      "status": "new",
                      "name": "Hattie Moreau",
                      "email": "hattie@example.com",
                      "phone": "902-555-0177",
                      "message": null,
                      "listing": null,
                      "survey": {
                        "id": "5a7c2e91-3b8d-4f60-a1e4-9d2b6c8f0e35",
                        "slug": "ready-to-buy",
                        "title": "Ready to buy?",
                        "score": 90,
                        "temperature": "hot",
                        "answers": [
                          {
                            "q": "When would you like to move?",
                            "a": [
                              "Within three months"
                            ]
                          },
                          {
                            "q": "Have you spoken to a lender?",
                            "a": [
                              "Yes, I am pre-approved"
                            ]
                          }
                        ]
                      },
                      "brief": {
                        "summary": "Pre-approved and wants to move within three months.",
                        "next_step": "Call this week and offer two viewings."
                      },
                      "survey_email": {
                        "subject": "Your result, and a next step",
                        "status": "sent",
                        "sent_at": "2026-11-11T10:02:13.000Z",
                        "note": null
                      },
                      "follow_ups": [],
                      "page_url": "https://www.example.com/quiz",
                      "utm": null,
                      "language": "en",
                      "notes": null,
                      "alert_sent": true,
                      "created_at": "2026-11-11T10:02:05.000Z",
                      "updated_at": "2026-11-11T10:02:13.000Z"
                    }
                  ],
                  "page": 1,
                  "has_more": false
                }
              }
            }
          },
          "400": {
            "description": "bad_status: status is not one this call takes. Bookings: enquiry, confirmed, paid, completed, cancelled. Leads: new, contacted, qualified, closed, spam. bad_kind: kind is one or more of contact, listing and quiz, separated by commas. bad_temperature: temperature is one or more of hot, warm and nurture, separated by commas. bad_date: since or before is not a date, such as 2026-11-01 or 2026-11-01T09:00:00Z.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/media": {
      "post": {
        "operationId": "mediaUpload",
        "summary": "Upload a photo",
        "description": "Adds a photo to the account's media library: send the file itself as a form upload, or a web address to fetch it from. It is turned into WebP at several widths (480, 960, 1600 and 2400 pixels, never wider than the original) and served from Realtor Flow for good, so the addresses work on any website.\n\nThe answer has the addresses of every size, a srcset, and html: an <img> ready to paste, with the width and height set so the page does not jump while it loads. Write alt as a short description of what the photo shows: it is read out to people who cannot see it and read by search engines.\n\nJPEG, PNG, WebP, AVIF, HEIC, GIF or TIFF; up to 20 MB as a file, 15 MB from a web address. Nothing here uses AI, so photos are not counted against the month's allowance.",
        "tags": [
          "Media"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-media"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "A web address to fetch the photo from (JSON body). Send this or file."
                  },
                  "alt": {
                    "type": "string",
                    "description": "What the photo shows, in a short sentence. Up to 300 characters."
                  }
                }
              },
              "example": {
                "url": "https://www.example.com/photos/harbour-at-dusk.jpg",
                "alt": "The harbour at dusk, seen from the condo balcony"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The photo, as a multipart/form-data upload with this field name. Send this or url."
                  },
                  "alt": {
                    "type": "string",
                    "description": "What the photo shows, in a short sentence. Up to 300 characters."
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48",
                  "object": "media",
                  "filename": "harbour-at-dusk.jpg",
                  "width": 2000,
                  "height": 1200,
                  "bytes": 1843921,
                  "alt": "The harbour at dusk, seen from the condo balcony",
                  "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp",
                  "sizes": [
                    {
                      "width": 480,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp"
                    },
                    {
                      "width": 960,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp"
                    },
                    {
                      "width": 1600,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp"
                    },
                    {
                      "width": 2000,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp"
                    }
                  ],
                  "srcset": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w",
                  "html": "<img src=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp\" srcset=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w\" sizes=\"(max-width: 960px) 100vw, 960px\" width=\"2000\" height=\"1200\" alt=\"The harbour at dusk, seen from the condo balcony\" loading=\"lazy\" decoding=\"async\">",
                  "created_at": "2026-11-13T19:42:10.000Z"
                }
              }
            }
          },
          "400": {
            "description": "no_photo: No photo was sent: a form upload with the field file, or JSON with url. bad_photo: A photo could not be used: the address does not answer, is not a JPEG, PNG or WebP, is over 15 MB, or is not on the public internet. The sentence names the photo. bad_upload: The form upload is not one photo in the field file. bad_alt: alt is not text, or is over 300 characters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "media_full: The account's media library holds 5,000 photos, the most it can. Delete some first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "413": {
            "description": "file_too_large: The photo is over 20 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "mediaList",
        "summary": "List photos",
        "description": "The account's media library, newest first: photos uploaded here, in the dashboard, or fetched for listings.",
        "tags": [
          "Media"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-media"
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Up to 200. The default is 50."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Which page of results, from 1."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48",
                      "object": "media",
                      "filename": "harbour-at-dusk.jpg",
                      "width": 2000,
                      "height": 1200,
                      "bytes": 1843921,
                      "alt": "The harbour at dusk, seen from the condo balcony",
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp",
                      "sizes": [
                        {
                          "width": 480,
                          "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp"
                        },
                        {
                          "width": 960,
                          "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp"
                        },
                        {
                          "width": 1600,
                          "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp"
                        },
                        {
                          "width": 2000,
                          "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp"
                        }
                      ],
                      "srcset": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w",
                      "html": "<img src=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp\" srcset=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w\" sizes=\"(max-width: 960px) 100vw, 960px\" width=\"2000\" height=\"1200\" alt=\"The harbour at dusk, seen from the condo balcony\" loading=\"lazy\" decoding=\"async\">",
                      "created_at": "2026-11-13T19:42:10.000Z"
                    }
                  ],
                  "page": 1,
                  "has_more": false
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/media/{id}": {
      "get": {
        "operationId": "mediaGet",
        "summary": "Get a photo",
        "description": "One photo by its id, with used_in: the listings, pages, articles and other places on the account that show it.",
        "tags": [
          "Media"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-media-one"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48",
                  "object": "media",
                  "filename": "harbour-at-dusk.jpg",
                  "width": 2000,
                  "height": 1200,
                  "bytes": 1843921,
                  "alt": "The harbour at dusk, seen from the condo balcony",
                  "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp",
                  "sizes": [
                    {
                      "width": 480,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp"
                    },
                    {
                      "width": 960,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp"
                    },
                    {
                      "width": 1600,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp"
                    },
                    {
                      "width": 2000,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp"
                    }
                  ],
                  "srcset": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w",
                  "html": "<img src=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp\" srcset=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w\" sizes=\"(max-width: 960px) 100vw, 960px\" width=\"2000\" height=\"1200\" alt=\"The harbour at dusk, seen from the condo balcony\" loading=\"lazy\" decoding=\"async\">",
                  "created_at": "2026-11-13T19:42:10.000Z",
                  "used_in": [
                    {
                      "kind": "listing",
                      "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                      "name": "Waterfront condo"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "mediaUpdate",
        "summary": "Change a photo's alt text",
        "description": "Changes the words that describe the photo. A listing keeps the alt text it was given when the photo was added to it.",
        "tags": [
          "Media"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#patch-media"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "alt": {
                    "type": "string",
                    "description": "Up to 300 characters. An empty string clears it."
                  }
                },
                "required": [
                  "alt"
                ]
              },
              "example": {
                "alt": "The harbour at dusk from the balcony of unit 1204"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48",
                  "object": "media",
                  "filename": "harbour-at-dusk.jpg",
                  "width": 2000,
                  "height": 1200,
                  "bytes": 1843921,
                  "alt": "The harbour at dusk from the balcony of unit 1204",
                  "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp",
                  "sizes": [
                    {
                      "width": 480,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp"
                    },
                    {
                      "width": 960,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp"
                    },
                    {
                      "width": 1600,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp"
                    },
                    {
                      "width": 2000,
                      "url": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp"
                    }
                  ],
                  "srcset": "https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w",
                  "html": "<img src=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp\" srcset=\"https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/480.webp 480w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/960.webp 960w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/1600.webp 1600w, https://api.realtorflow.ca/media/4f0e8a2c-6b1d-4c3e-9a7f-2d5b8c1e0f63/a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48/2000.webp 2000w\" sizes=\"(max-width: 960px) 100vw, 960px\" width=\"2000\" height=\"1200\" alt=\"The harbour at dusk, seen from the condo balcony\" loading=\"lazy\" decoding=\"async\">",
                  "created_at": "2026-11-13T19:42:10.000Z"
                }
              }
            }
          },
          "400": {
            "description": "nothing_to_change: The body has nothing to change: for a lead, neither status nor notes; for a photo, no alt. bad_alt: alt is not text, or is over 300 characters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "mediaDelete",
        "summary": "Delete a photo",
        "description": "Removes the photo and every size of it; its addresses stop working. Refused while anything on the account still shows it, so no page is left with a missing photo.",
        "tags": [
          "Media"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#delete-media"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a3d9e6f1-2c4b-4e8a-b7d5-9f1c3e2a6b48",
                  "object": "media",
                  "deleted": true
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "media_in_use: The photo is still used by a listing, page, article or something else on the account. The sentence names them. Take it out of those first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/leads/{id}": {
      "get": {
        "operationId": "leadGet",
        "summary": "Get a lead",
        "description": "One lead by its id, with everything the list gives.",
        "tags": [
          "Leads"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-lead"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "7c1d7f52-2a3e-4d8a-8a55-0d7c3f1e9b20",
                  "object": "lead",
                  "kind": "listing",
                  "status": "new",
                  "name": "Dana Whitfield",
                  "email": "dana@example.com",
                  "phone": "902-555-0142",
                  "message": "Is the house on Tower Road still available?",
                  "listing": {
                    "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                    "slug": "tower-road-family-home",
                    "title": "Tower Road family home"
                  },
                  "survey": null,
                  "brief": null,
                  "survey_email": null,
                  "follow_ups": [
                    {
                      "id": "b71f0c2e-5d4a-4c38-9e61-2a8f7d3c1b90",
                      "sequence": {
                        "id": "e3c9a1d4-7b2f-4e8a-b5c6-1d0f9a8e7c21",
                        "name": "New enquiries"
                      },
                      "status": "active",
                      "stop_reason": null,
                      "emails_sent": 1,
                      "next_email_at": "2026-11-15T15:09:41.000Z",
                      "started_at": "2026-11-12T15:09:41.000Z"
                    }
                  ],
                  "page_url": "https://www.example.com/contact",
                  "utm": {
                    "utm_source": "newsletter"
                  },
                  "language": null,
                  "notes": null,
                  "alert_sent": true,
                  "created_at": "2026-11-12T15:09:41.000Z",
                  "updated_at": "2026-11-12T15:09:41.000Z"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "leadUpdate",
        "summary": "Change a lead's status or notes",
        "description": "Moves a lead along (new, contacted, qualified, closed, spam) and keeps the agent's own notes, the same ones the dashboard shows. Notes never reach the lead.\n\nClosing a lead, or marking it as spam, stops its follow-up emails at once.",
        "tags": [
          "Leads"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#patch-lead"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "description": "The new status."
                  },
                  "notes": {
                    "type": "string",
                    "description": "Up to 4,000 characters. null clears them."
                  }
                }
              },
              "example": {
                "status": "contacted",
                "notes": "Called Tuesday. Viewing on Saturday at 10."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "7c1d7f52-2a3e-4d8a-8a55-0d7c3f1e9b20",
                  "object": "lead",
                  "kind": "listing",
                  "status": "contacted",
                  "name": "Dana Whitfield",
                  "email": "dana@example.com",
                  "phone": "902-555-0142",
                  "message": "Is the house on Tower Road still available?",
                  "listing": {
                    "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                    "slug": "tower-road-family-home",
                    "title": "Tower Road family home"
                  },
                  "survey": null,
                  "brief": null,
                  "survey_email": null,
                  "follow_ups": [
                    {
                      "id": "b71f0c2e-5d4a-4c38-9e61-2a8f7d3c1b90",
                      "sequence": {
                        "id": "e3c9a1d4-7b2f-4e8a-b5c6-1d0f9a8e7c21",
                        "name": "New enquiries"
                      },
                      "status": "active",
                      "stop_reason": null,
                      "emails_sent": 1,
                      "next_email_at": "2026-11-15T15:09:41.000Z",
                      "started_at": "2026-11-12T15:09:41.000Z"
                    }
                  ],
                  "page_url": "https://www.example.com/contact",
                  "utm": {
                    "utm_source": "newsletter"
                  },
                  "language": null,
                  "notes": "Called Tuesday. Viewing on Saturday at 10.",
                  "alert_sent": true,
                  "created_at": "2026-11-12T15:09:41.000Z",
                  "updated_at": "2026-11-12T15:09:41.000Z"
                }
              }
            }
          },
          "400": {
            "description": "nothing_to_change: The body has nothing to change: for a lead, neither status nor notes; for a photo, no alt. bad_status: status is not one this call takes. Bookings: enquiry, confirmed, paid, completed, cancelled. Leads: new, contacted, qualified, closed, spam. bad_notes: notes is not text (send null to clear it).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "413": {
            "description": "notes_too_long: notes is over 4,000 characters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/leads/{id}/follow-ups/stop": {
      "post": {
        "operationId": "leadStopFollowUps",
        "summary": "Stop a lead's follow-ups",
        "description": "Stops every follow-up sequence the lead is going through, for example once the agent has spoken to them. The lead itself is left as it is. stopped says how many were stopped; calling it again stops nothing and is not an error.",
        "tags": [
          "Leads"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-lead-follow-ups-stop"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "7c1d7f52-2a3e-4d8a-8a55-0d7c3f1e9b20",
                  "object": "lead",
                  "kind": "listing",
                  "status": "new",
                  "name": "Dana Whitfield",
                  "email": "dana@example.com",
                  "phone": "902-555-0142",
                  "message": "Is the house on Tower Road still available?",
                  "listing": {
                    "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                    "slug": "tower-road-family-home",
                    "title": "Tower Road family home"
                  },
                  "survey": null,
                  "brief": null,
                  "survey_email": null,
                  "follow_ups": [
                    {
                      "id": "b71f0c2e-5d4a-4c38-9e61-2a8f7d3c1b90",
                      "sequence": {
                        "id": "e3c9a1d4-7b2f-4e8a-b5c6-1d0f9a8e7c21",
                        "name": "New enquiries"
                      },
                      "status": "stopped",
                      "stop_reason": "stopped_by_api",
                      "emails_sent": 1,
                      "next_email_at": null,
                      "started_at": "2026-11-12T15:09:41.000Z"
                    }
                  ],
                  "page_url": "https://www.example.com/contact",
                  "utm": {
                    "utm_source": "newsletter"
                  },
                  "language": null,
                  "notes": null,
                  "alert_sent": true,
                  "created_at": "2026-11-12T15:09:41.000Z",
                  "updated_at": "2026-11-12T15:09:41.000Z",
                  "stopped": 1
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/articles/draft": {
      "post": {
        "operationId": "articleDraft",
        "summary": "Write an article from a draft",
        "description": "Send a rough draft: notes, bullet points, a transcript, an old blog post. A clear article comes back: a headline, a short answer up top, key points, sections with question headings, common questions and a closing line, plus a search title and description, ready HTML and its markup.\n\nOnly what is in the draft and in the account's business details is used. No figure, price, rule, name or quotation is added; a thin draft makes a short article. gaps lists what a reader would expect that the draft does not give, for the writer to add. check lists any figure or quotation in the article that is not in the draft word for word: read those before publishing.\n\nNothing is published or saved. The call answers when the article is written, which can take up to a minute. One article is counted against the month's allowance; a draft that fails is not counted.",
        "tags": [
          "Articles and translation"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-articles-draft"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "string",
                    "description": "The draft. 200 to 20,000 characters, in any of the five languages; the article is written in the account's language."
                  },
                  "title": {
                    "type": "string",
                    "description": "A working title, kept when it is a good one."
                  },
                  "page_url": {
                    "type": "string",
                    "description": "Where the article will be, so the markup carries its address."
                  }
                },
                "required": [
                  "source"
                ]
              },
              "example": {
                "title": "What to check before an offer",
                "source": "Before you make an offer in the harbour district, look at the roof and ask how old it is. Read the condo minutes for the last two years, because they show what repairs are coming. Ask what the seller is leaving behind, such as appliances and window coverings.",
                "page_url": "https://www.example.com/blog/before-an-offer"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "article_draft",
                  "title": "What to check before you make an offer in the harbour district",
                  "excerpt": "Three things to check before an offer: the roof, the condo minutes and what the seller is leaving behind.",
                  "meta_title": "What to check before an offer in the harbour district",
                  "meta_description": "Before an offer in the harbour district, check the roof, read two years of condo minutes and ask what the seller is leaving behind.",
                  "body": {
                    "intro": "...",
                    "points": [
                      "..."
                    ],
                    "sections": [
                      {
                        "heading": "How old is the roof?",
                        "text": "..."
                      }
                    ],
                    "faq": [
                      {
                        "question": "...",
                        "answer": "..."
                      }
                    ],
                    "closing": "...",
                    "button_label": "",
                    "button_link": ""
                  },
                  "html": "<div class=\"rf-article\">\n<div class=\"rf-intro\"><p>...</p></div>\n<div class=\"rf-points\"><h2>In short</h2><ul><li>...</li></ul></div>\n<section class=\"rf-section\"><h2>How old is the roof?</h2><p>...</p></section>\n...\n</div>",
                  "json_ld": [
                    {
                      "@context": "https://schema.org",
                      "@type": "Article",
                      "headline": "...",
                      "url": "https://www.example.com/blog/before-an-offer",
                      "...": "..."
                    },
                    {
                      "@context": "https://schema.org",
                      "@type": "FAQPage",
                      "...": "..."
                    }
                  ],
                  "gaps": [
                    "The draft gives no prices for the area."
                  ],
                  "check": {
                    "numbers": [],
                    "quotes": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "draft_too_short: The draft is under 200 characters. The article only uses what is in the draft, so it needs something to work with.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "413": {
            "description": "draft_too_long: The draft is over 20,000 characters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "limit_reached: The month's allowance for this kind of work is used up. It starts again on the first of the month (UTC). slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "502": {
            "description": "draft_failed: The draft did not come back complete. Nothing was counted. Try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "503": {
            "description": "try_later: The account has reached the day's ceiling for AI work. It starts again the next day. ai_off: AI writing is not available right now. Try again later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/translate": {
      "post": {
        "operationId": "translate",
        "summary": "Translate",
        "description": "Text from your site in English, French, Spanish, German or Chinese, translated as Realtor Flow sites translate theirs: faithfully, in a real estate agent's words, with the business's names kept as they are.\n\nEvery line is checked before it is handed back: figures, prices, phone numbers, email and web addresses, {markers} and the business's name must come through exactly, and the length must be reasonable. A line that fails comes back with translation set to null and the reason in problem, so it can be kept in the original language.\n\nOne translation is counted for each call, up to 20,000 characters; a call where nothing came back translated is not counted.",
        "tags": [
          "Articles and translation"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-translate"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "to": {
                    "type": "string",
                    "description": "en, fr, es, de or zh."
                  },
                  "text": {
                    "type": "string",
                    "description": "One text. Or texts: a list of up to 200, answered in the same order."
                  },
                  "from": {
                    "type": "string",
                    "description": "The language of the text. The default is the account's."
                  }
                },
                "required": [
                  "to"
                ]
              },
              "example": {
                "to": "fr",
                "texts": [
                  "Three bedrooms near the harbour, listed at $649,000.",
                  "Book a visit"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "translation",
                  "from": "en",
                  "to": "fr",
                  "items": [
                    {
                      "text": "Three bedrooms near the harbour, listed at $649,000.",
                      "translation": "Trois chambres près du port, à 649 000 $.",
                      "problem": null
                    },
                    {
                      "text": "Book a visit",
                      "translation": "Planifier une visite",
                      "problem": null
                    }
                  ],
                  "translated": 2,
                  "failed": 0
                }
              }
            }
          },
          "400": {
            "description": "no_text: Nothing to translate. Send text, or texts (up to 200). bad_language: to (or from) is not one of en, fr, es, de or zh, or both are the same.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "413": {
            "description": "text_too_long: Over 20,000 characters in one call. Split it into several calls.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "limit_reached: The month's allowance for this kind of work is used up. It starts again on the first of the month (UTC). slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "502": {
            "description": "translation_failed: The translation did not come back. Nothing was counted. Try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "503": {
            "description": "try_later: The account has reached the day's ceiling for AI work. It starts again the next day. ai_off: AI writing is not available right now. Try again later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/visibility": {
      "post": {
        "operationId": "visibility",
        "summary": "Build the AI visibility files",
        "description": "What AI assistants read about the business, built for your website's own address: a plain-text guide (llms.txt), the business as markup (RealEstateAgent) and the lines for robots.txt that welcome AI crawlers, following the account's choice about crawlers that collect pages to train models.\n\nEverything comes from what the account already says about itself (its name, area, licence and contact details, set in the dashboard) and from the pages and listings you name. Nothing is looked up or added. Publish llms_txt at /llms.txt, put json_ld in a <script type=\"application/ld+json\"> on every page, and add robots_txt to your robots.txt (its sitemap line assumes /sitemap.xml).\n\nBuilding them changes nothing, so it is not counted. Build them again when the listings or the details change.",
        "tags": [
          "AI visibility and traffic"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-visibility"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "description": "The website's address, https://www.example.com. Only the address is kept, not a path."
                  },
                  "listing_url": {
                    "type": "string",
                    "description": "How the website addresses a listing, with {slug}: https://www.example.com/homes/{slug}. Without it, listings are left out of the guide."
                  },
                  "pages": {
                    "type": "array",
                    "description": "The website's main pages, up to 50: { \"title\", \"url\", \"description\" }."
                  }
                },
                "required": [
                  "origin"
                ]
              },
              "example": {
                "origin": "https://www.example.com",
                "listing_url": "https://www.example.com/homes/{slug}",
                "pages": [
                  {
                    "title": "Selling your home",
                    "url": "https://www.example.com/sell",
                    "description": "How I price and sell homes in Halifax."
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "visibility",
                  "origin": "https://www.example.com",
                  "llms_txt": "# Harbour Realty\n\n> The website of Harbour Realty. Area served: Halifax and Dartmouth. 12 homes for sale or rent are listed.\n\nLicensed with the Nova Scotia Real Estate Commission\n\nContact:\n\n- Phone: 902-555-0142\n- Email: hello@harbour.example\n\n## Pages\n\n- [Selling your home](https://www.example.com/sell): How I price and sell homes in Halifax.\n\n## Listings\n\n- [Waterfront condo](https://www.example.com/homes/waterfront-condo): Condo. For sale. Halifax, NS. Beds: 2. $649,000\n...",
                  "listings_in_llms_txt": 12,
                  "json_ld": {
                    "@context": "https://schema.org",
                    "@type": "RealEstateAgent",
                    "name": "Harbour Realty",
                    "url": "https://www.example.com",
                    "telephone": "902-555-0142",
                    "email": "hello@harbour.example",
                    "areaServed": "Halifax and Dartmouth"
                  },
                  "robots_choice": "all",
                  "robots_txt": "# AI crawlers are welcome on this site.\nUser-agent: OAI-SearchBot\nUser-agent: ChatGPT-User\nUser-agent: GPTBot\n...\nAllow: /\n\nUser-agent: *\nAllow: /\n\n# A plain-text guide to this site for AI assistants: https://www.example.com/llms.txt\nSitemap: https://www.example.com/sitemap.xml\n"
                }
              }
            }
          },
          "400": {
            "description": "bad_origin: origin is missing or is not a web address starting with https://. bad_listing_url: listing_url is not a full address with {slug} where each listing's short name goes. bad_pages: pages is not a list of { \"title\", \"url\", \"description\" }.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/analytics": {
      "get": {
        "operationId": "analytics",
        "summary": "AI traffic",
        "description": "The page views the pasted line counted (with data-count=\"on\") and, for a Realtor Flow site, its own: visits, visitors, where they came from and which AI assistants sent them. The same figures as the dashboard's AI-Traffic Analytics.",
        "tags": [
          "AI visibility and traffic"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-analytics"
        },
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "7, 30 (the default) or 90."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "analytics",
                  "days": 30,
                  "tz": "America/Toronto",
                  "keep_days": 180,
                  "totals": {
                    "views": 1840,
                    "visits": 1210,
                    "visitors": 960,
                    "ai": 64
                  },
                  "by_day": [
                    {
                      "day": "2026-11-13",
                      "views": 71,
                      "visits": 48,
                      "ai": 3,
                      "visitors": 40
                    },
                    {
                      "...": "..."
                    }
                  ],
                  "sources": {
                    "ai": 64,
                    "search": 610,
                    "social": 140,
                    "direct": 330,
                    "other": 66
                  },
                  "pages": [
                    {
                      "path": "/homes/waterfront-condo",
                      "views": 220,
                      "ai": 11
                    }
                  ],
                  "ai_referrers": [
                    {
                      "name": "ChatGPT",
                      "n": 41
                    },
                    {
                      "name": "Perplexity",
                      "n": 15
                    },
                    {
                      "name": "Gemini",
                      "n": 8
                    }
                  ],
                  "ai_pages": [
                    {
                      "path": "/neighbourhoods/verdun",
                      "n": 9
                    }
                  ],
                  "referrers": [],
                  "campaigns": [],
                  "crawlers": [],
                  "crawled": [],
                  "leads": {
                    "on": true,
                    "total": 22,
                    "by": [
                      {
                        "utm_source": "chatgpt.com",
                        "n": 2,
                        "ai": true
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/crawls": {
      "post": {
        "operationId": "crawls",
        "summary": "Report AI crawler visits",
        "description": "For a website whose own server draws its pages: report the AI crawlers it saw (GPTBot, ClaudeBot, PerplexityBot and the others), so they appear in the account's AI traffic beside its visitors. A pasted line cannot do this, because crawlers do not run scripts. The WordPress plugin calls this for you.\n\nSend every visit you are unsure about: anything that is not a known AI crawler is dropped, so people are never counted here. Send them in batches, every few minutes, rather than one call per page.",
        "tags": [
          "AI visibility and traffic"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-crawls"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "hits": {
                    "type": "array",
                    "description": "1 to 200 visits, each { \"user_agent\", \"path\", \"at\" }: the visitor's user agent as your server received it, the page's path (starting with /), and when (ISO 8601, within the last two days; now when left out). A single visit can also be sent on its own, without hits."
                  }
                },
                "required": [
                  "hits"
                ]
              },
              "example": {
                "hits": [
                  {
                    "user_agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)",
                    "path": "/homes/waterfront-condo",
                    "at": "2026-11-13T18:02:11Z"
                  },
                  {
                    "user_agent": "Mozilla/5.0 (compatible; ClaudeBot/1.0; +claudebot@anthropic.com)",
                    "path": "/llms.txt",
                    "at": "2026-11-13T18:04:40Z"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "crawls",
                  "counted": 2,
                  "dropped": 0,
                  "crawlers": {
                    "GPTBot": 1,
                    "ClaudeBot": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "bad_crawls: hits is empty or holds more than 200 visits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/listings/{id}/booking": {
      "put": {
        "operationId": "bookingTerms",
        "summary": "Take bookings on a listing",
        "description": "Gives a listing its booking terms, or changes them. From then on, guests can ask for dates on it. DELETE on the same address stops it taking requests; the bookings already made stay.",
        "tags": [
          "Bookings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#put-listing-booking"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nightly_rate": {
                    "type": "number",
                    "description": "In the listing's currency."
                  },
                  "min_nights": {
                    "type": "number",
                    "description": "The shortest stay, from 1 to 90."
                  },
                  "max_guests": {
                    "type": "number",
                    "description": "From 1 to 99."
                  },
                  "is_on": {
                    "type": "boolean",
                    "description": "false keeps the terms but stops new requests for now."
                  }
                },
                "required": [
                  "nightly_rate",
                  "min_nights",
                  "max_guests"
                ]
              },
              "example": {
                "nightly_rate": 180,
                "min_nights": 2,
                "max_guests": 4
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "booking_terms",
                  "listing": "beach-cottage",
                  "nightly_rate": 180,
                  "currency": "CAD",
                  "min_nights": 2,
                  "max_guests": 4,
                  "taking_bookings": true
                }
              }
            }
          },
          "400": {
            "description": "bad_terms: The booking terms are not right: a nightly rate above zero, and whole numbers for the shortest stay and the most guests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/listings/{id}/availability": {
      "get": {
        "operationId": "availability",
        "summary": "Check availability",
        "description": "The terms and the nights already held by confirmed or paid bookings, for a calendar on your own page. Only dates: never who booked.",
        "tags": [
          "Bookings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-availability"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "availability",
                  "listing": "beach-cottage",
                  "taking_bookings": true,
                  "nightly_rate": 180,
                  "currency": "CAD",
                  "min_nights": 2,
                  "max_guests": 4,
                  "max_nights": 90,
                  "booked": [
                    {
                      "check_in": "2026-12-26",
                      "check_out": "2027-01-02"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/bookings": {
      "post": {
        "operationId": "bookingCreate",
        "summary": "Send a booking request",
        "description": "A request from your own booking form. It is checked as on a Realtor Flow site (the dates, the shortest stay, the guests and the nights already held), saved as an enquiry with its estimate, and the broker's alert and the guest's receipt go out.\n\nA request does not hold the nights. They are held once the broker confirms. No payment is taken anywhere in the tool kit.",
        "tags": [
          "Bookings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-bookings"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "listing": {
                    "type": "string",
                    "description": "The listing's id or slug."
                  },
                  "check_in": {
                    "type": "string",
                    "description": "A date, YYYY-MM-DD. Not in the past, and within two years."
                  },
                  "check_out": {
                    "type": "string",
                    "description": "A later date. Up to 90 nights."
                  },
                  "guests": {
                    "type": "number",
                    "description": "Up to the listing's most guests."
                  },
                  "name": {
                    "type": "string",
                    "description": "The guest's name."
                  },
                  "email": {
                    "type": "string",
                    "description": "A valid email address. The receipt goes there."
                  },
                  "phone": {
                    "type": "string",
                    "description": "Also message."
                  }
                },
                "required": [
                  "listing",
                  "check_in",
                  "check_out",
                  "guests",
                  "name",
                  "email"
                ]
              },
              "example": {
                "listing": "beach-cottage",
                "check_in": "2026-12-18",
                "check_out": "2026-12-21",
                "guests": 2,
                "name": "Dana Whitfield",
                "email": "dana@example.com",
                "phone": "902-555-0142",
                "message": "Arriving late on the first night."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "4e2a9c71-8b3d-4f6e-a0c5-7d19e2b6f348",
                  "object": "booking",
                  "status": "enquiry",
                  "listing": {
                    "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                    "slug": "beach-cottage",
                    "title": "Beach cottage"
                  },
                  "check_in": "2026-12-18",
                  "check_out": "2026-12-21",
                  "nights": 3,
                  "guests": 2,
                  "name": "Dana Whitfield",
                  "email": "dana@example.com",
                  "phone": "902-555-0142",
                  "message": "Arriving late on the first night.",
                  "nightly_rate": 180,
                  "currency": "CAD",
                  "estimate": 540,
                  "notes": null,
                  "overlaps_confirmed": false,
                  "created_at": "2026-11-13T17:20:05.000Z",
                  "updated_at": "2026-11-13T17:20:05.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_booking: The request is not right. The sentence says which part, in the account's language: the dates, the length of stay, the number of guests or the contact details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_bookable: The listing is not taking booking requests: it has no booking terms, or it is not active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "dates_taken: Some of those nights are already held by a confirmed or paid booking.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "bookingList",
        "summary": "List bookings",
        "description": "The account's bookings, newest first.",
        "tags": [
          "Bookings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-bookings"
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only bookings with this status."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Up to 200. The default is 50."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Which page of results, from 1."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "4e2a9c71-8b3d-4f6e-a0c5-7d19e2b6f348",
                      "object": "booking",
                      "status": "enquiry",
                      "listing": {
                        "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                        "slug": "beach-cottage",
                        "title": "Beach cottage"
                      },
                      "check_in": "2026-12-18",
                      "check_out": "2026-12-21",
                      "nights": 3,
                      "guests": 2,
                      "name": "Dana Whitfield",
                      "email": "dana@example.com",
                      "phone": "902-555-0142",
                      "message": "Arriving late on the first night.",
                      "nightly_rate": 180,
                      "currency": "CAD",
                      "estimate": 540,
                      "notes": null,
                      "overlaps_confirmed": false,
                      "created_at": "2026-11-13T17:20:05.000Z",
                      "updated_at": "2026-11-13T17:20:05.000Z"
                    }
                  ],
                  "page": 1,
                  "has_more": false
                }
              }
            }
          },
          "400": {
            "description": "bad_status: status is not one this call takes. Bookings: enquiry, confirmed, paid, completed, cancelled. Leads: new, contacted, qualified, closed, spam.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/bookings/{id}": {
      "get": {
        "operationId": "bookingGet",
        "summary": "Get a booking",
        "description": "One booking by its id.",
        "tags": [
          "Bookings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-booking"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "4e2a9c71-8b3d-4f6e-a0c5-7d19e2b6f348",
                  "object": "booking",
                  "status": "enquiry",
                  "listing": {
                    "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                    "slug": "beach-cottage",
                    "title": "Beach cottage"
                  },
                  "check_in": "2026-12-18",
                  "check_out": "2026-12-21",
                  "nights": 3,
                  "guests": 2,
                  "name": "Dana Whitfield",
                  "email": "dana@example.com",
                  "phone": "902-555-0142",
                  "message": "Arriving late on the first night.",
                  "nightly_rate": 180,
                  "currency": "CAD",
                  "estimate": 540,
                  "notes": null,
                  "overlaps_confirmed": false,
                  "created_at": "2026-11-13T17:20:05.000Z",
                  "updated_at": "2026-11-13T17:20:05.000Z"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "bookingUpdate",
        "summary": "Change a booking's status",
        "description": "Moves a booking along: enquiry, confirmed, paid (a note that the money reached the broker some other way), completed or cancelled. Confirming, or marking paid, is refused while another booking already holds any of the nights. notes are the broker's own and never reach the guest.",
        "tags": [
          "Bookings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#patch-booking"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "description": "The new status."
                  },
                  "notes": {
                    "type": "string",
                    "description": "Up to 5,000 characters."
                  }
                }
              },
              "example": {
                "status": "confirmed",
                "notes": "Deposit by e-transfer."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "4e2a9c71-8b3d-4f6e-a0c5-7d19e2b6f348",
                  "object": "booking",
                  "status": "confirmed",
                  "listing": {
                    "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                    "slug": "beach-cottage",
                    "title": "Beach cottage"
                  },
                  "check_in": "2026-12-18",
                  "check_out": "2026-12-21",
                  "nights": 3,
                  "guests": 2,
                  "name": "Dana Whitfield",
                  "email": "dana@example.com",
                  "phone": "902-555-0142",
                  "message": "Arriving late on the first night.",
                  "nightly_rate": 180,
                  "currency": "CAD",
                  "estimate": 540,
                  "notes": "Deposit by e-transfer.",
                  "overlaps_confirmed": false,
                  "created_at": "2026-11-13T17:20:05.000Z",
                  "updated_at": "2026-11-13T17:20:05.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_status: status is not one this call takes. Bookings: enquiry, confirmed, paid, completed, cancelled. Leads: new, contacted, qualified, closed, spam.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "dates_taken: Some of those nights are already held by a confirmed or paid booking.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/subscribers": {
      "post": {
        "operationId": "subscriberAdd",
        "summary": "Add a sign-up",
        "description": "Someone who signed up on your own form, with a box they ticked themselves. They join the account's mailing list, and campaigns sent from the dashboard reach them. Never send people who did not agree.\n\nAn address that bounced or complained is not added; the answer says blocked. Someone who had unsubscribed and signs up again is back on the list, with the new consent.",
        "tags": [
          "Newsletter"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-subscribers"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "Their email address."
                  },
                  "consent_text": {
                    "type": "string",
                    "description": "The exact words beside the box they ticked. Kept with the address as the record of their consent. 10 to 300 characters."
                  },
                  "name": {
                    "type": "string",
                    "description": "Their name."
                  },
                  "page_url": {
                    "type": "string",
                    "description": "The page they signed up on."
                  }
                },
                "required": [
                  "email",
                  "consent_text"
                ]
              },
              "example": {
                "email": "dana@example.com",
                "name": "Dana Whitfield",
                "consent_text": "Yes, send me the monthly market note from Harbour Realty.",
                "page_url": "https://www.example.com/newsletter"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "subscriber",
                  "email": "dana@example.com",
                  "name": "Dana Whitfield",
                  "status": "subscribed",
                  "consent_text": "Yes, send me the monthly market note from Harbour Realty.",
                  "consent_at": "2026-11-13T16:02:11.000Z",
                  "page_url": "https://www.example.com/newsletter",
                  "created_at": "2026-11-13T16:02:11.000Z",
                  "updated_at": "2026-11-13T16:02:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad_subscriber: A sign-up needs a valid email. no_consent: No consent: the box was not ticked, or consent_text (the exact words the person agreed to) was not sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "subscriberList",
        "summary": "List sign-ups",
        "description": "The mailing list, newest first, with each person's consent and when it was given.",
        "tags": [
          "Newsletter"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-subscribers"
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "subscribed, unsubscribed or bounced."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Up to 200. The default is 50."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Which page of results, from 1."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "subscriber",
                      "email": "dana@example.com",
                      "name": "Dana Whitfield",
                      "status": "subscribed",
                      "consent_text": "Yes, send me the monthly market note from Harbour Realty.",
                      "consent_at": "2026-11-13T16:02:11.000Z",
                      "page_url": "https://www.example.com/newsletter",
                      "created_at": "2026-11-13T16:02:11.000Z",
                      "updated_at": "2026-11-13T16:02:11.000Z"
                    }
                  ],
                  "page": 1,
                  "has_more": false
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/subscribers/unsubscribe": {
      "post": {
        "operationId": "subscriberRemove",
        "summary": "Unsubscribe someone",
        "description": "For an unsubscribe link or request handled on your side. The address leaves the list and goes on the account's do-not-mail list; any follow-up emails under way for it stop.",
        "tags": [
          "Newsletter"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-subscribers-unsubscribe"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "The address to take off."
                  }
                },
                "required": [
                  "email"
                ]
              },
              "example": {
                "email": "dana@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "subscriber",
                  "email": "dana@example.com",
                  "status": "unsubscribed"
                }
              }
            }
          },
          "400": {
            "description": "bad_subscriber: A sign-up needs a valid email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/listings": {
      "get": {
        "operationId": "listingList",
        "summary": "List listings",
        "description": "The account's listings, featured ones first, then the newest. Each comes in the short form, with its first photo.",
        "tags": [
          "Listings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-listings"
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only listings with this status."
          },
          {
            "name": "listing_type",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "sale or rent."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Up to 100. The default is 20."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Which page of results, from 1."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                      "object": "listing",
                      "slug": "brick-duplex-near-the-river",
                      "status": "active",
                      "title": "Brick duplex near the river",
                      "listing_type": "sale",
                      "property_type": "Duplex",
                      "price": 899000,
                      "currency": "CAD",
                      "bedrooms": 5,
                      "bathrooms": 2,
                      "area": 2100,
                      "area_unit": "sqft",
                      "city": "Halifax",
                      "region": "NS",
                      "is_featured": false,
                      "photos": [
                        {
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp",
                          "width": 1600,
                          "height": 1067,
                          "alt": "Front of the duplex",
                          "sizes": [
                            {
                              "width": 480,
                              "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/480.webp"
                            },
                            {
                              "width": 960,
                              "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/960.webp"
                            },
                            {
                              "width": 1600,
                              "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp"
                            }
                          ]
                        }
                      ],
                      "created_at": "2026-11-13T14:34:59.409Z",
                      "updated_at": "2026-11-13T14:34:59.409Z"
                    }
                  ],
                  "page": 1,
                  "has_more": false
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "listingCreate",
        "summary": "Add a listing",
        "description": "Photos are sent as web addresses. Each one is fetched once, stored and sized like a photo uploaded in the dashboard, so it no longer depends on where it came from. A call with many photos can take some seconds.\n\nNothing here uses AI, so listings are not counted against the month's allowance.",
        "tags": [
          "Listings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#post-listings"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Up to 200 characters."
                  },
                  "description": {
                    "type": "string",
                    "description": "Plain text. A blank line starts a new paragraph. Up to 12,000 characters."
                  },
                  "listing_type": {
                    "type": "string",
                    "description": "sale (the default) or rent."
                  },
                  "property_type": {
                    "type": "string",
                    "description": "One of the types above, in any capitals."
                  },
                  "price": {
                    "type": "number",
                    "description": "Leave it out for price on request."
                  },
                  "currency": {
                    "type": "string",
                    "description": "CAD (the default), USD or EUR."
                  },
                  "bedrooms": {
                    "type": "number",
                    "description": "Also bathrooms, area, lot_size and year_built."
                  },
                  "address": {
                    "type": "string",
                    "description": "Also city, region and country."
                  },
                  "features": {
                    "type": "array",
                    "description": "Short lines such as \"Garage\". Up to 40."
                  },
                  "photos": {
                    "type": "array",
                    "description": "Up to 30 photos: web addresses, { \"url\", \"alt\" }, or { \"media\", \"alt\" } for a photo already in the media library. A web address is fetched once and stored (JPEG, PNG or WebP, up to 15 MB). A library photo is used as it is and stays in the library if the listing drops it later."
                  },
                  "status": {
                    "type": "string",
                    "description": "active (the default here), pending, sold, draft or archived."
                  },
                  "mls_number": {
                    "type": "string",
                    "description": "Shown only when sent."
                  }
                },
                "required": [
                  "title"
                ]
              },
              "example": {
                "title": "Brick duplex near the river",
                "listing_type": "sale",
                "property_type": "Duplex",
                "price": 899000,
                "bedrooms": 5,
                "bathrooms": 2,
                "area": 2100,
                "address": "1234 Example Street",
                "city": "Halifax",
                "region": "NS",
                "features": [
                  "Garage",
                  "Terrace"
                ],
                "photos": [
                  {
                    "url": "https://www.example.com/photos/duplex-front.jpg",
                    "alt": "Front of the duplex"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                  "object": "listing",
                  "slug": "brick-duplex-near-the-river",
                  "status": "active",
                  "title": "Brick duplex near the river",
                  "listing_type": "sale",
                  "property_type": "Duplex",
                  "price": 899000,
                  "currency": "CAD",
                  "bedrooms": 5,
                  "bathrooms": 2,
                  "area": 2100,
                  "area_unit": "sqft",
                  "city": "Halifax",
                  "region": "NS",
                  "is_featured": false,
                  "photos": [
                    {
                      "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp",
                      "width": 1600,
                      "height": 1067,
                      "alt": "Front of the duplex",
                      "sizes": [
                        {
                          "width": 480,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/480.webp"
                        },
                        {
                          "width": 960,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/960.webp"
                        },
                        {
                          "width": 1600,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp"
                        }
                      ]
                    }
                  ],
                  "created_at": "2026-11-13T14:34:59.409Z",
                  "updated_at": "2026-11-13T14:34:59.409Z",
                  "description": "Two full units on a quiet street, each with its own entrance.\n\nA detached garage and a private terrace.",
                  "lot_size": null,
                  "year_built": 1928,
                  "address": "1234 Example Street",
                  "country": "CA",
                  "mls_number": null,
                  "features": [
                    "Garage",
                    "Terrace"
                  ],
                  "meta_title": null,
                  "meta_description": null,
                  "json_ld": {
                    "@context": "https://schema.org",
                    "@type": "RealEstateListing",
                    "name": "Brick duplex near the river",
                    "datePosted": "2026-11-13T14:34:59.409Z",
                    "dateModified": "2026-11-13T14:34:59.409Z",
                    "mainEntity": {
                      "@type": "Accommodation",
                      "name": "Brick duplex near the river",
                      "address": {
                        "@type": "PostalAddress",
                        "streetAddress": "1234 Example Street",
                        "addressLocality": "Halifax",
                        "addressRegion": "NS",
                        "addressCountry": "CA"
                      },
                      "numberOfBedrooms": 5,
                      "numberOfBathroomsTotal": 2,
                      "floorSize": {
                        "@type": "QuantitativeValue",
                        "value": 2100,
                        "unitCode": "FTK"
                      },
                      "yearBuilt": 1928,
                      "...": "..."
                    },
                    "provider": {
                      "@type": "RealEstateAgent",
                      "name": "Harbour Realty"
                    },
                    "image": [
                      "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp"
                    ],
                    "offers": {
                      "@type": "Offer",
                      "price": 899000,
                      "priceCurrency": "CAD"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "bad_listing: The listing sent is not right. The sentence says which part: a missing title, an unknown property type or status. bad_photo: A photo could not be used: the address does not answer, is not a JPEG, PNG or WebP, is over 15 MB, or is not on the public internet. The sentence names the photo. too_many_photos: A listing can have up to 30 photos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "409": {
            "description": "too_many_listings: The account already holds 2,000 listings. Delete or archive old ones.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    },
    "/listings/{id}": {
      "get": {
        "operationId": "listingGet",
        "summary": "Get a listing",
        "description": "One listing in full, by its id or its slug, with its search markup. Put json_ld in a <script type=\"application/ld+json\"> on the listing's page.",
        "tags": [
          "Listings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#get-listing"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          },
          {
            "name": "page_url",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The address of the page the listing is on, so the markup carries it."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                  "object": "listing",
                  "slug": "brick-duplex-near-the-river",
                  "status": "active",
                  "title": "Brick duplex near the river",
                  "listing_type": "sale",
                  "property_type": "Duplex",
                  "price": 899000,
                  "currency": "CAD",
                  "bedrooms": 5,
                  "bathrooms": 2,
                  "area": 2100,
                  "area_unit": "sqft",
                  "city": "Halifax",
                  "region": "NS",
                  "is_featured": false,
                  "photos": [
                    {
                      "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp",
                      "width": 1600,
                      "height": 1067,
                      "alt": "Front of the duplex",
                      "sizes": [
                        {
                          "width": 480,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/480.webp"
                        },
                        {
                          "width": 960,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/960.webp"
                        },
                        {
                          "width": 1600,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp"
                        }
                      ]
                    }
                  ],
                  "created_at": "2026-11-13T14:34:59.409Z",
                  "updated_at": "2026-11-13T14:34:59.409Z",
                  "description": "Two full units on a quiet street, each with its own entrance.\n\nA detached garage and a private terrace.",
                  "lot_size": null,
                  "year_built": 1928,
                  "address": "1234 Example Street",
                  "country": "CA",
                  "mls_number": null,
                  "features": [
                    "Garage",
                    "Terrace"
                  ],
                  "meta_title": null,
                  "meta_description": null,
                  "json_ld": {
                    "@context": "https://schema.org",
                    "@type": "RealEstateListing",
                    "name": "Brick duplex near the river",
                    "url": "https://www.example.com/homes/brick-duplex",
                    "mainEntityOfPage": "https://www.example.com/homes/brick-duplex",
                    "datePosted": "2026-11-13T14:34:59.409Z",
                    "dateModified": "2026-11-13T14:34:59.409Z",
                    "mainEntity": {
                      "@type": "Accommodation",
                      "name": "Brick duplex near the river",
                      "address": {
                        "@type": "PostalAddress",
                        "streetAddress": "1234 Example Street",
                        "addressLocality": "Halifax",
                        "addressRegion": "NS",
                        "addressCountry": "CA"
                      },
                      "numberOfBedrooms": 5,
                      "numberOfBathroomsTotal": 2,
                      "floorSize": {
                        "@type": "QuantitativeValue",
                        "value": 2100,
                        "unitCode": "FTK"
                      },
                      "yearBuilt": 1928,
                      "...": "..."
                    },
                    "provider": {
                      "@type": "RealEstateAgent",
                      "name": "Harbour Realty"
                    },
                    "image": [
                      "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp"
                    ],
                    "offers": {
                      "@type": "Offer",
                      "price": 899000,
                      "priceCurrency": "CAD"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "listingUpdate",
        "summary": "Change a listing",
        "description": "Send only what changes. photos replaces the whole set; the photos it no longer uses are removed. Without photos, the listing keeps the ones it has. Marking a home sold is { \"status\": \"sold\" }.",
        "tags": [
          "Listings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#patch-listing"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Up to 200 characters."
                  },
                  "description": {
                    "type": "string",
                    "description": "Plain text. A blank line starts a new paragraph. Up to 12,000 characters."
                  },
                  "listing_type": {
                    "type": "string",
                    "description": "sale (the default) or rent."
                  },
                  "property_type": {
                    "type": "string",
                    "description": "One of the types above, in any capitals."
                  },
                  "price": {
                    "type": "number",
                    "description": "Leave it out for price on request."
                  },
                  "currency": {
                    "type": "string",
                    "description": "CAD (the default), USD or EUR."
                  },
                  "bedrooms": {
                    "type": "number",
                    "description": "Also bathrooms, area, lot_size and year_built."
                  },
                  "address": {
                    "type": "string",
                    "description": "Also city, region and country."
                  },
                  "features": {
                    "type": "array",
                    "description": "Short lines such as \"Garage\". Up to 40."
                  },
                  "photos": {
                    "type": "array",
                    "description": "Up to 30 photos: web addresses, { \"url\", \"alt\" }, or { \"media\", \"alt\" } for a photo already in the media library. A web address is fetched once and stored (JPEG, PNG or WebP, up to 15 MB). A library photo is used as it is and stays in the library if the listing drops it later."
                  },
                  "status": {
                    "type": "string",
                    "description": "active (the default here), pending, sold, draft or archived."
                  },
                  "mls_number": {
                    "type": "string",
                    "description": "Shown only when sent."
                  }
                }
              },
              "example": {
                "price": 879000,
                "status": "pending"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                  "object": "listing",
                  "slug": "brick-duplex-near-the-river",
                  "status": "pending",
                  "title": "Brick duplex near the river",
                  "listing_type": "sale",
                  "property_type": "Duplex",
                  "price": 879000,
                  "currency": "CAD",
                  "bedrooms": 5,
                  "bathrooms": 2,
                  "area": 2100,
                  "area_unit": "sqft",
                  "city": "Halifax",
                  "region": "NS",
                  "is_featured": false,
                  "photos": [
                    {
                      "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp",
                      "width": 1600,
                      "height": 1067,
                      "alt": "Front of the duplex",
                      "sizes": [
                        {
                          "width": 480,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/480.webp"
                        },
                        {
                          "width": 960,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/960.webp"
                        },
                        {
                          "width": 1600,
                          "url": "https://api.realtorflow.ca/media/3b8f6a2e-7c1d-4e5a-9f20-6d1c8b4a7e13/a41c9e7b-2f6d-4b8e-91c3-5e7a0d2f6b84/1600.webp"
                        }
                      ]
                    }
                  ],
                  "created_at": "2026-11-13T14:34:59.409Z",
                  "updated_at": "2026-11-13T14:34:59.409Z",
                  "description": "Two full units on a quiet street, each with its own entrance.\n\nA detached garage and a private terrace.",
                  "lot_size": null,
                  "year_built": 1928,
                  "address": "1234 Example Street",
                  "country": "CA",
                  "mls_number": null,
                  "features": [
                    "Garage",
                    "Terrace"
                  ],
                  "meta_title": null,
                  "meta_description": null,
                  "json_ld": "..."
                }
              }
            }
          },
          "400": {
            "description": "bad_listing: The listing sent is not right. The sentence says which part: a missing title, an unknown property type or status. bad_photo: A photo could not be used: the address does not answer, is not a JPEG, PNG or WebP, is over 15 MB, or is not on the public internet. The sentence names the photo. too_many_photos: A listing can have up to 30 photos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "listingDelete",
        "summary": "Delete a listing",
        "description": "The listing and its photos are removed. Leads that asked about it stay in the inbox.",
        "tags": [
          "Listings"
        ],
        "externalDocs": {
          "url": "https://api.realtorflow.ca/#delete-listing"
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id."
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9cb5d6ac-fba8-4538-898b-c3309569fa5d",
                  "object": "listing",
                  "deleted": true
                }
              }
            }
          },
          "401": {
            "description": "no_key: No key was sent. Send it as Authorization: Bearer <key>. bad_key: The key is not one of ours. Copy it again from the Developers page. key_revoked: The key has been revoked. Make a new one on the Developers page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "403": {
            "description": "tool_off: The tool this call belongs to (Videos, Surveys, Leads, Listings, Bookings and so on) is not switched on for the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "404": {
            "description": "not_found: There is nothing with that id, or no such call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "description": "slow_down: Too many calls in a minute. Wait and try again; the RateLimit-Reset header says how many seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "key": {
        "type": "http",
        "scheme": "bearer",
        "description": "A live key (rf_live_...) or a test key (rf_test_...), made on the Developers page of the Realtor Flow dashboard. A test key saves nothing, sends nothing and is not counted."
      }
    },
    "schemas": {
      "Refusal": {
        "type": "object",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A sentence a person can read."
          },
          "code": {
            "type": "string",
            "description": "A short code a program can act on.",
            "enum": [
              "no_key",
              "bad_key",
              "key_revoked",
              "paused",
              "not_switched_on",
              "wrong_key",
              "browser_only",
              "domain_not_listed",
              "tool_off",
              "not_found",
              "bad_json",
              "too_large",
              "slow_down",
              "limit_reached",
              "try_later",
              "ai_off",
              "server_error",
              "bad_youtube_url",
              "no_transcript",
              "transcript_too_short",
              "transcript_too_long",
              "bad_page_url",
              "not_yours_to_delete",
              "bad_survey",
              "too_many_surveys",
              "no_prompt",
              "draft_failed",
              "survey_not_live",
              "bad_response",
              "bad_lead",
              "draft_too_short",
              "draft_too_long",
              "no_text",
              "text_too_long",
              "bad_language",
              "translation_failed",
              "bad_crawls",
              "bad_origin",
              "bad_listing_url",
              "bad_pages",
              "bad_terms",
              "bad_booking",
              "not_bookable",
              "dates_taken",
              "bad_status",
              "bad_kind",
              "bad_temperature",
              "bad_date",
              "nothing_to_change",
              "no_photo",
              "bad_upload",
              "file_too_large",
              "bad_alt",
              "media_full",
              "media_in_use",
              "bad_notes",
              "notes_too_long",
              "bad_subscriber",
              "no_consent",
              "bad_listing",
              "bad_photo",
              "too_many_photos",
              "too_many_listings"
            ]
          }
        }
      }
    }
  }
}