{
  "openapi": "3.1.0",
  "info": {
    "title": "LeadMarina API",
    "version": "1.0.0",
    "summary": "Verified local-business leads: search any niche and city, poll for checked contacts, export to your CRM.",
    "description": "Search local businesses by niche and city and get their contacts checked — emails checked for deliverability, phones for line type and carrier — then send them to Close, GoHighLevel, Google Sheets or a file. One lead covers a listing and all of its verification; lookups, reads and exports are free.\n\nAuthenticate with an API key from https://leadmarina.com/dashboard/api-keys, sent as `Authorization: Bearer <key>` (or the `x-api-key` header). Each key may make 120 requests a minute; see https://leadmarina.com/docs/limits for every limit and https://leadmarina.com/docs/errors for every status code.\n\nThe same account also works over MCP at https://leadmarina.com/api/mcp (https://leadmarina.com/docs/mcp).",
    "termsOfService": "https://leadmarina.com/terms",
    "contact": {
      "name": "LeadMarina support",
      "url": "https://leadmarina.com/docs",
      "email": "support@leadmarina.com"
    }
  },
  "externalDocs": {
    "description": "LeadMarina API docs",
    "url": "https://leadmarina.com/docs"
  },
  "servers": [
    {
      "url": "https://leadmarina.com"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "apiKeyHeader": []
    }
  ],
  "tags": [
    {
      "name": "Search",
      "description": "Find businesses and poll for their verified contacts."
    },
    {
      "name": "Enrich",
      "description": "Verify domains you already have."
    },
    {
      "name": "Leads",
      "description": "Read everything you have collected."
    },
    {
      "name": "Export",
      "description": "Send leads to a CRM, a spreadsheet or a file."
    },
    {
      "name": "Automations",
      "description": "Scheduled searches that export themselves."
    },
    {
      "name": "Campaigns",
      "description": "Advanced search: many keywords across many places, each business charged once."
    }
  ],
  "paths": {
    "/api/v1/locations": {
      "get": {
        "operationId": "lookupLocations",
        "tags": [
          "Search"
        ],
        "summary": "Look up locations",
        "description": "Fuzzy city search returning the location_code values POST /api/v1/search accepts. Free — no leads spent. Fewer than 2 characters returns an empty list.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Part of a city name, at least 2 characters.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "locations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Location"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Query is too long.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/search": {
      "post": {
        "operationId": "search",
        "tags": [
          "Search"
        ],
        "summary": "Search for businesses",
        "description": "Runs a live local-business search for US places and returns the first batch of listings, spending 1 lead per result. More matching leads are found and verified in the background — up to 3 emails and 3 phones checked per lead, plus the owner name where one is found. Poll GET /api/v1/searches/{search_id} until enrichment is \"complete\". When discovery is \"in_progress\", results is empty for now and the leads arrive on the poll endpoint.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query"
                ],
                "properties": {
                  "query": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "The niche or keyword, e.g. \"electrician\"."
                  },
                  "location": {
                    "type": "string",
                    "description": "City string, e.g. \"Austin, TX\". Or send location_code."
                  },
                  "location_code": {
                    "type": "integer",
                    "description": "Exact code from GET /api/v1/locations. When sent, that code is what is searched, whatever location says."
                  },
                  "exact_category": {
                    "type": [
                      "boolean",
                      "string"
                    ],
                    "description": "true — the query must then BE a listing category, such as \"Plumber\" — or that category's id (\"plumber\"). Only businesses whose MAIN category is that one are kept. Runs in the background."
                  },
                  "max_leads": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 1000000,
                    "description": "Stop after this many leads."
                  },
                  "country": {
                    "type": "string",
                    "description": "\"US\" (the default), or a US territory's code — \"PR\", \"GU\", \"VI\", \"AS\" or \"MP\" — with places from GET /api/v1/places?country=PR. Any other country is a 403 (a 400 for one no search may target), and nothing is searched or charged."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchStarted"
                }
              }
            }
          },
          "400": {
            "description": "A body the API can't use: no query, a location outside the US, or an invalid option.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Not enough leads left.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A country this account can't search yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Every place asked for was already searched for this keyword recently, on an account that takes each business only once.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/searches": {
      "get": {
        "operationId": "listSearches",
        "tags": [
          "Search"
        ],
        "summary": "List searches",
        "description": "Your searches, newest first, with each one's stage. A campaign's batches are left out unless include_campaign_batches=true.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Up to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Rows to skip.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "stage",
            "in": "query",
            "required": false,
            "description": "Only searches at this stage; total then counts those.",
            "schema": {
              "$ref": "#/components/schemas/Stage"
            }
          },
          {
            "name": "include_campaign_batches",
            "in": "query",
            "required": false,
            "description": "Include a campaign's batches, each with its campaign_id.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "searches": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "search_id": {
                            "type": "string"
                          },
                          "campaign_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "With include_campaign_batches only."
                          },
                          "query": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "location": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "result_count": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "stage": {
                            "$ref": "#/components/schemas/Stage"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/searches/{search_id}": {
      "get": {
        "operationId": "getSearch",
        "tags": [
          "Search"
        ],
        "summary": "Get a search (poll for results)",
        "description": "Results with verification filled in as it progresses, one page at a time in rank order. Poll every 30–60 seconds until enrichment is \"complete\" — every charge has then settled and credits_remaining is final. Read stage for what is happening. To read every lead, keep calling with offset set to next_offset until it comes back null.",
        "parameters": [
          {
            "name": "search_id",
            "in": "path",
            "required": true,
            "description": "The search's id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, up to 1,000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Where the page starts.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Search not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "delete": {
        "operationId": "cancelSearch",
        "tags": [
          "Search"
        ],
        "summary": "Cancel a queued search",
        "description": "Cancels a search that is still queued: its un-enriched rows are removed and refunded. A search already running is left to finish (409, with the current stage).",
        "parameters": [
          {
            "name": "search_id",
            "in": "path",
            "required": true,
            "description": "The search's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "search_id": {
                      "type": "string"
                    },
                    "stage": {
                      "type": "string",
                      "const": "cancelled"
                    },
                    "removed": {
                      "type": "integer"
                    },
                    "refunded_credits": {
                      "type": "integer"
                    },
                    "kept_leads": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "credits_remaining": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "credits_window": {
                      "$ref": "#/components/schemas/CreditsWindow"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Search not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Already running, or nothing to cancel.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/enrich": {
      "post": {
        "operationId": "enrichDomains",
        "tags": [
          "Enrich"
        ],
        "summary": "Enrich by domain",
        "description": "Verify up to 10 business domains you already have — no search required. 1 lead per distinct domain; spellings of the same site are one domain, charged once. US businesses only for now. Returns a search_id to poll like a search.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "leads"
                ],
                "properties": {
                  "leads": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 10,
                    "items": {
                      "type": "object",
                      "required": [
                        "domain"
                      ],
                      "properties": {
                        "domain": {
                          "type": "string",
                          "description": "e.g. \"acme.com\"."
                        },
                        "business_name": {
                          "type": "string",
                          "description": "Improves accuracy."
                        },
                        "city": {
                          "type": "string"
                        },
                        "state": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "country": {
                    "type": "string",
                    "description": "Leave it out, or send the US; any other country is a 400 and nothing is charged."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "search_id": {
                      "type": "string"
                    },
                    "delivered": {
                      "type": "integer",
                      "description": "Distinct domains enriched and charged."
                    },
                    "credits_remaining": {
                      "type": "integer"
                    },
                    "enrichment": {
                      "type": "string",
                      "const": "pending"
                    },
                    "poll": {
                      "type": "string"
                    },
                    "note": {
                      "type": "string",
                      "description": "Names repeats, and domains your balance did not cover."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A body the API can't use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Not enough leads left.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/leads": {
      "get": {
        "operationId": "listLeads",
        "tags": [
          "Leads"
        ],
        "summary": "List your leads",
        "description": "Every business you have collected, once each as its newest row, newest first. Free — no leads spent. For volume, use POST /api/v1/exports.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, up to 2,500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2500,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Where the page starts.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "returned": {
                      "type": "integer"
                    },
                    "next_offset": {
                      "type": [
                        "integer",
                        "null"
                      ],
                      "description": "Pass as offset for the next page; null on the last."
                    },
                    "leads": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Lead"
                      }
                    },
                    "data_sources": {
                      "type": "string",
                      "format": "uri",
                      "description": "Present when some of these leads' emails or owner names may come from open datasets and public records: the page with their sources, licences and notices (also sent as a Link header, rel=\"license\"). Pass it on with any of this data you share."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/exports": {
      "post": {
        "operationId": "exportLeads",
        "tags": [
          "Export"
        ],
        "summary": "Export leads",
        "description": "The bulk path: push leads to a CRM, a spreadsheet or a file. Free — you already paid for these leads. Per call: 50,000 for csv/xlsx, 25,000 for json, 5,000 for google_sheets, 1,000 for close or ghl. When more leads match, the response carries truncated, a warning and next_cursor: call again with the same selection and cursor set to it (for google_sheets also the spreadsheet_id the response returns, or each batch makes a new spreadsheet; up to 50,000 leads a spreadsheet). Close and GoHighLevel update leads exported before, matched on cid.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "destination"
                ],
                "properties": {
                  "destination": {
                    "type": "string",
                    "enum": [
                      "close",
                      "ghl",
                      "google_sheets",
                      "csv",
                      "xlsx",
                      "json"
                    ]
                  },
                  "search_id": {
                    "type": "string",
                    "description": "Export one search's leads."
                  },
                  "all": {
                    "type": "boolean",
                    "description": "Or export the whole library."
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "Or export one campaign's leads — not with search_id."
                  },
                  "filters": {
                    "type": "array",
                    "maxItems": 100,
                    "description": "Filter rows. Fields and the operators each type takes — text fields [operators: contains, not_contains, is, is_not, is_empty, is_not_empty]: name, category, city, state, country, postal_code, address, website, primary_email (or email_1), email_2, email_3, primary_phone (or phone_1), phone_carrier (or phone_1_carrier), phone_2, phone_2_carrier, phone_3, phone_3_carrier, owner_name, contact_name, contact_title, social_facebook, social_instagram, social_linkedin, social_x, social_youtube, social_tiktok, social_yelp, gbp_url, google_cid, logo_url, main_image_url. number fields [operators: eq, neq, gt, gte, lt, lte, is_empty, is_not_empty]: rank, rating, reviews, people. yes/no fields [operators: is_true, is_false, is_empty, is_not_empty]: claimed. choice fields [operators: is, is_not, is_empty, is_not_empty]: website_status take none (No website), live, unreachable, blocked (Blocked our crawler), unknown, pending; email_status (or email_1_status), email_2_status, email_3_status take safe, risky, invalid, unknown; phone_line_type (or phone_1_type), phone_2_type, phone_3_type take mobile, fixed_line (Landline), fixed_line_or_mobile (Landline or mobile), voip, non_fixed_voip, toll_free (Toll-free), premium_rate, shared_cost, personal_number (Personal), pager, uan, voicemail, unknown. A field, operator or value the API can't use is a 400 that names it.",
                    "items": {
                      "type": "object",
                      "required": [
                        "field",
                        "operator"
                      ],
                      "properties": {
                        "field": {
                          "type": "string"
                        },
                        "operator": {
                          "type": "string",
                          "description": "A test the field's type takes. Case is ignored."
                        },
                        "value": {
                          "description": "Text, a number, or one of a choice field's values. is_empty, is_not_empty, is_true and is_false take none."
                        },
                        "conj": {
                          "type": "string",
                          "enum": [
                            "and",
                            "or"
                          ],
                          "description": "Joins the row to the one before it. \"and\" binds tighter."
                        }
                      }
                    }
                  },
                  "spreadsheet_id": {
                    "type": "string",
                    "description": "google_sheets only: add to a spreadsheet an earlier export created, updating the leads it holds."
                  },
                  "sheet_title": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "google_sheets without spreadsheet_id: the new spreadsheet's title."
                  },
                  "update_existing": {
                    "type": "boolean",
                    "description": "close, and google_sheets with spreadsheet_id: true (the default) refreshes leads already there. false: Close sends only leads it hasn't had yet; a sheet appends every lead as a new row."
                  },
                  "cursor": {
                    "type": "string",
                    "description": "The next_cursor a previous call returned, with the same selection and filters."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportResult"
                }
              }
            }
          },
          "400": {
            "description": "A request that can't run as sent, or a destination that isn't connected or set up. The message says what to do.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Search not found, or Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/schedules": {
      "get": {
        "operationId": "listAutomations",
        "tags": [
          "Automations"
        ],
        "summary": "List automations",
        "description": "Your scheduled searches, with cadence, destination, next run and last result.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schedules": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Schedule"
                      }
                    },
                    "data_sources": {
                      "type": "string",
                      "format": "uri",
                      "description": "Present when some of these leads' emails or owner names may come from open datasets and public records: the page with their sources, licences and notices (also sent as a Link header, rel=\"license\"). Pass it on with any of this data you share."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "post": {
        "operationId": "createAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Create an automation",
        "description": "Re-run a search on a cadence and send each run's leads to a destination. Every run spends leads — one per result, as a manual search does. A close, ghl or google_sheets destination is checked now: not connected is a 400 right away. US places only for now.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "keyword",
                  "locations",
                  "cadence"
                ],
                "properties": {
                  "keyword": {
                    "type": "string",
                    "description": "The niche, e.g. \"roofing contractor\"."
                  },
                  "locations": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 25,
                    "description": "Cities as strings, or { location_code, location_name } objects. Every city string must be found, or nothing is saved and the 400 names it.",
                    "items": {
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "object",
                          "required": [
                            "location_code"
                          ],
                          "properties": {
                            "location_code": {
                              "type": "integer",
                              "minimum": 1
                            },
                            "location_name": {
                              "type": "string"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "cadence": {
                    "type": "string",
                    "enum": [
                      "once",
                      "daily",
                      "weekly",
                      "monthly",
                      "yearly"
                    ]
                  },
                  "destination": {
                    "description": "Where each run's leads go; omit or null to save them to your library only.",
                    "oneOf": [
                      {
                        "type": "string",
                        "enum": [
                          "none",
                          "csv",
                          "xlsx",
                          "json",
                          "ghl",
                          "close",
                          "google_sheets"
                        ]
                      },
                      {
                        "$ref": "#/components/schemas/ScheduleDestinationInput"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "spreadsheet_id": {
                    "type": "string",
                    "description": "With google_sheets: add each run to this spreadsheet."
                  },
                  "start_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "First run (ISO 8601). Omitted, null or past means the next tick. At most 2 years ahead."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "locations": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "location_code": {
                            "type": "integer"
                          },
                          "location_name": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "destination": {
                      "$ref": "#/components/schemas/ScheduleDestination"
                    },
                    "next_run_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "data_sources": {
                      "type": "string",
                      "format": "uri",
                      "description": "Present when some of these leads' emails or owner names may come from open datasets and public records: the page with their sources, licences and notices (also sent as a Link header, rel=\"license\"). Pass it on with any of this data you share."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A body the API can't use; nothing was saved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/schedules/{id}": {
      "patch": {
        "operationId": "setAutomationActive",
        "tags": [
          "Automations"
        ],
        "summary": "Pause or resume an automation",
        "description": "Pausing keeps the automation but stops it running and spending, and cancels any run still waiting in the queue.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "active"
                ],
                "properties": {
                  "active": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "active": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Pass { \"active\": true } or { \"active\": false }.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Automation not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A one-time automation whose run is still in progress can't be resumed: it finishes by itself.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "delete": {
        "operationId": "deleteAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Delete an automation",
        "description": "Deletes it and cancels any run still waiting. Leads collected by past runs are kept.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Automation not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/countries": {
      "get": {
        "operationId": "listCountries",
        "tags": [
          "Campaigns"
        ],
        "summary": "List searchable countries",
        "description": "Every country and territory a search can run in, A–Z. Free.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "countries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Country"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/places": {
      "get": {
        "operationId": "findPlaces",
        "tags": [
          "Campaigns"
        ],
        "summary": "Find places",
        "description": "Without q: the country's regions. With q (at least 2 characters): places whose name contains it, names that start with it first, up to 50. Each code is one a campaign's places or a single search's location_code takes. Free.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO code; the US when left out.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Part of a place name.",
            "schema": {
              "type": "string",
              "minLength": 2
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RegionList"
                    },
                    {
                      "$ref": "#/components/schemas/PlaceMatches"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Unknown country, or a query too short.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "A country this account can't search yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/campaigns/estimate": {
      "post": {
        "operationId": "estimateCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Estimate a campaign",
        "description": "What a campaign would find and how long it would take, without starting it or spending anything.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "keywords"
                ],
                "properties": {
                  "keywords": {
                    "type": "array",
                    "maxItems": 20,
                    "description": "Up to 20, each up to 100 characters: a string, or { keyword, exact } to keep only that category. Repeats are searched once.",
                    "items": {
                      "oneOf": [
                        {
                          "type": "string",
                          "maxLength": 100
                        },
                        {
                          "type": "object",
                          "required": [
                            "keyword"
                          ],
                          "properties": {
                            "keyword": {
                              "type": "string",
                              "maxLength": 100
                            },
                            "exact": {
                              "type": "boolean"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "country": {
                    "type": "string",
                    "description": "\"US\" (the default), or a US territory's code — \"PR\", \"GU\", \"VI\", \"AS\" or \"MP\" — with places from GET /api/v1/places?country=PR. Any other country is a 403 (a 400 for one no search may target), and nothing is searched or charged."
                  },
                  "everywhere": {
                    "type": "boolean",
                    "description": "Every place in the US."
                  },
                  "regions": {
                    "type": "array",
                    "items": {
                      "type": [
                        "string",
                        "integer"
                      ]
                    },
                    "description": "Whole states, by name or code."
                  },
                  "places": {
                    "type": "array",
                    "items": {
                      "type": [
                        "string",
                        "integer"
                      ]
                    },
                    "description": "Single places: a name, \"name, region\" when a name is in several regions, or a code from /places. Up to 25,000 regions and places together, and keywords × places at most 50,000 searches."
                  },
                  "lead_cap": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 1000000,
                    "description": "Stop after this many unique, charged leads. Leave it out to search every place."
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 80
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignEstimate"
                }
              }
            }
          },
          "400": {
            "description": "The body can't be planned as sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "A country this account can't search yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/campaigns": {
      "get": {
        "operationId": "listCampaigns",
        "tags": [
          "Campaigns"
        ],
        "summary": "List campaigns",
        "description": "Your campaigns, newest first.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Up to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "campaigns": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Campaign"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "post": {
        "operationId": "startCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Start a campaign",
        "description": "Many keywords across whole states or single places, run in the background in batches. Each unique business spends 1 lead however many keywords or places find it, and it stops at lead_cap if set.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "keywords"
                ],
                "properties": {
                  "keywords": {
                    "type": "array",
                    "maxItems": 20,
                    "description": "Up to 20, each up to 100 characters: a string, or { keyword, exact } to keep only that category. Repeats are searched once.",
                    "items": {
                      "oneOf": [
                        {
                          "type": "string",
                          "maxLength": 100
                        },
                        {
                          "type": "object",
                          "required": [
                            "keyword"
                          ],
                          "properties": {
                            "keyword": {
                              "type": "string",
                              "maxLength": 100
                            },
                            "exact": {
                              "type": "boolean"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "country": {
                    "type": "string",
                    "description": "\"US\" (the default), or a US territory's code — \"PR\", \"GU\", \"VI\", \"AS\" or \"MP\" — with places from GET /api/v1/places?country=PR. Any other country is a 403 (a 400 for one no search may target), and nothing is searched or charged."
                  },
                  "everywhere": {
                    "type": "boolean",
                    "description": "Every place in the US."
                  },
                  "regions": {
                    "type": "array",
                    "items": {
                      "type": [
                        "string",
                        "integer"
                      ]
                    },
                    "description": "Whole states, by name or code."
                  },
                  "places": {
                    "type": "array",
                    "items": {
                      "type": [
                        "string",
                        "integer"
                      ]
                    },
                    "description": "Single places: a name, \"name, region\" when a name is in several regions, or a code from /places. Up to 25,000 regions and places together, and keywords × places at most 50,000 searches."
                  },
                  "lead_cap": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 1000000,
                    "description": "Stop after this many unique, charged leads. Leave it out to search every place."
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 80
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignDetail"
                }
              }
            }
          },
          "400": {
            "description": "The body can't be planned as sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Not enough leads left.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A country this account can't search yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/campaigns/{id}": {
      "get": {
        "operationId": "getCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Get a campaign",
        "description": "Its status, progress by keyword, top places and the batch running now.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "post": {
        "operationId": "controlCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Pause, resume or stop a campaign",
        "description": "A pause or stop takes effect after the batches running now (a batch still queued is cancelled and refunded). Only a running campaign can be paused, only a paused one resumed, and a completed one not stopped: each a 409. Pausing a paused campaign, or stopping a stopped one, again only takes a batch still queued off the queue — what a 500 saying one could not be taken off asks for.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "action"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "pause",
                      "resume",
                      "stop"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "400": {
            "description": "Unknown action.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Resuming needs leads, and a Free account's leads don't renew.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Not in a state that action applies to.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/campaigns/{id}/leads": {
      "get": {
        "operationId": "listCampaignLeads",
        "tags": [
          "Campaigns"
        ],
        "summary": "List a campaign's leads",
        "description": "One page at a time, by cursor: total_matching on the first page, next_cursor null on the last.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Up to 2,500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2500,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The next_cursor a previous page returned.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CursorLeadPage"
                }
              }
            }
          },
          "400": {
            "description": "A cursor the API can't use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "post": {
        "operationId": "queryCampaignLeads",
        "tags": [
          "Campaigns"
        ],
        "summary": "Filter and sort a campaign's leads",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "filters": {
                    "type": "array",
                    "maxItems": 100,
                    "description": "Filter rows. Fields and the operators each type takes — text fields [operators: contains, not_contains, is, is_not, is_empty, is_not_empty]: name, category, city, state, country, postal_code, address, website, primary_email (or email_1), email_2, email_3, primary_phone (or phone_1), phone_carrier (or phone_1_carrier), phone_2, phone_2_carrier, phone_3, phone_3_carrier, owner_name, contact_name, contact_title, social_facebook, social_instagram, social_linkedin, social_x, social_youtube, social_tiktok, social_yelp, gbp_url, google_cid, logo_url, main_image_url. number fields [operators: eq, neq, gt, gte, lt, lte, is_empty, is_not_empty]: rank, rating, reviews, people. yes/no fields [operators: is_true, is_false, is_empty, is_not_empty]: claimed. choice fields [operators: is, is_not, is_empty, is_not_empty]: website_status take none (No website), live, unreachable, blocked (Blocked our crawler), unknown, pending; email_status (or email_1_status), email_2_status, email_3_status take safe, risky, invalid, unknown; phone_line_type (or phone_1_type), phone_2_type, phone_3_type take mobile, fixed_line (Landline), fixed_line_or_mobile (Landline or mobile), voip, non_fixed_voip, toll_free (Toll-free), premium_rate, shared_cost, personal_number (Personal), pager, uan, voicemail, unknown. A field, operator or value the API can't use is a 400 that names it.",
                    "items": {
                      "type": "object",
                      "required": [
                        "field",
                        "operator"
                      ],
                      "properties": {
                        "field": {
                          "type": "string"
                        },
                        "operator": {
                          "type": "string",
                          "description": "A test the field's type takes. Case is ignored."
                        },
                        "value": {
                          "description": "Text, a number, or one of a choice field's values. is_empty, is_not_empty, is_true and is_false take none."
                        },
                        "conj": {
                          "type": "string",
                          "enum": [
                            "and",
                            "or"
                          ],
                          "description": "Joins the row to the one before it. \"and\" binds tighter."
                        }
                      }
                    }
                  },
                  "sort": {
                    "type": "array",
                    "description": "Sort keys in priority order, e.g. [{\"id\": \"reviews\", \"dir\": -1}]. id is any filter field; dir is 1 ascending (the default) or -1 descending.",
                    "items": {
                      "type": "object",
                      "required": [
                        "id"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "dir": {
                          "type": "integer",
                          "enum": [
                            1,
                            -1
                          ]
                        }
                      }
                    }
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2500,
                    "default": 50
                  },
                  "cursor": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CursorLeadPage"
                }
              }
            }
          },
          "400": {
            "description": "A filter, sort or cursor the API can't use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your LeadMarina API key."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "The same key, in a header of its own."
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Seconds to wait before trying again.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, invalid or revoked API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests; wait Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServerError": {
        "description": "Failed on our side; the message says whether anything changed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "Briefly unavailable; nothing was changed. Retry after Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "What went wrong and what to do."
          }
        }
      },
      "Stage": {
        "type": "string",
        "enum": [
          "queued",
          "discovering",
          "enriching",
          "verifying",
          "complete",
          "failed",
          "cancelled"
        ]
      },
      "CreditsWindow": {
        "type": [
          "object",
          "null"
        ],
        "description": "On a plan with no monthly quota: the current 7-day period.",
        "properties": {
          "limit": {
            "type": "integer"
          },
          "used": {
            "type": "integer"
          },
          "resets_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Location": {
        "type": "object",
        "properties": {
          "location_code": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "full_name": {
            "type": "string"
          }
        }
      },
      "Person": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "owner",
              "manager",
              "practitioner",
              "staff"
            ]
          }
        }
      },
      "EmailCheck": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "safe",
              "risky",
              "invalid",
              "unknown"
            ]
          },
          "is_deliverable": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "is_catch_all": {
            "type": [
              "boolean",
              "null"
            ]
          }
        }
      },
      "PhoneCheck": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          },
          "valid": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "line_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Usually mobile | fixed_line | voip | toll_free; sometimes unknown or fixed_line_or_mobile."
          },
          "carrier": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Lead": {
        "type": "object",
        "description": "One business. Each field is filled only where it can be found, and is null (or an empty list) otherwise. A lead with no reachable website still carries its full listing fields.",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "description": "The listing row's id."
          },
          "search_id": {
            "type": "string",
            "description": "The search that found it."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Position in its search's results."
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "The business's primary listing category."
          },
          "website": {
            "type": [
              "string",
              "null"
            ],
            "description": "Site URL."
          },
          "owner_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Likely owner or decision-maker, when one can be identified — best-effort, only a fraction of leads."
          },
          "contact_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The person the business's own website names as running part of it, when it names no owner."
          },
          "contact_title": {
            "type": [
              "string",
              "null"
            ],
            "description": "That person's role, as the site gives it."
          },
          "people": {
            "type": [
              "array",
              "null"
            ],
            "description": "Everyone the business's own website names as working there.",
            "items": {
              "$ref": "#/components/schemas/Person"
            }
          },
          "address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Street address."
          },
          "city": {
            "type": [
              "string",
              "null"
            ],
            "description": "City."
          },
          "state": {
            "type": [
              "string",
              "null"
            ],
            "description": "State or region."
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "Two-letter ISO country code (\"US\"; a US territory's lead found since October 2026 carries its own code, such as \"PR\")."
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Postal code as the listing gives it."
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "description": "The listing's phone."
          },
          "rating": {
            "type": [
              "number",
              "null"
            ],
            "description": "Average review rating."
          },
          "reviews": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Review count."
          },
          "claimed": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the owner has claimed the listing."
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Logo image URL."
          },
          "main_image_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Main photo URL."
          },
          "cid": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stable listing identifier: match a business across searches and syncs on cid."
          },
          "place_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Second listing identifier."
          },
          "primary_email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Best email found."
          },
          "primary_phone": {
            "type": [
              "string",
              "null"
            ],
            "description": "Best phone found."
          },
          "emails": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Up to 3 emails."
          },
          "phones": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Up to 3 phones."
          },
          "email_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "primary_email's deliverability: safe | risky | invalid | unknown."
          },
          "phone_line_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "primary_phone's line type."
          },
          "phone_carrier": {
            "type": [
              "string",
              "null"
            ],
            "description": "primary_phone's carrier."
          },
          "emails_data": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/EmailCheck"
            },
            "description": "Each email found, with its deliverability check."
          },
          "phones_data": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/PhoneCheck"
            },
            "description": "Each phone found, with its line type and carrier."
          },
          "socials": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            },
            "description": "Profile URLs by network: facebook, instagram, linkedin, x, youtube, tiktok, yelp."
          },
          "enrichment_status": {
            "type": "string",
            "enum": [
              "pending",
              "enriched",
              "failed",
              "skipped"
            ]
          },
          "enrichment_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "What went wrong on the website check, when something did (e.g. \"site unreachable\"); null when nothing did."
          },
          "website_status": {
            "type": "string",
            "enum": [
              "none",
              "live",
              "unreachable",
              "blocked",
              "unknown",
              "pending"
            ],
            "description": "One word for the state of the lead's website."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SearchStarted": {
        "type": "object",
        "properties": {
          "search_id": {
            "type": "string"
          },
          "query": {
            "type": "string"
          },
          "location": {
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "type": "string"
          },
          "exact_category": {
            "type": [
              "string",
              "null"
            ]
          },
          "max_leads": {
            "type": [
              "integer",
              "null"
            ]
          },
          "delivered": {
            "type": "integer"
          },
          "found": {
            "type": "integer"
          },
          "credits_remaining": {
            "type": "integer"
          },
          "enrichment": {
            "type": "string",
            "enum": [
              "pending",
              "complete"
            ]
          },
          "more_results": {
            "type": "string",
            "enum": [
              "pending",
              "complete"
            ]
          },
          "discovery": {
            "type": "string",
            "enum": [
              "complete",
              "in_progress"
            ]
          },
          "poll": {
            "type": "string",
            "description": "The path to poll."
          },
          "note": {
            "type": "string"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Lead"
            }
          }
        }
      },
      "SearchResults": {
        "type": "object",
        "properties": {
          "search_id": {
            "type": "string"
          },
          "query": {
            "type": [
              "string",
              "null"
            ]
          },
          "location": {
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "type": "string"
          },
          "exact_category": {
            "type": [
              "string",
              "null"
            ]
          },
          "max_leads": {
            "type": [
              "integer",
              "null"
            ]
          },
          "campaign_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "enrichment": {
            "type": "string",
            "enum": [
              "pending",
              "complete"
            ]
          },
          "delivered": {
            "type": "integer",
            "description": "Leads in the whole search, not this page."
          },
          "showing": {
            "type": "object",
            "properties": {
              "offset": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              },
              "returned": {
                "type": "integer"
              }
            }
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Pass as offset for the next page; null on the last."
          },
          "credits_remaining": {
            "type": [
              "integer",
              "null"
            ]
          },
          "credits_window": {
            "$ref": "#/components/schemas/CreditsWindow"
          },
          "stage": {
            "$ref": "#/components/schemas/Stage"
          },
          "stage_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "queue_position": {
            "type": [
              "integer",
              "null"
            ],
            "description": "For a queued search: its place in your own queue (1 = next)."
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "progress": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "done": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            }
          },
          "verify_progress": {
            "type": [
              "object",
              "null"
            ],
            "description": "While stage is verifying: email addresses checked of those queued, refreshed about every 30 seconds. null otherwise.",
            "properties": {
              "done": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            }
          },
          "results": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Lead"
                },
                {
                  "type": "object",
                  "properties": {
                    "enrichment_error": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "What went wrong on the website check, when something did; null when nothing did."
                    }
                  }
                }
              ]
            }
          },
          "data_sources": {
            "type": "string",
            "format": "uri",
            "description": "Present when some of these leads' emails or owner names may come from open datasets and public records: the page with their sources, licences and notices (also sent as a Link header, rel=\"license\"). Pass it on with any of this data you share."
          }
        }
      },
      "ExportResult": {
        "type": "object",
        "properties": {
          "exported": {
            "type": "integer"
          },
          "not_sent": {
            "type": "integer",
            "description": "A CRM batch that ran out of time: its next_cursor sends the rest."
          },
          "outcome": {
            "type": "string",
            "description": "e.g. \"CSV ready to download\"."
          },
          "download_url": {
            "type": "string",
            "format": "uri",
            "description": "csv, xlsx or json: valid for 7 days."
          },
          "spreadsheet_url": {
            "type": "string",
            "format": "uri"
          },
          "spreadsheet_id": {
            "type": "string",
            "description": "google_sheets: pass it as spreadsheet_id to send the next batch into this same spreadsheet. Absent once the spreadsheet holds 50,000 leads."
          },
          "file": {
            "type": "string"
          },
          "truncated": {
            "type": "boolean"
          },
          "limit": {
            "type": "integer"
          },
          "warning": {
            "type": "string"
          },
          "next_cursor": {
            "type": "string"
          },
          "note": {
            "type": "string",
            "description": "Whether leads were updated in place or written fresh."
          },
          "data_sources": {
            "type": "string",
            "format": "uri",
            "description": "Present when some of these leads' emails or owner names may come from open datasets and public records: the page with their sources, licences and notices (also sent as a Link header, rel=\"license\"). Pass it on with any of this data you share."
          }
        }
      },
      "ScheduleDestinationInput": {
        "type": "object",
        "required": [
          "provider"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "none",
              "email",
              "ghl",
              "close",
              "google_sheets"
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "csv",
              "xlsx",
              "json"
            ],
            "description": "email only; csv by default."
          },
          "updateExisting": {
            "type": "boolean",
            "description": "close: false sends only leads it hasn't had. google_sheets with a spreadsheet: false appends every row."
          },
          "spreadsheet_id": {
            "type": "string",
            "description": "google_sheets: a spreadsheet an earlier export created."
          },
          "title": {
            "type": "string",
            "maxLength": 100,
            "description": "google_sheets without a spreadsheet: each run's new spreadsheet's title."
          }
        }
      },
      "ScheduleDestination": {
        "description": "The destination as each run reads it.",
        "oneOf": [
          {
            "type": "object",
            "required": [
              "provider"
            ],
            "properties": {
              "provider": {
                "const": "none"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "provider",
              "format"
            ],
            "properties": {
              "provider": {
                "const": "email"
              },
              "format": {
                "type": "string",
                "enum": [
                  "csv",
                  "xlsx",
                  "json"
                ]
              }
            }
          },
          {
            "type": "object",
            "required": [
              "provider"
            ],
            "properties": {
              "provider": {
                "const": "ghl"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "provider",
              "updateExisting"
            ],
            "properties": {
              "provider": {
                "const": "close"
              },
              "updateExisting": {
                "type": "boolean"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "provider",
              "mode"
            ],
            "properties": {
              "provider": {
                "const": "google_sheets"
              },
              "mode": {
                "type": "string",
                "enum": [
                  "new",
                  "existing"
                ]
              },
              "spreadsheetId": {
                "type": "string",
                "description": "With mode existing."
              },
              "updateExisting": {
                "type": "boolean",
                "description": "With mode existing."
              }
            }
          }
        ]
      },
      "Schedule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "keyword": {
            "type": "string"
          },
          "locations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "location_code": {
                  "type": "integer"
                },
                "location_name": {
                  "type": "string"
                }
              }
            }
          },
          "cadence": {
            "type": "string",
            "enum": [
              "once",
              "daily",
              "weekly",
              "monthly",
              "yearly"
            ]
          },
          "destination": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ScheduleDestination"
              },
              {
                "type": "null"
              }
            ]
          },
          "active": {
            "type": "boolean"
          },
          "next_run_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_run_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_file_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_file_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Country": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "description": "The word for its regions, such as state."
          },
          "places": {
            "type": "integer"
          }
        }
      },
      "RegionList": {
        "type": "object",
        "properties": {
          "country": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "places": {
            "type": "integer"
          },
          "regions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": [
                    "string",
                    "integer"
                  ]
                },
                "name": {
                  "type": "string"
                },
                "places": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "PlaceMatches": {
        "type": "object",
        "properties": {
          "country": {
            "type": "string"
          },
          "total_matching": {
            "type": "integer"
          },
          "places": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "integer"
                },
                "name": {
                  "type": "string"
                },
                "region": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CampaignEstimate": {
        "type": "object",
        "properties": {
          "country": {
            "type": "string"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "keyword": {
                  "type": "string"
                },
                "exact": {
                  "type": "boolean"
                }
              }
            }
          },
          "places": {
            "type": "integer"
          },
          "searches": {
            "type": "integer"
          },
          "expected_leads": {
            "type": "integer",
            "description": "The most likely number of unique leads."
          },
          "low": {
            "type": "integer"
          },
          "high": {
            "type": "integer",
            "description": "low–high is the range it lands in most of the time."
          },
          "charged_leads": {
            "type": "integer",
            "description": "expected_leads capped by lead_cap."
          },
          "minutes": {
            "type": "integer",
            "description": "Includes waiting for your daily campaign budget."
          },
          "time": {
            "type": "string",
            "description": "minutes, said as a duration (\"~3 days\")."
          },
          "paced_by_daily_budget": {
            "type": "boolean"
          },
          "campaign_searches_per_day": {
            "type": "integer"
          },
          "estimate_quality": {
            "type": "string",
            "enum": [
              "fitted",
              "rough"
            ],
            "description": "How far the estimate can be trusted."
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "paused",
              "completed",
              "stopped"
            ]
          },
          "status_label": {
            "type": "string"
          },
          "status_detail": {
            "type": "string",
            "description": "One sentence on where it is, and until when (resume_at)."
          },
          "finish_reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "all_searched",
              "lead_limit",
              "stopped",
              null
            ]
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "keyword": {
                  "type": "string"
                },
                "exact": {
                  "type": "boolean"
                }
              }
            }
          },
          "places": {
            "type": "integer",
            "description": "How many places it searches."
          },
          "searches_total": {
            "type": "integer",
            "description": "Keywords × places."
          },
          "searches_done": {
            "type": "integer"
          },
          "leads": {
            "type": "integer",
            "description": "Unique leads charged so far."
          },
          "lead_cap": {
            "type": [
              "integer",
              "null"
            ]
          },
          "estimate": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "expected_leads": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "low": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "high": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "minutes": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          },
          "resume_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "leads_url": {
            "type": "string"
          }
        }
      },
      "CampaignDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Campaign"
          },
          {
            "type": "object",
            "properties": {
              "by_keyword": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "keyword": {
                      "type": "string"
                    },
                    "exact": {
                      "type": "boolean"
                    },
                    "category": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "searches": {
                      "type": "integer"
                    },
                    "searches_done": {
                      "type": "integer"
                    },
                    "leads": {
                      "type": "integer"
                    }
                  }
                }
              },
              "top_places": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "place": {
                      "type": "string"
                    },
                    "leads": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "basis": {
                      "type": "string",
                      "enum": [
                        "leads",
                        "businesses_checked"
                      ]
                    },
                    "businesses_checked": {
                      "type": "integer"
                    }
                  }
                }
              },
              "places_skipped": {
                "type": "integer",
                "description": "Present when some places were not searched (or charged) because this account searched the same keyword there in the last 30 days."
              },
              "places_skipped_reason": {
                "type": "string"
              },
              "running_now": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "keyword": {
                    "type": "string"
                  },
                  "places": {
                    "type": "integer"
                  },
                  "status": {
                    "type": "string"
                  },
                  "verified": {
                    "type": "integer"
                  },
                  "of": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        ]
      },
      "CursorLeadPage": {
        "type": "object",
        "properties": {
          "total_matching": {
            "type": [
              "integer",
              "null"
            ],
            "description": "On the first page; null on the pages after it."
          },
          "returned": {
            "type": "integer"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass back as cursor; null on the last page."
          },
          "leads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Lead"
            }
          },
          "data_sources": {
            "type": "string",
            "format": "uri",
            "description": "Present when some of these leads' emails or owner names may come from open datasets and public records: the page with their sources, licences and notices (also sent as a Link header, rel=\"license\"). Pass it on with any of this data you share."
          }
        }
      }
    }
  }
}