{
  "openapi": "3.1.0",
  "info": {
    "title": "ShowFirst API",
    "version": "2.0.0",
    "summary": "Find local businesses, build websites and preview sites for them, and share Online Presence Reports.",
    "description": "Every ShowFirst route in one file. Send requests to the same domain you use for your dashboard. Make keys on the API Keys page of your dashboard and send one as x-api-key or Authorization: Bearer. Account keys work on Websites, Reports and Prospecting. White-label agency keys (sf_agency_) work on client requests only.\n\nAnything that spends credits answers first with a plan and its cost, and starts only when the same request is sent again with \"confirm\": true.\n\nError responses have \"ok\": false and an error string. Validation errors also have a details list with one line per problem.\n\nThe readable guides: /docs/api-websites and /docs/api-prospecting. AI agents can use the MCP server at /docs/mcp and the skills at /docs/skills-websites and /docs/skills-prospecting.",
    "termsOfService": "https://showfirst.app/terms",
    "contact": {
      "name": "ShowFirst",
      "url": "https://showfirst.app/docs/"
    }
  },
  "servers": [
    {
      "url": "https://showfirst.app",
      "description": "Production. If your dashboard is on your own domain, use that domain instead."
    }
  ],
  "tags": [
    {
      "name": "Websites",
      "description": "Build a website for one business, make one-page preview sites for a whole list, change previews, and take client requests. Websites use website credits; preview batches use a plan's batch sites first."
    },
    {
      "name": "Reports",
      "description": "Shareable Online Presence Report links for businesses from your searches. Free."
    },
    {
      "name": "Prospecting",
      "description": "Find local businesses by kind and place, run one search across many places, page through results and export CSVs. Uses lead credits."
    },
    {
      "name": "Resources",
      "description": "Files for agents and tools."
    }
  ],
  "security": [
    {
      "BearerAuth": []
    },
    {
      "ApiKeyHeader": []
    }
  ],
  "paths": {
    "/api/websites/designs": {
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "listDesigns",
        "summary": "List designs",
        "description": "The designs a website or preview batch can use, with the picture the dashboard shows for each. No key is needed.",
        "responses": {
          "200": {
            "description": "The designs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesignList"
                },
                "example": {
                  "ok": true,
                  "designs": [
                    {
                      "design": "classic",
                      "name": "Classic",
                      "picture": "https://showfirst.app/img/look-picker/classic-2.jpg"
                    }
                  ]
                }
              }
            }
          }
        },
        "security": [
          {}
        ]
      }
    },
    "/api/websites/business-lookup": {
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "lookupBusiness",
        "summary": "Look a business up on Google",
        "description": "Send name (with city if you know it), phone or website to get matches and a lookup_session. Then send the chosen place_id with that lookup_session for its address, phone, hours and website, and pass google_place_id to Build a website. Free.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Business name as it shows on Google."
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Town or city."
          },
          {
            "name": "phone",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Phone."
          },
          {
            "name": "website",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Website."
          },
          {
            "name": "place_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "A place_id from an earlier match."
          },
          {
            "name": "lookup_session",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The lookup_session an earlier call returned."
          }
        ],
        "responses": {
          "200": {
            "description": "Matches, or one business.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LookupResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "400": {
            "$ref": "#/components/responses/Invalid"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "503": {
            "description": "Google lookup is not available right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "Google lookup is not available right now."
                }
              }
            }
          }
        }
      }
    },
    "/api/websites": {
      "post": {
        "tags": [
          "Websites"
        ],
        "operationId": "buildWebsite",
        "summary": "Build a website",
        "description": "Builds a full website for one business. Without confirm, the answer is the plan and its cost and nothing starts. Send the same body with \"confirm\": true to start. Cost: 1 website credit, given back if the build fails. Use from_search to build for a business from one of your searches.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebsiteRequest"
              },
              "example": {
                "business_name": "Harbor Plumbing",
                "design": "bold",
                "city": "Sarasota",
                "state": "FL",
                "confirm": true
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Started. Check its progress with Get a website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebsiteStarted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "200": {
            "description": "Without confirm: the plan. With confirm, when builds are paused: paused, nothing spent.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/WebsitePlan"
                    },
                    {
                      "$ref": "#/components/schemas/WebsitePaused"
                    }
                  ]
                },
                "example": {
                  "ok": true,
                  "requires_confirmation": true,
                  "plan": {
                    "business_name": "Harbor Plumbing",
                    "design": "bold",
                    "website_credits_needed": 1,
                    "website_credits_left": 3
                  },
                  "next": "Nothing has started. Send the same request with confirm: true to build it."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Invalid"
          },
          "403": {
            "$ref": "#/components/responses/NotEnough"
          },
          "404": {
            "description": "from_search names a business that is not in that search.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "That business is not in this search."
                }
              }
            }
          },
          "503": {
            "description": "Building is under maintenance. Nothing was spent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "New site generation is temporarily in maintenance mode."
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "listWebsites",
        "summary": "List your websites",
        "description": "Every website your account has built, newest first, a page at a time.",
        "parameters": [
          {
            "$ref": "#/components/parameters/offset"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of websites.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebsiteList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/websites/{websiteId}": {
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "getWebsite",
        "summary": "Get a website",
        "description": "How far a build has got and its preview link. Check every 15 to 30 seconds. The link works from preview_ready; pages and photos keep arriving until done.",
        "parameters": [
          {
            "$ref": "#/components/parameters/websiteId"
          }
        ],
        "responses": {
          "200": {
            "description": "The website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Website"
                },
                "example": {
                  "ok": true,
                  "website_id": "0c9b8a52-3d0e-4f7e-9d1d-2a6c7e1b5f10",
                  "name": "Harbor Plumbing",
                  "status": "preview_ready",
                  "step": "Adding service pages",
                  "progress_percent": 70,
                  "preview_url": "https://harbor-plumbing.example/",
                  "notes": [],
                  "error": null,
                  "preview_ready_at": "2026-11-09T18:02:11Z",
                  "done_at": null,
                  "credit_refunded": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/WebsiteNotFound"
          }
        }
      }
    },
    "/api/websites/batches": {
      "post": {
        "tags": [
          "Websites"
        ],
        "operationId": "createPreviewBatch",
        "summary": "Make a preview batch",
        "description": "A one-page preview site for every business in a list, or in one of your finished searches (from_search), up to 500. Without confirm, the answer is the plan and its cost. Cost: 1 batch site per business, at least 5. A plan's monthly batch sites are used first, then website credits. The cost comes back only if no preview in the batch gets built.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreviewBatchRequest"
              },
              "example": {
                "industry": "Plumbing",
                "design": "night",
                "from_search": {
                  "job_id": "6f1c2a9e-1b0d-4c55-9a51-0d6c1e1f7a20",
                  "has_website": false
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Without confirm: the plan. With confirm: the started batch.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PreviewBatchPlan"
                    },
                    {
                      "$ref": "#/components/schemas/PreviewBatchStarted"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "400": {
            "$ref": "#/components/responses/Invalid"
          },
          "403": {
            "$ref": "#/components/responses/NotEnough"
          }
        }
      },
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "listPreviewBatches",
        "summary": "List preview batches",
        "description": "Your account's preview batches, newest first.",
        "parameters": [
          {
            "$ref": "#/components/parameters/offset"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of batches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewBatchList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/websites/batches/{batchId}": {
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "getPreviewBatch",
        "summary": "Open a preview batch",
        "description": "One batch and every business's preview link and status.",
        "parameters": [
          {
            "$ref": "#/components/parameters/batchId"
          }
        ],
        "responses": {
          "200": {
            "description": "The batch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewBatch"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/BatchNotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Websites"
        ],
        "operationId": "restylePreviewBatch",
        "summary": "Restyle a preview batch",
        "description": "Change the batch's colour, background or logo size, or its language before it is built. Previews with their own colour or background keep it. Free.",
        "parameters": [
          {
            "$ref": "#/components/parameters/batchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestyleRequest"
              },
              "example": {
                "brand_color": "#1D4ED8",
                "background": "dark"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new settings and how many previews changed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "400": {
            "$ref": "#/components/responses/Invalid"
          },
          "404": {
            "$ref": "#/components/responses/BatchNotFound"
          },
          "409": {
            "description": "The language can only change before the batch is built.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "language can only change before the batch is generated."
                }
              }
            }
          }
        }
      }
    },
    "/api/websites/batches/{batchId}/results": {
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "previewBatchResults",
        "summary": "Download a preview batch",
        "description": "The previews as JSON (the same as Open a preview batch), format=csv for the spreadsheet the dashboard's Export button gives, with every preview link, or format=ghl for a GoHighLevel contact import: the GoHighLevel lead export's columns plus Preview Site (each business's preview link) and the tag showfirst-preview, one row per built preview.",
        "parameters": [
          {
            "$ref": "#/components/parameters/batchId"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv",
                "ghl"
              ]
            },
            "description": "json (default), csv or ghl (GoHighLevel import)."
          }
        ],
        "responses": {
          "200": {
            "description": "The previews.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewBatch"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/BatchNotFound"
          }
        }
      }
    },
    "/api/websites/batches/{batchId}/previews/{previewId}": {
      "patch": {
        "tags": [
          "Websites"
        ],
        "operationId": "updatePreview",
        "summary": "Change one preview",
        "description": "Change one preview's name, phone, email, address, logo, colour or background. Free.",
        "parameters": [
          {
            "$ref": "#/components/parameters/batchId"
          },
          {
            "$ref": "#/components/parameters/previewId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreviewChange"
              },
              "example": {
                "phone": "(941) 555-0102"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The preview as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "400": {
            "$ref": "#/components/responses/Invalid"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "description": "The batch or preview is unknown, or belongs to another account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "Preview not found."
                }
              }
            }
          }
        }
      }
    },
    "/api/websites/requests": {
      "post": {
        "tags": [
          "Websites"
        ],
        "operationId": "createClientRequest",
        "summary": "Save a client's website request",
        "description": "For agencies that take website requests from their own clients, with an agency key (sf_agency_). The request waits for Approve on your API Keys page, or builds now with build_now (1 website credit, the same rules as Build a website).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientRequest"
              },
              "example": {
                "business_name": "Client Roofing",
                "client_email": "owner@client.example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The saved request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientRequestStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AgencyUnauthorized"
          },
          "400": {
            "$ref": "#/components/responses/Invalid"
          },
          "403": {
            "$ref": "#/components/responses/NotEnough"
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/websites/requests/{requestId}": {
      "get": {
        "tags": [
          "Websites"
        ],
        "operationId": "getClientRequest",
        "summary": "Check a client's request",
        "description": "Whether the request was approved, and the build's progress and link. Same agency key.",
        "parameters": [
          {
            "$ref": "#/components/parameters/requestId"
          }
        ],
        "responses": {
          "200": {
            "description": "The request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientRequestStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AgencyUnauthorized"
          },
          "404": {
            "description": "Unknown request, or another account's.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "Request not found."
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/reports": {
      "post": {
        "tags": [
          "Reports"
        ],
        "operationId": "createReport",
        "summary": "Make an Online Presence Report link",
        "description": "A shareable report for one business from one of your finished searches: how it shows up online next to its top local competitors. Public facts only, never the owner's contact details. Asking again for the same business gives the same link unless new_link is true. Free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportRequest"
              },
              "example": {
                "job_id": "6f1c2a9e-1b0d-4c55-9a51-0d6c1e1f7a20",
                "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The report link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Report"
                },
                "example": {
                  "ok": true,
                  "report_url": "https://showfirst.app/report/r_8kq2m4",
                  "reused": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "400": {
            "$ref": "#/components/responses/Invalid"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "description": "The search or business is not one of yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "That business is not in this search."
                }
              }
            }
          }
        }
      }
    },
    "/api/prospecting/credits": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "getProspectingCredits",
        "summary": "Lead credits left",
        "description": "The account's lead credits, the same ones the Search tab uses.",
        "responses": {
          "200": {
            "description": "The balance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "lead_credits"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "lead_credits": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "lead_credits": 1400
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          }
        }
      }
    },
    "/api/prospecting/locations": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "findLocation",
        "summary": "Find a location",
        "description": "Place name to location_code. The best matches come first, up to 8.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A place name, such as Sarasota or Tampa, Florida.",
            "example": "Sarasota"
          }
        ],
        "responses": {
          "200": {
            "description": "Matching places, best first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "locations"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "locations": {
                      "type": "array",
                      "maxItems": 8,
                      "items": {
                        "$ref": "#/components/schemas/Location"
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "locations": [
                    {
                      "location_code": 1015192,
                      "location_name": "Sarasota,Florida,United States",
                      "location_type": "City"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "q is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "query is required, e.g. \"Tampa, Florida\"."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/categories": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "listCategories",
        "summary": "List business categories",
        "description": "The business kinds a search can be narrowed to with exact_category_key. Public: no key is needed. Send q to filter by name.",
        "security": [
          {}
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only categories whose name contains this text.",
            "example": "roof"
          }
        ],
        "responses": {
          "200": {
            "description": "The categories.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "categories"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "categories": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "key",
                          "name"
                        ],
                        "properties": {
                          "key": {
                            "type": "string",
                            "description": "The value to send as exact_category_key.",
                            "example": "roofing_contractor"
                          },
                          "name": {
                            "type": "string",
                            "example": "Roofing contractor"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "categories": [
                    {
                      "key": "roofing_contractor",
                      "name": "Roofing contractor"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/prospecting/searches": {
      "post": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "createSearch",
        "summary": "Plan or start a search",
        "description": "One kind of business in one place. Two phases: without confirm the reply is the plan (what the search would hold, and your balance) and nothing starts. Send the same request with \"confirm\": true to start it.\n\nA search holds 1 lead credit for each business it may return: its depth, or twice that with verify_emails on (the default). When it finishes you pay 1 per business found with a phone or website, plus 1 per verified email address when verify_emails is on, and the rest come back. With 1 to 99 lead credits left, a depth 100 search holds your balance and returns at most that many businesses (max_leads); with verify_emails on, a balance below 200 does the same and returns at most half your balance.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              },
              "examples": {
                "plan": {
                  "summary": "Get the plan",
                  "value": {
                    "keyword": "roofing contractor",
                    "location_code": 1015192,
                    "depth": 300
                  }
                },
                "start": {
                  "summary": "Start the search",
                  "value": {
                    "keyword": "roofing contractor",
                    "location_code": 1015192,
                    "depth": 300,
                    "confirm": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Without confirm: the plan. With confirm true: the started search and its job_id.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SearchPlanResponse"
                    },
                    {
                      "$ref": "#/components/schemas/SearchStarted"
                    }
                  ]
                },
                "examples": {
                  "plan": {
                    "summary": "The plan",
                    "value": {
                      "ok": true,
                      "requires_confirmation": true,
                      "plan": {
                        "keyword": "roofing contractor",
                        "location_code": 1015192,
                        "location_name": null,
                        "depth": 300,
                        "verify_emails": true,
                        "lead_credits_held": 600,
                        "lead_credits_balance": 1400
                      },
                      "next": "Nothing has started. Send the same request with confirm: true to run it."
                    }
                  },
                  "started": {
                    "summary": "Started",
                    "value": {
                      "ok": true,
                      "job_id": "6f1c2a9e-1b0d-4c55-9a51-0d6c1e1f7a20",
                      "status": "enriching",
                      "keyword": "roofing contractor",
                      "location_code": 1015192,
                      "depth": 300,
                      "lead_credits_held": 600
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A field is missing or invalid: keyword missing, a depth that is not 100, 300, 500 or 700, a radius_miles that is not 10, 25, 50 or 100, a website that is not any or none, or a verify_emails that is not true or false.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "depth must be one of 100, 300, 500, 700."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfLeadCredits"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "description": "No place matched location.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "No location matched \"Nowhere, ZZ\". Try \"City, State\" or a larger nearby city."
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          },
          "502": {
            "$ref": "#/components/responses/SearchServiceProblem"
          },
          "503": {
            "$ref": "#/components/responses/SearchServiceProblem"
          }
        }
      }
    },
    "/api/prospecting/searches/{jobId}": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "getSearch",
        "summary": "A search's progress",
        "description": "Poll every 10 to 20 seconds. A search usually takes a few minutes. Credits settle the first time a status check sees a final status, so keep polling until the search is done.",
        "parameters": [
          {
            "$ref": "#/components/parameters/jobId"
          }
        ],
        "responses": {
          "200": {
            "description": "The search's status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchJob"
                },
                "example": {
                  "job_id": "6f1c2a9e-1b0d-4c55-9a51-0d6c1e1f7a20",
                  "status": "completed",
                  "keyword": "roofing contractor",
                  "total_businesses": 212,
                  "enriched_count": 212,
                  "failed_count": 0,
                  "progress": 100
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "$ref": "#/components/responses/SearchNotFound"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/searches/{jobId}/results": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "getSearchResults",
        "summary": "A page of businesses, or a CSV",
        "description": "A page of businesses with the same fields as the results table in the Search tab, or a CSV file when format is a CSV format. The filters work the same way for both. Each business has 28 fields; see Business.",
        "parameters": [
          {
            "$ref": "#/components/parameters/jobId"
          },
          {
            "$ref": "#/components/parameters/offset"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/page_size"
          },
          {
            "$ref": "#/components/parameters/has_website"
          },
          {
            "$ref": "#/components/parameters/has_email"
          },
          {
            "$ref": "#/components/parameters/has_phone"
          },
          {
            "$ref": "#/components/parameters/has_mobile_phone"
          },
          {
            "$ref": "#/components/parameters/has_verified_email"
          },
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of businesses (format json), or a CSV file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultsPage"
                },
                "example": {
                  "ok": true,
                  "job_id": "6f1c2a9e-1b0d-4c55-9a51-0d6c1e1f7a20",
                  "total": 38,
                  "offset": 0,
                  "limit": 2,
                  "next_offset": 2,
                  "businesses": [
                    {
                      "name": "Gulf Coast Roof Repair",
                      "category": "Roofing contractor",
                      "website": null,
                      "email": "office@example.com",
                      "phone": "(941) 555-0142",
                      "owner": "Dana Ruiz",
                      "contact": {
                        "address": "1200 Main St",
                        "city": "Sarasota",
                        "state_code": "FL"
                      },
                      "reputation": {
                        "rating": 4.8,
                        "reviews": 61,
                        "is_claimed": true
                      },
                      "site_report": null
                    }
                  ]
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "example": "name,phone,email,website\nGulf Coast Roof Repair,(941) 555-0142,office@example.com,\n"
              }
            }
          },
          "400": {
            "description": "A filter or format value is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "format must be one of simple, advanced, ghl, instantly, batch."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "$ref": "#/components/responses/SearchNotFound"
          },
          "409": {
            "description": "The search has not finished yet. Keep polling.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "This search has not finished yet. Check search_status until it is completed."
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaigns": {
      "post": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "createCampaign",
        "summary": "Plan or start a campaign",
        "description": "One keyword across many places. Without confirm the reply is the plan: the lead estimate, about how long it takes, and lead_credits_held. With \"confirm\": true the campaign starts.\n\nA campaign holds places × depth_per_location, or max_leads if that is lower, twice that with verify_emails on. It settles the same way as a search when it finishes or is stopped. A campaign moves on to its next places each time you check it, so poll its results about once a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignCreateRequest"
              },
              "example": {
                "keyword": "plumber",
                "locations": [
                  "Tampa, Florida",
                  "Sarasota, Florida",
                  "Bradenton, Florida"
                ],
                "depth_per_location": 100,
                "max_leads": 250,
                "confirm": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Without confirm: the plan. With confirm true: the started campaign.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/CampaignPlanResponse"
                    },
                    {
                      "$ref": "#/components/schemas/CampaignStarted"
                    }
                  ]
                },
                "examples": {
                  "started": {
                    "summary": "Started",
                    "value": {
                      "ok": true,
                      "campaign_id": "b2a7f0de-55c1-4f0e-8d0b-3c0f7c1a9e44",
                      "lead_credits_held": 500
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A field is missing or invalid: keyword missing, neither location_codes nor locations sent, more than 200 locations, a depth_per_location that is not 100, 300, 500 or 700, a max_leads that is not a positive whole number, a website that is not any or none, or an idempotency_key that is not a UUID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "depth_per_location must be one of 100, 300, 500, 700."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfLeadCredits"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "description": "No place matched one of the locations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "No location matched \"Nowhere, ZZ\". Try \"City, State\" or a larger nearby city."
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          },
          "502": {
            "$ref": "#/components/responses/SearchServiceProblem"
          },
          "503": {
            "$ref": "#/components/responses/SearchServiceProblem"
          }
        }
      },
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "listCampaigns",
        "summary": "List campaigns",
        "description": "Your campaigns, newest first, with the same fields as a campaign's progress.",
        "responses": {
          "200": {
            "description": "Your campaigns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "campaigns"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "campaigns": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Campaign"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaigns/preview": {
      "post": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "previewCampaign",
        "summary": "Plan a campaign",
        "description": "The plan for a campaign, without starting it: the same answer as POST /api/prospecting/campaigns without confirm. Nothing is held.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignCreateRequest"
              },
              "example": {
                "keyword": "plumber",
                "locations": [
                  "Tampa, Florida",
                  "Sarasota, Florida"
                ],
                "depth_per_location": 100
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignPlanResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field is missing or invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "description": "No place matched one of the locations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaign-locations": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "listCampaignLocations",
        "summary": "Browse campaign locations",
        "description": "Places a campaign can cover, by country and region, as location codes. Use it to build the location_codes list for a campaign.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "A two-letter country code, such as US.",
            "example": "US"
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "A state or region code within the country, such as FL.",
            "example": "FL"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only places whose name contains this text.",
            "example": "Tampa"
          },
          {
            "$ref": "#/components/parameters/offset"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of places.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "locations"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "total": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "next_offset": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "locations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Location"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaigns/{campaignId}": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "getCampaign",
        "summary": "A campaign's progress",
        "description": "Each check also moves the campaign on to its next places, and the first check that sees a final status settles its lead credits. needs_attention means the campaign paused because your lead credits ran low: add credits, then resume it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "The campaign.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "$ref": "#/components/responses/CampaignNotFound"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaigns/{campaignId}/results": {
      "get": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "getCampaignResults",
        "summary": "Progress and a page of businesses, or a CSV",
        "description": "The campaign's progress plus a page of the businesses found so far (same offset, limit, filters and format as a search), or a CSV file when format is a CSV format. Poll about once a minute; stop when status is completed, stopped or failed. A campaign that has found nothing yet answers with an empty page.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campaignId"
          },
          {
            "$ref": "#/components/parameters/offset"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/page_size"
          },
          {
            "$ref": "#/components/parameters/has_website"
          },
          {
            "$ref": "#/components/parameters/has_email"
          },
          {
            "$ref": "#/components/parameters/has_phone"
          },
          {
            "$ref": "#/components/parameters/has_mobile_phone"
          },
          {
            "$ref": "#/components/parameters/has_verified_email"
          },
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Progress and a page of businesses (format json), or a CSV file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResultsPage"
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "A filter or format value is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "$ref": "#/components/responses/CampaignNotFound"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaigns/{campaignId}/pause": {
      "post": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "pauseCampaign",
        "summary": "Pause a campaign",
        "description": "Pauses a running campaign. Resume it with POST .../resume.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campaignId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CampaignActionDone"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "$ref": "#/components/responses/CampaignNotFound"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaigns/{campaignId}/resume": {
      "post": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "resumeCampaign",
        "summary": "Resume a paused campaign",
        "description": "Resumes a paused campaign, including one that paused with needs_attention after you added credits.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campaignId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CampaignActionDone"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "$ref": "#/components/responses/CampaignNotFound"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/campaigns/{campaignId}/stop": {
      "post": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "stopCampaign",
        "summary": "Stop a campaign for good",
        "description": "Stops the campaign. It cannot be resumed. Its lead credits settle on the next status check: you pay for what it found and the rest come back.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campaignId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CampaignActionDone"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "404": {
            "$ref": "#/components/responses/CampaignNotFound"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/api/prospecting/enrich": {
      "post": {
        "tags": [
          "Prospecting"
        ],
        "operationId": "enrichWebsites",
        "summary": "Look up websites",
        "description": "Finds emails, phones, social links and runs the website check for 1 to 10 websites you already have. 1 lead credit per website, held when the lookup starts and given back if it cannot start. Returns a job_id: poll GET /api/prospecting/searches/{jobId} and read GET .../results like a search. Send domains, or businesses when you know the names, or leads.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrichRequest"
              },
              "examples": {
                "domains": {
                  "summary": "Websites only",
                  "value": {
                    "domains": [
                      "gulfcoastroofing.com",
                      "https://www.example-plumbing.com"
                    ]
                  }
                },
                "businesses": {
                  "summary": "With names",
                  "value": {
                    "businesses": [
                      {
                        "business_name": "Gulf Coast Roofing",
                        "website": "gulfcoastroofing.com",
                        "phone": "(941) 555-0142"
                      }
                    ]
                  }
                },
                "leads": {
                  "summary": "With place",
                  "value": {
                    "leads": [
                      {
                        "domain": "gulfcoastroofing.com",
                        "business_name": "Gulf Coast Roofing",
                        "city": "Sarasota",
                        "state": "FL"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The lookup started. job_id is null and status completed when every website given is on your do-not-include list, in which case nothing is held.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "job_id",
                    "status",
                    "lead_credits_held"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "job_id": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "enriching",
                        "completed"
                      ]
                    },
                    "lead_credits_held": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "next": {
                      "type": "string"
                    }
                  },
                  "additionalProperties": true
                },
                "example": {
                  "ok": true,
                  "job_id": "0d4e9b61-7a2c-4c1e-9f35-5b8a2c6e1d07",
                  "status": "enriching",
                  "lead_credits_held": 2
                }
              }
            }
          },
          "400": {
            "description": "No websites were sent, more than 10 were sent, or an entry has no website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "At most 10 websites per call."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfLeadCredits"
          },
          "403": {
            "$ref": "#/components/responses/NoAccount"
          },
          "429": {
            "$ref": "#/components/responses/Busy"
          },
          "502": {
            "$ref": "#/components/responses/SearchServiceProblem"
          },
          "503": {
            "$ref": "#/components/responses/SearchServiceProblem"
          }
        }
      }
    },
    "/docs/skills/prospecting/SKILL.md": {
      "get": {
        "tags": [
          "Resources"
        ],
        "operationId": "getProspectingSkill",
        "summary": "The prospecting skill",
        "description": "A Markdown skill file that teaches a coding agent to use the Prospecting API and MCP tools: the confirm-first rule, the routes, and the credit arithmetic. No key is needed.",
        "security": [
          {}
        ],
        "responses": {
          "200": {
            "description": "The skill file.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/docs/skills/websites/SKILL.md": {
      "get": {
        "tags": [
          "Resources"
        ],
        "operationId": "getWebsitesSkill",
        "summary": "The websites skill",
        "description": "A Markdown skill file that teaches a coding agent to use the website API and MCP tools: the confirm-first rule, the routes and the costs. No key is needed.",
        "security": [
          {}
        ],
        "responses": {
          "200": {
            "description": "The skill file.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer YOUR_API_KEY. Make keys on the API Keys page of your dashboard. Account keys work everywhere except client requests; white-label agency keys begin with sf_agency_ and work on client requests only. The full key is shown once; treat it like a password."
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "The same key, sent as an x-api-key header instead of a bearer token."
      }
    },
    "parameters": {
      "batchId": {
        "name": "batchId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The batch_id."
      },
      "jobId": {
        "name": "jobId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "The job_id returned when a search or a website lookup started."
      },
      "campaignId": {
        "name": "campaignId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "The campaign_id returned when the campaign started."
      },
      "offset": {
        "name": "offset",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 0,
          "default": 0
        },
        "description": "Skip this many businesses. Use next_offset from the last page."
      },
      "limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        },
        "description": "Businesses per page, 1 to 100."
      },
      "page": {
        "name": "page",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "description": "Page number, starting at 1. Another way to say offset: page 2 with page_size 25 is offset 25."
      },
      "page_size": {
        "name": "page_size",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100
        },
        "description": "Businesses per page when you send page. Same range as limit."
      },
      "has_website": {
        "name": "has_website",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean"
        },
        "description": "true keeps only businesses whose Google listing shows a website, false only those without."
      },
      "has_email": {
        "name": "has_email",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean"
        },
        "description": "true keeps only businesses with an email address, false only those without."
      },
      "has_phone": {
        "name": "has_phone",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean"
        },
        "description": "true keeps only businesses with a phone number, false only those without."
      },
      "has_mobile_phone": {
        "name": "has_mobile_phone",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean"
        },
        "description": "true keeps only businesses with a mobile number, false only those without."
      },
      "has_verified_email": {
        "name": "has_verified_email",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean"
        },
        "description": "true keeps only businesses whose email passed the mailbox check (verified). Catch-all, unknown and unchecked emails are left out. false keeps the rest."
      },
      "format": {
        "name": "format",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "json",
            "simple",
            "advanced",
            "ghl",
            "instantly",
            "batch"
          ],
          "default": "json"
        },
        "description": "json (default) returns a page of businesses. The others return a CSV file: simple (the main columns), advanced (every column), ghl (ready to import into GoHighLevel), instantly (ready to import into Instantly), batch (ready for a ShowFirst preview batch)."
      },
      "websiteId": {
        "name": "websiteId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The website_id."
      },
      "previewId": {
        "name": "previewId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The preview_id from the batch."
      },
      "requestId": {
        "name": "requestId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The request_id."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The key is missing, unknown or revoked.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Missing or invalid API key."
            }
          }
        }
      },
      "AgencyUnauthorized": {
        "description": "The key is missing, not an agency key (sf_agency_), unknown or revoked.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Missing or invalid agency API key."
            }
          }
        }
      },
      "NoAccount": {
        "description": "The key is not linked to a ShowFirst account. Make a new key on the API Keys page.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "This API key is not linked to a ShowFirst account. Make a key on the API Keys page of the dashboard."
            }
          }
        }
      },
      "BatchNotFound": {
        "description": "The ID is unknown, or the batch belongs to another account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Batch not found."
            }
          }
        }
      },
      "SearchNotFound": {
        "description": "The search is unknown or belongs to another account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Search not found."
            }
          }
        }
      },
      "CampaignNotFound": {
        "description": "The campaign is unknown or belongs to another account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Campaign not found."
            }
          }
        }
      },
      "OutOfLeadCredits": {
        "description": "Not enough lead credits. Nothing started and nothing was held.",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Error"
                },
                {
                  "type": "object",
                  "properties": {
                    "balance": {
                      "type": "integer",
                      "description": "Your lead credits."
                    },
                    "required": {
                      "type": "integer",
                      "description": "What this request needs."
                    }
                  }
                }
              ]
            },
            "example": {
              "ok": false,
              "error": "You're out of lead credits.",
              "details": [
                "This search needs 300 lead credits; you have 120."
              ],
              "balance": 120,
              "required": 300
            }
          }
        }
      },
      "Busy": {
        "description": "The search service is busy. Wait a few seconds and send the request again. Keep to about one request a second.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "SearchServiceProblem": {
        "description": "The search service had a problem. Try again in a moment. Any credits held for a request that did not start came back.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "CampaignActionDone": {
        "description": "The action was applied. campaign is the campaign's status right after.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "ok"
              ],
              "properties": {
                "ok": {
                  "type": "boolean",
                  "const": true
                },
                "campaign": {
                  "$ref": "#/components/schemas/Campaign"
                }
              },
              "additionalProperties": true
            }
          }
        }
      },
      "WebsiteNotFound": {
        "description": "The ID is unknown, or the website belongs to another account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Website not found."
            }
          }
        }
      },
      "Invalid": {
        "description": "Something in the request is wrong. Nothing was started and nothing was spent.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Unknown field",
              "details": [
                "businessName: not a website field"
              ]
            }
          }
        }
      },
      "NotEnough": {
        "description": "Not enough credits, or the plan does not include batch sites. Nothing was started.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "Not enough website credits for this batch."
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every error body. details, when present, has one line per problem.",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string",
            "description": "What went wrong, in one sentence."
          },
          "details": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "One line per problem, on validation errors."
          }
        },
        "additionalProperties": true
      },
      "Location": {
        "type": "object",
        "description": "A place a search can cover.",
        "required": [
          "location_code",
          "location_name"
        ],
        "properties": {
          "location_code": {
            "type": "integer",
            "description": "Send as location_code (or in location_codes).",
            "example": 1015192
          },
          "location_name": {
            "type": "string",
            "example": "Sarasota,Florida,United States"
          },
          "location_type": {
            "type": "string",
            "example": "City"
          }
        },
        "additionalProperties": true
      },
      "Depth": {
        "type": "integer",
        "enum": [
          100,
          300,
          500,
          700
        ],
        "default": 100,
        "description": "How many businesses to look through."
      },
      "WebsiteFilter": {
        "type": "string",
        "enum": [
          "any",
          "none"
        ],
        "default": "any",
        "description": "none keeps only businesses whose Google listing shows no website; businesses whose listing shows one are left out and not charged. any keeps every business."
      },
      "SearchRequest": {
        "type": "object",
        "description": "Send keyword or exact_category_key, and location_code or location.",
        "properties": {
          "keyword": {
            "type": "string",
            "description": "The kind of business, e.g. roofing contractor. Required unless exact_category_key is sent.",
            "example": "roofing contractor"
          },
          "location_code": {
            "type": "integer",
            "description": "From GET /api/prospecting/locations.",
            "example": 1015192
          },
          "location": {
            "type": "string",
            "description": "A place as text, e.g. Sarasota, Florida. The best match is used.",
            "example": "Sarasota, Florida"
          },
          "depth": {
            "$ref": "#/components/schemas/Depth"
          },
          "radius_miles": {
            "type": "integer",
            "enum": [
              10,
              25,
              50,
              100
            ],
            "description": "Only keep businesses within this many miles."
          },
          "website": {
            "$ref": "#/components/schemas/WebsiteFilter"
          },
          "verify_emails": {
            "type": "boolean",
            "default": true,
            "description": "true checks each email address; each business whose address is verified costs 1 extra lead credit. false runs no email check: addresses come back as found, without a verified status, and only the business credit is charged."
          },
          "exact_category_key": {
            "type": "string",
            "description": "A category_key from GET /api/prospecting/categories. Keeps only businesses in exactly that category."
          },
          "confirm": {
            "type": "boolean",
            "default": false,
            "description": "Leave it out to get the plan without starting anything. true starts the search."
          }
        }
      },
      "SearchPlan": {
        "type": "object",
        "description": "What a search would hold, before it starts.",
        "required": [
          "keyword",
          "location_code",
          "location_name",
          "depth",
          "verify_emails",
          "lead_credits_held",
          "lead_credits_balance"
        ],
        "properties": {
          "keyword": {
            "type": "string"
          },
          "location_code": {
            "type": "integer"
          },
          "location_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "depth": {
            "$ref": "#/components/schemas/Depth"
          },
          "radius_miles": {
            "type": "integer",
            "enum": [
              10,
              25,
              50,
              100
            ]
          },
          "website": {
            "type": "string",
            "enum": [
              "none"
            ]
          },
          "verify_emails": {
            "type": "boolean"
          },
          "lead_credits_held": {
            "type": "integer",
            "description": "The hold confirm would place."
          },
          "max_leads": {
            "type": "integer",
            "description": "Present when your balance is below the full hold: the most businesses the search will return."
          },
          "lead_credits_balance": {
            "type": "integer"
          }
        }
      },
      "SearchPlanResponse": {
        "type": "object",
        "required": [
          "ok",
          "requires_confirmation",
          "plan"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "requires_confirmation": {
            "type": "boolean",
            "const": true
          },
          "plan": {
            "$ref": "#/components/schemas/SearchPlan"
          },
          "next": {
            "type": "string",
            "description": "What to do next, in plain words."
          }
        }
      },
      "SearchStarted": {
        "type": "object",
        "required": [
          "ok",
          "job_id",
          "status",
          "lead_credits_held"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "job_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "enriching"
            ]
          },
          "keyword": {
            "type": "string"
          },
          "location_code": {
            "type": "integer"
          },
          "location_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "depth": {
            "$ref": "#/components/schemas/Depth"
          },
          "lead_credits_held": {
            "type": "integer"
          },
          "max_leads": {
            "type": "integer"
          },
          "next": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "SearchJob": {
        "type": "object",
        "description": "A search's progress.",
        "required": [
          "job_id",
          "status"
        ],
        "properties": {
          "job_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "enriching",
              "completed",
              "no_results",
              "failed"
            ],
            "description": "enriching: still running, keep polling. completed: done, read the results. no_results: nothing matched; a search that finds nothing costs 10 credits and the rest of the hold came back. failed: the search stopped and unused credits came back."
          },
          "keyword": {
            "type": "string"
          },
          "total_businesses": {
            "type": "integer"
          },
          "enriched_count": {
            "type": "integer"
          },
          "failed_count": {
            "type": "integer"
          },
          "progress": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          }
        },
        "additionalProperties": true
      },
      "Business": {
        "type": "object",
        "description": "One business, with the same 28 fields as the results table in the Search tab. The example on the docs page is shortened; a real row has every field, with null where nothing was found.",
        "properties": {
          "name": {
            "type": "string"
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "website": {
            "type": [
              "string",
              "null"
            ],
            "description": "null when the Google listing shows no website."
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "owner": {
            "type": [
              "string",
              "null"
            ],
            "description": "The owner's name, where known."
          },
          "mobile_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "place_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Google Place ID."
          },
          "gbp_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Google Business Profile link."
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "description": "A short description of the business."
          },
          "greeting_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "A first name to open an email with."
          },
          "services": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "contact": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "address": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "city": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "state_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "postal_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "country_code": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "additionalProperties": true
          },
          "reputation": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "rating": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "reviews": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "is_claimed": {
                "type": [
                  "boolean",
                  "null"
                ]
              }
            },
            "additionalProperties": true
          },
          "web": {
            "type": [
              "object",
              "null"
            ],
            "description": "What the website check found.",
            "properties": {
              "tech": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                }
              },
              "socials": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "pages": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                }
              }
            },
            "additionalProperties": true
          },
          "site_report": {
            "type": [
              "object",
              "null"
            ],
            "description": "The website check, or null when there is no website.",
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "ResultsPage": {
        "type": "object",
        "description": "A page of businesses.",
        "required": [
          "ok",
          "job_id",
          "total",
          "offset",
          "limit",
          "next_offset",
          "businesses"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "job_id": {
            "type": "string",
            "format": "uuid"
          },
          "total": {
            "type": "integer",
            "description": "How many businesses match the filters."
          },
          "offset": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Send as offset for the next page. null on the last page."
          },
          "businesses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Business"
            }
          }
        }
      },
      "CampaignCreateRequest": {
        "type": "object",
        "description": "Send keyword or exact_category_key, and location_codes or locations.",
        "properties": {
          "keyword": {
            "type": "string",
            "description": "The kind of business. Required unless exact_category_key is sent.",
            "example": "plumber"
          },
          "location_codes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "items": {
              "type": "integer"
            },
            "description": "A list of location codes, up to 200."
          },
          "locations": {
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "items": {
              "type": "string"
            },
            "description": "A list of places as text; each uses its best match."
          },
          "depth_per_location": {
            "$ref": "#/components/schemas/Depth"
          },
          "max_leads": {
            "type": "integer",
            "minimum": 1,
            "description": "Stop after this many businesses in total."
          },
          "website": {
            "allOf": [
              {
                "$ref": "#/components/schemas/WebsiteFilter"
              }
            ],
            "description": "none keeps only businesses whose Google listing shows no website in every place."
          },
          "verify_emails": {
            "type": "boolean",
            "default": true,
            "description": "As in a search: true adds 1 lead credit per verified email address; false runs no email check."
          },
          "exact_category_key": {
            "type": "string",
            "description": "A category_key from GET /api/prospecting/categories. Keeps only businesses in exactly that category."
          },
          "name": {
            "type": "string",
            "description": "Shown in the Campaigns tab."
          },
          "confirm": {
            "type": "boolean",
            "default": false,
            "description": "Leave it out for the plan. true starts the campaign."
          },
          "idempotency_key": {
            "type": "string",
            "format": "uuid",
            "description": "A UUID. Sending the same one again does not start a second campaign."
          }
        }
      },
      "CampaignPlanResponse": {
        "type": "object",
        "description": "The plan for a campaign: the lead estimate, about how long it takes, and what confirm would hold.",
        "required": [
          "ok",
          "requires_confirmation",
          "location_codes",
          "depth_per_location",
          "max_leads",
          "verify_emails",
          "lead_credits_held",
          "lead_credits_balance"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "requires_confirmation": {
            "type": "boolean",
            "const": true
          },
          "location_codes": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "depth_per_location": {
            "$ref": "#/components/schemas/Depth"
          },
          "max_leads": {
            "type": [
              "integer",
              "null"
            ]
          },
          "verify_emails": {
            "type": "boolean"
          },
          "estimated_leads_low": {
            "type": "integer"
          },
          "estimated_leads_high": {
            "type": "integer"
          },
          "estimated_run_time_minutes": {
            "type": "number"
          },
          "total_planned_depth": {
            "type": "integer"
          },
          "lead_credits_held": {
            "type": "integer",
            "description": "places × depth_per_location, or max_leads if lower, twice that with verify_emails on."
          },
          "lead_credits_balance": {
            "type": "integer"
          },
          "next": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "CampaignStarted": {
        "type": "object",
        "required": [
          "ok",
          "campaign_id",
          "lead_credits_held"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "campaign_id": {
            "type": "string",
            "format": "uuid"
          },
          "lead_credits_held": {
            "type": "integer"
          },
          "next": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "Campaign": {
        "type": "object",
        "description": "A campaign's progress.",
        "required": [
          "campaign_id",
          "status"
        ],
        "properties": {
          "campaign_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "keyword": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "queued",
              "running",
              "paused",
              "needs_attention",
              "completed",
              "stopped",
              "failed"
            ],
            "description": "completed, stopped and failed are final. needs_attention: paused because your lead credits ran low; add credits, then resume."
          },
          "leads_found": {
            "type": "integer"
          },
          "location_count": {
            "type": "integer",
            "description": "How many places the campaign covers."
          },
          "locations_completed": {
            "type": "integer"
          },
          "depth_per_location": {
            "$ref": "#/components/schemas/Depth"
          },
          "max_leads": {
            "type": [
              "integer",
              "null"
            ]
          },
          "lead_credits_held": {
            "type": "integer"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "CampaignResultsPage": {
        "type": "object",
        "description": "The campaign's progress plus a page of the businesses found so far.",
        "required": [
          "ok",
          "campaign_id",
          "campaign",
          "total",
          "offset",
          "limit",
          "next_offset",
          "businesses"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "campaign_id": {
            "type": "string",
            "format": "uuid"
          },
          "campaign": {
            "$ref": "#/components/schemas/Campaign"
          },
          "total": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ]
          },
          "businesses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Business"
            }
          }
        }
      },
      "EnrichRequest": {
        "type": "object",
        "description": "Send one of domains, businesses or leads, with 1 to 10 entries.",
        "properties": {
          "domains": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "type": "string"
            },
            "description": "Website addresses, with or without https:// and www."
          },
          "businesses": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "type": "object",
              "required": [
                "website"
              ],
              "properties": {
                "business_name": {
                  "type": "string"
                },
                "website": {
                  "type": "string"
                },
                "phone": {
                  "type": "string"
                },
                "address": {
                  "type": "string"
                }
              }
            },
            "description": "When you know the names."
          },
          "leads": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "type": "object",
              "required": [
                "domain"
              ],
              "properties": {
                "domain": {
                  "type": "string"
                },
                "business_name": {
                  "type": "string"
                },
                "city": {
                  "type": "string"
                },
                "state": {
                  "type": "string"
                }
              }
            },
            "description": "When you know the place as well."
          }
        }
      },
      "Design": {
        "type": "string",
        "enum": [
          "classic",
          "bold",
          "night",
          "angle",
          "waterline"
        ],
        "description": "A website design. Left out, a website uses classic."
      },
      "DesignList": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "designs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "design": {
                  "$ref": "#/components/schemas/Design"
                },
                "name": {
                  "type": "string"
                },
                "picture": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          }
        }
      },
      "FromSearchBusiness": {
        "type": "object",
        "required": [
          "job_id",
          "place_id"
        ],
        "additionalProperties": false,
        "description": "One business from one of your finished searches. Its name, phone, email, website, address, category and Google place are filled in; any field you also send wins.",
        "properties": {
          "job_id": {
            "type": "string",
            "description": "A finished search's job_id."
          },
          "place_id": {
            "type": "string",
            "description": "That business's place_id in the search results."
          }
        }
      },
      "WebsiteRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "business_name": {
            "type": "string",
            "description": "Business name. The only required field (unless from_search is sent)."
          },
          "design": {
            "$ref": "#/components/schemas/Design"
          },
          "phone": {
            "type": "string",
            "description": "Phone. In the US, at least 10 digits."
          },
          "email": {
            "type": "string",
            "description": "Email."
          },
          "website": {
            "type": "string",
            "description": "The business's current website, http or https."
          },
          "address": {
            "type": "string",
            "description": "Full address, or just a town or service area."
          },
          "street": {
            "type": "string",
            "description": "Street address."
          },
          "city": {
            "type": "string",
            "description": "Town or city."
          },
          "state": {
            "type": "string",
            "description": "State or region."
          },
          "postal_code": {
            "type": "string",
            "description": "Postal code."
          },
          "country_code": {
            "type": "string",
            "description": "Two-letter country code, e.g. US."
          },
          "show_street_address": {
            "type": "boolean",
            "description": "false hides the street address and postal code on the site."
          },
          "industry": {
            "type": "string",
            "description": "What the business does, e.g. Plumbing."
          },
          "about": {
            "type": "string",
            "description": "A few sentences about the business."
          },
          "services": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Services offered."
          },
          "service_areas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Towns or areas served."
          },
          "hours": {
            "type": "string",
            "description": "Opening hours as text."
          },
          "google_place_id": {
            "type": "string",
            "description": "A Google place_id (from the business lookup). Name, address, phone and hours are filled in from Google."
          },
          "brand_color": {
            "type": "string",
            "pattern": "^#[0-9a-fA-F]{6}$",
            "description": "Six-digit hex colour, e.g. #2F6B55."
          },
          "logo_url": {
            "type": "string",
            "description": "Direct link to a logo image, http or https."
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "it",
              "ro",
              "tr"
            ],
            "description": "Site language. Default en."
          },
          "from_search": {
            "$ref": "#/components/schemas/FromSearchBusiness"
          },
          "confirm": {
            "type": "boolean",
            "description": "Leave out to get the plan and its cost. true starts the build."
          }
        }
      },
      "WebsitePlan": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "requires_confirmation": {
            "const": true
          },
          "plan": {
            "type": "object",
            "properties": {
              "business_name": {
                "type": "string"
              },
              "design": {
                "$ref": "#/components/schemas/Design"
              },
              "website_credits_needed": {
                "type": "integer"
              },
              "website_credits_left": {
                "type": "integer"
              }
            }
          },
          "next": {
            "type": "string"
          }
        }
      },
      "WebsiteStarted": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "started": {
            "type": "boolean"
          },
          "website_id": {
            "type": "string"
          },
          "status": {
            "const": "queued"
          },
          "preview_url": {
            "type": "null"
          },
          "website_credits_used": {
            "type": "integer"
          },
          "website_credits_left": {
            "type": "integer"
          },
          "next": {
            "type": "string"
          }
        }
      },
      "WebsitePaused": {
        "type": "object",
        "description": "Builds are paused for now. Nothing was queued and no credit was used.",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "started": {
            "const": false
          },
          "paused": {
            "const": true
          },
          "message": {
            "type": "string"
          },
          "website_credits_used": {
            "const": 0
          }
        }
      },
      "WebsiteStatusName": {
        "type": "string",
        "enum": [
          "queued",
          "building",
          "preview_ready",
          "finishing",
          "done",
          "failed"
        ],
        "description": "queued: waiting to start. building: being built. preview_ready: the preview link works; pages and photos are still being added. finishing: the last pages and photos. done: finished. failed: did not build; the credit is given back."
      },
      "Website": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "website_id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/WebsiteStatusName"
          },
          "step": {
            "type": [
              "string",
              "null"
            ]
          },
          "progress_percent": {
            "type": [
              "integer",
              "null"
            ]
          },
          "preview_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Things the build could not do, in plain words."
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "preview_ready_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "done_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "credit_refunded": {
            "type": "boolean"
          }
        }
      },
      "WebsiteList": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ]
          },
          "websites": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "website_id": {
                  "type": "string"
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "status": {
                  "$ref": "#/components/schemas/WebsiteStatusName"
                },
                "preview_url": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "domain": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "created_at": {
                  "type": "string"
                },
                "preview_ready_at": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "done_at": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          }
        }
      },
      "LookupResult": {
        "type": "object",
        "description": "With a name, phone or website: matches to choose from and a lookup_session. With a place_id: that business's details.",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "lookup_session": {
            "type": "string"
          },
          "matches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "place_id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "address": {
                  "type": "string"
                }
              }
            }
          },
          "business": {
            "type": "object",
            "additionalProperties": true
          },
          "next": {
            "type": "string"
          }
        }
      },
      "PreviewBusiness": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "business_name": {
            "type": "string",
            "description": "Name. Optional when google_place_id or google_cid is sent."
          },
          "google_place_id": {
            "type": "string",
            "description": "Google place_id; the details are filled in from Google when the batch runs."
          },
          "google_cid": {
            "type": "string",
            "description": "Google CID, the number in a ?cid= Maps link. Send this or google_place_id, not both."
          },
          "phone": {
            "type": "string",
            "description": "Phone."
          },
          "email": {
            "type": "string",
            "description": "Email."
          },
          "address": {
            "type": "string",
            "description": "Address."
          },
          "website": {
            "type": "string",
            "description": "Their current website."
          },
          "hours": {
            "type": "string",
            "description": "Hours as text."
          },
          "brand_color": {
            "type": "string",
            "description": "This preview's own colour, six-digit hex."
          },
          "logo_url": {
            "type": "string",
            "description": "Direct link to a logo."
          }
        }
      },
      "PreviewBatchRequest": {
        "type": "object",
        "additionalProperties": false,
        "description": "Send businesses, from_search, or both (up to 500 in all).",
        "properties": {
          "industry": {
            "type": "string",
            "description": "One industry for the whole batch, e.g. Plumbing. Default Home Services."
          },
          "design": {
            "$ref": "#/components/schemas/Design"
          },
          "brand_color": {
            "type": "string",
            "description": "Six-digit hex colour for every preview."
          },
          "background": {
            "type": "string",
            "enum": [
              "light",
              "dark"
            ]
          },
          "logo_size": {
            "type": "integer",
            "minimum": 48,
            "maximum": 160,
            "description": "Logo size in pixels. Default 88."
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "it",
              "ro",
              "tr"
            ]
          },
          "businesses": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "$ref": "#/components/schemas/PreviewBusiness"
            }
          },
          "from_search": {
            "type": "object",
            "required": [
              "job_id"
            ],
            "additionalProperties": false,
            "properties": {
              "job_id": {
                "type": "string",
                "description": "A finished search's job_id."
              },
              "has_website": {
                "type": "boolean",
                "description": "false keeps only businesses with no website."
              },
              "has_email": {
                "type": "boolean"
              },
              "has_phone": {
                "type": "boolean"
              },
              "max_businesses": {
                "type": "integer",
                "minimum": 1,
                "maximum": 500,
                "description": "Use at most this many. Default 500."
              }
            }
          },
          "confirm": {
            "type": "boolean",
            "description": "Leave out to get the plan and its cost. true starts the batch."
          }
        }
      },
      "PreviewBatchPlan": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "requires_confirmation": {
            "const": true
          },
          "plan": {
            "type": "object",
            "properties": {
              "businesses": {
                "type": "integer"
              },
              "design": {
                "$ref": "#/components/schemas/Design"
              },
              "industry": {
                "type": "string"
              },
              "batch_sites_from_plan": {
                "type": "integer"
              },
              "website_credits_needed": {
                "type": "integer"
              },
              "website_credits_left": {
                "type": "integer"
              },
              "from_search": {
                "type": "object"
              }
            }
          },
          "cost_rule": {
            "type": "string"
          },
          "next": {
            "type": "string"
          }
        }
      },
      "PreviewBatchStarted": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "started": {
            "const": true
          },
          "batch_id": {
            "type": "string"
          },
          "status": {
            "const": "queued"
          },
          "businesses": {
            "type": "integer"
          },
          "batch_sites_from_plan": {
            "type": "integer"
          },
          "website_credits_used": {
            "type": "integer"
          },
          "website_credits_left": {
            "type": [
              "integer",
              "null"
            ]
          },
          "next": {
            "type": "string"
          }
        }
      },
      "Preview": {
        "type": "object",
        "properties": {
          "preview_id": {
            "type": "string"
          },
          "business_name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "preview_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "brand_color": {
            "type": [
              "string",
              "null"
            ]
          },
          "background": {
            "type": [
              "string",
              "null"
            ]
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PreviewBatch": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "batch_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "pending, queued, processing, completed or failed."
          },
          "industry": {
            "type": "string"
          },
          "design": {
            "$ref": "#/components/schemas/Design"
          },
          "brand_color": {
            "type": "string"
          },
          "background": {
            "type": "string"
          },
          "logo_size": {
            "type": "integer"
          },
          "language": {
            "type": "string"
          },
          "businesses": {
            "type": "integer"
          },
          "preview_expires_on": {
            "type": [
              "string",
              "null"
            ],
            "description": "Previews stop showing after this date unless the batch is published."
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "previews": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Preview"
            }
          }
        }
      },
      "PreviewBatchList": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ]
          },
          "batches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "batch_id": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "description": "pending, queued, processing, completed or failed."
                },
                "industry": {
                  "type": "string"
                },
                "design": {
                  "$ref": "#/components/schemas/Design"
                },
                "brand_color": {
                  "type": "string"
                },
                "background": {
                  "type": "string"
                },
                "logo_size": {
                  "type": "integer"
                },
                "language": {
                  "type": "string"
                },
                "businesses": {
                  "type": "integer"
                },
                "preview_expires_on": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Previews stop showing after this date unless the batch is published."
                },
                "error": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "created_at": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "RestyleRequest": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "brand_color": {
            "type": "string",
            "description": "Six-digit hex colour."
          },
          "background": {
            "type": "string",
            "enum": [
              "light",
              "dark"
            ]
          },
          "logo_size": {
            "type": "integer",
            "minimum": 48,
            "maximum": 160
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "it",
              "ro",
              "tr"
            ],
            "description": "Only before the batch is built."
          }
        }
      },
      "PreviewChange": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "description": "Send only what changes. null clears a field.",
        "properties": {
          "business_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "brand_color": {
            "type": [
              "string",
              "null"
            ]
          },
          "background": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "light",
              "dark",
              null
            ]
          }
        }
      },
      "ReportRequest": {
        "type": "object",
        "required": [
          "job_id",
          "place_id"
        ],
        "additionalProperties": false,
        "properties": {
          "job_id": {
            "type": "string",
            "description": "The finished search the business came from."
          },
          "place_id": {
            "type": "string",
            "description": "The business's place_id in that search."
          },
          "website_url": {
            "type": "string",
            "description": "Optional: a website you built for them, shown on the report (http or https)."
          },
          "new_link": {
            "type": "boolean",
            "description": "true makes a new link even if this business already has one."
          }
        }
      },
      "Report": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "report_url": {
            "type": "string",
            "format": "uri"
          },
          "reused": {
            "type": "boolean"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "ClientRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "client_email"
        ],
        "properties": {
          "business_name": {
            "type": "string",
            "description": "Business name. The only required field (unless from_search is sent)."
          },
          "design": {
            "$ref": "#/components/schemas/Design"
          },
          "phone": {
            "type": "string",
            "description": "Phone. In the US, at least 10 digits."
          },
          "email": {
            "type": "string",
            "description": "Email."
          },
          "website": {
            "type": "string",
            "description": "The business's current website, http or https."
          },
          "address": {
            "type": "string",
            "description": "Full address, or just a town or service area."
          },
          "street": {
            "type": "string",
            "description": "Street address."
          },
          "city": {
            "type": "string",
            "description": "Town or city."
          },
          "state": {
            "type": "string",
            "description": "State or region."
          },
          "postal_code": {
            "type": "string",
            "description": "Postal code."
          },
          "country_code": {
            "type": "string",
            "description": "Two-letter country code, e.g. US."
          },
          "show_street_address": {
            "type": "boolean",
            "description": "false hides the street address and postal code on the site."
          },
          "industry": {
            "type": "string",
            "description": "What the business does, e.g. Plumbing."
          },
          "about": {
            "type": "string",
            "description": "A few sentences about the business."
          },
          "services": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Services offered."
          },
          "service_areas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Towns or areas served."
          },
          "hours": {
            "type": "string",
            "description": "Opening hours as text."
          },
          "google_place_id": {
            "type": "string",
            "description": "A Google place_id (from the business lookup). Name, address, phone and hours are filled in from Google."
          },
          "brand_color": {
            "type": "string",
            "pattern": "^#[0-9a-fA-F]{6}$",
            "description": "Six-digit hex colour, e.g. #2F6B55."
          },
          "logo_url": {
            "type": "string",
            "description": "Direct link to a logo image, http or https."
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "it",
              "ro",
              "tr"
            ],
            "description": "Site language. Default en."
          },
          "client_email": {
            "type": "string",
            "description": "The client's email. Saved as the business email; we never write to it."
          },
          "build_now": {
            "type": "boolean",
            "description": "true builds now (1 website credit). Otherwise the request waits for Approve on your API Keys page."
          }
        }
      },
      "ClientRequestStatus": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "request_id": {
            "type": "string"
          },
          "business_name": {
            "type": "string"
          },
          "client_email": {
            "type": "string"
          },
          "approval": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected"
            ]
          },
          "status": {
            "type": "string",
            "description": "awaiting_approval, rejected, or the build's status (see WebsiteStatusName)."
          },
          "website_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "website_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "preview_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "progress_percent": {
            "type": "integer"
          },
          "step": {
            "type": [
              "string",
              "null"
            ]
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "decided_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    }
  }
}
