{
  "openapi": "3.1.0",
  "info": {
    "title": "Tracerfy API",
    "version": "2026-03-21",
    "description": "Skip tracing, DNC checks, and property data for U.S. real estate, over a simple JSON API. You pay per hit: a request that finds nothing costs nothing, unless an endpoint says otherwise.\n\n## Get started in 3 steps\n\n**1. Get your API key.** Log in, then open your account settings from the menu in the top-right corner. No account yet? [Create one](/auth/sign-up/). Every request sends the key in this header:\n\n```\nAuthorization: Bearer YOUR_API_KEY\n```\n\n**2. Send your first request.** This finds the owner of a property and returns their phones and emails:\n\n```bash\ncurl -X POST https://tracerfy.com/v1/api/trace/lookup/ \\\n  -H \"Authorization: Bearer YOUR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"address\": \"123 Main St\", \"city\": \"Austin\", \"state\": \"TX\", \"zip\": \"78701\"}'\n```\n\n**3. Check `hit` in the response.** `true` means we found data and charged the credits shown in `credits_deducted`. `false` means we found nothing and charged nothing.\n\nEvery response also carries `meta.request_id`. Quote it when you contact support.\n\n**Try it free:** the [API Tester](/skip-tracing-api-documentation/tester/) runs any endpoint in Mock mode with example data and no credits.\n\n\n## Authentication, Errors & Rate Limits\n\nEvery endpoint requires a Bearer token in the `Authorization` header: `Authorization: Bearer <YOUR_TOKEN>`. Requests without a valid token get a **401**.\n\n**Status codes you may receive:**\n\n- `200 OK`: success (synchronous endpoints).\n- `202 Accepted`: async job accepted and queued (e.g. Lead Builder execute).\n- `400 Bad Request`: malformed body, missing/invalid parameter, or a column named in your request is not present in the uploaded data.\n- `401 Unauthorized`: missing, malformed, or invalid/expired Bearer token.\n- `402 Payment Required`: insufficient credits for the requested work.\n- `403 Forbidden`: account suspended (unpaid invoices or API access disabled), or you tried to access a resource that belongs to another account.\n- `404 Not Found`: the resource ID does not exist. Lead lists, templates, and monitors also return 404 for an ID that belongs to another account; trace and DNC jobs return 403 for that case.\n- `405 Method Not Allowed`: wrong HTTP method for the route.\n- `409 Conflict`: the resource is not ready yet (e.g. reading rows of a lead list that is still processing).\n- `429 Too Many Requests`: a rate limit was exceeded. Back off and retry; the response body includes how many requests were counted in the window.\n- `500 Internal Server Error`: an unexpected error. Retry; if it persists, contact support.\n- `502` / `503`: the request couldn't be completed right away due to a temporary service delay. This usually resolves on its own. If it persists, contact support.\n\n**Rate limits (per account):**\n\n- **Batch Trace**: 10 submissions per 5 minutes. An APN Batch Trace is refused while this limit is reached.\n- **Instant Trace**, **Enhanced Trace**, **Phone Verification**, **APN Instant Lookup** &amp; **Property Lookup**, 500 lookups per minute (shared counter).\n- **DNC Scrub**: 10 scrubs per 5 minutes.\n- **DNC Instant Lookup**: 120 lookups per minute on v2, 30 per minute on v1.\n- **Fetch all Queues**: 1 request per 20 seconds.\n- **Property Search Preview, Execute &amp; Lookup**: 500 property searches per minute.\n- **Saved Templates** &amp; **Property Monitors**, 60 requests per minute.\n- **Address &amp; APN Autocomplete**: 30 requests per minute.\n\nThe insufficient-credits (402) and suspended-account (403) message wording varies slightly per endpoint, but the shape and status code are the same everywhere. Representative bodies are below.\n\n**401 Unauthorized: missing or invalid token**\n\n```json\n{\n  \"detail\": \"Authentication credentials were not provided.\"\n}\n```\n\n**400 Bad Request: field validation (detail is a field\u2192messages map)**\n\n```json\n{\n  \"address\": [\n    \"This field is required.\"\n  ],\n  \"state\": [\n    \"This field is required.\"\n  ]\n}\n```\n\n**402 Payment Required: insufficient credits: When the account cannot use monthly billing**\n\n```json\n{\n  \"error\": \"Insufficient credits. Instant trace requires 5 credits per lookup. You have 0 credits.\"\n}\n```\n\n**402 Payment Required: insufficient credits: When credits are short and no payment method is on file**\n\n```json\n{\n  \"error\": \"Insufficient credits. Instant trace requires 5 credits per lookup. Please add credits or a payment method.\"\n}\n```\n\n**403 Forbidden: account suspended: Unpaid invoices**\n\n```json\n{\n  \"error\": \"Your account has been temporarily suspended due to unpaid invoices. Please contact support@tracerfy.com to resolve outstanding payments.\"\n}\n```\n\n**403 Forbidden: account suspended: API access disabled for this account**\n\n```json\n{\n  \"error\": \"api_disabled\",\n  \"detail\": \"Your API access has been suspended. Please contact support at support@tracerfy.com.\",\n  \"status\": 403\n}\n```\n\n**404 Not Found: unknown or cross-account resource ID**\n\n```json\n{\n  \"error\": \"No Queue Found with ID 123\"\n}\n```\n\n**429 Too Many Requests (rate limited: Most endpoints) includes the count seen in the window**\n\n```json\n{\n  \"status\": \"429\",\n  \"error\": \"Rate limit exceeded. Max 500 lookups per minute.\",\n  \"lookups_in_window\": \"501\",\n  \"retry_after_seconds\": \"60\"\n}\n```\n\n**429 Too Many Requests: rate limited: Fetch all Queues (20-second throttle)**\n\n```json\n{\n  \"error\": \"Rate limit exceeded. Retry in intervals of 20 seconds.\",\n  \"retry_in\": \"3 seconds\"\n}\n```\n\n## Response Metadata\n\nEvery response carries an `X-Request-Id` response header, a unique id Tracerfy assigns to that request. Use it to correlate a specific response with your own application logs and retries, and quote it when contacting support. The id is always assigned server-side; any `X-Request-Id` you send on the request is ignored.\n\nIn addition, every response whose body is a JSON **object** includes a `meta` block:\n\n- `request_id`: the same value as the `X-Request-Id` header.\n- `timestamp`: when the response was generated (ISO 8601, UTC).\n- `api_version`: the response-schema version that served the request.\n\n`meta` is additive: new fields may be added over time, so treat unknown keys as optional and ignore them. Endpoints that return a top-level JSON **array** (e.g. [Fetch all Queues](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queues/) and [Fetch Single Queue](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queue/{id})) keep their bare-array body and do **not** include a `meta` block, read the `X-Request-Id` header for those. The AI-assist endpoint (`/v1/api/property-search/ai-assist/`) also returns no `meta` block (it still carries the `X-Request-Id` header).\n\n**meta block (present on every object response): Example: the Analytics response, with the meta block appended**\n\n```json\n{\n  \"total_queues\": 12,\n  \"properties_traced\": 18350,\n  \"queues_pending\": 2,\n  \"queues_completed\": 10,\n  \"balance\": 940,\n  \"meta\": {\n    \"request_id\": \"req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d\",\n    \"timestamp\": \"2026-07-16T18:22:05Z\",\n    \"api_version\": \"2026-03-21\"\n  }\n}\n```\n\n## Sandbox / Testing Environment\n\nBefore you spend a single credit, build and test your integration against the **free hosted sandbox** at `https://mock.tracerfy.com`. It mirrors this *exact* API (same paths, methods, field names, and response shapes) but returns realistic **fake** data. Nothing is charged and no credits are consumed.\n\n**Going live is a one-line change:** develop against `https://mock.tracerfy.com/v1/api/`, then swap the host to `https://tracerfy.com/v1/api/` and use your real token. Nothing else about your code changes.\n\n- **Auth:** any non-empty Bearer token authenticates, no real key needed. (The reserved value `INVALID_TOKEN` always returns `401` so you can test your unauthorized path.)\n- **Deterministic:** the same request always returns the same data (it's seeded from your inputs), so your test assertions stay stable. Only `meta.request_id` and `meta.timestamp` vary between calls.\n- **Full coverage:** every endpoint in these docs, batch &amp; instant trace, parcel/APN, DNC, property search, saved templates, and property monitors.\n- **Interactive docs:** browse and try every endpoint at `https://mock.tracerfy.com/docs`.\n\n**Magic values: force a specific scenario on demand.** Anything you send that isn't a magic value flows through to a normal deterministic fake response. The values below instead trigger a fixed outcome, so you can exercise every branch of your client without hunting for real data that happens to hit or miss:\n\n- **Numeric path IDs**: use an HTTP status code as any `{id}` to reproduce that scenario: `404` not found, `403` cross-account, `409` still processing, `0` a pending job. e.g. `GET /v1/api/property-monitors/404/` &rarr; `404`.\n- **String sentinels**: embed a keyword in the primary string field (`address`, `phone`, a monitor `name`, a strategy value, or a CSV `*_column`): `NO_CREDITS`&rarr;402, `SUSPENDED`&rarr;403, `RATE_LIMIT`&rarr;429, `SERVER_ERROR`&rarr;500, `UNAVAILABLE`&rarr;503, `MISSING_COLUMN`&rarr;400 (CSV), `NO_MATCH`&rarr;200 empty, `MULTI`&rarr;200 multiple results, `CAP_REACHED`&rarr;400 (monitor cap). The literal address `999 Nowhere Blvd` behaves as a miss.\n\n**The sandbox is for development only**: it returns fabricated data, so never point production traffic at it.\n\n```bash\n# Test against the sandbox: any token works, nothing is billed\ncurl -X POST 'https://mock.tracerfy.com/v1/api/trace/lookup/' \\\n  -H 'Authorization: Bearer sandbox_test_token' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"address\":\"123 Main St\",\"city\":\"Austin\",\"state\":\"TX\",\"zip\":\"78701\"}'\n\n# Force a scenario with a magic value (402 insufficient credits)\ncurl -X POST 'https://mock.tracerfy.com/v1/api/trace/lookup/' \\\n  -H 'Authorization: Bearer sandbox_test_token' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"address\":\"NO_CREDITS\",\"city\":\"Austin\",\"state\":\"TX\"}'\n\n# Ready for real data? Change the host and use your real token\ncurl -X POST 'https://tracerfy.com/v1/api/trace/lookup/' \\\n  -H 'Authorization: Bearer <YOUR_TOKEN>' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"address\":\"123 Main St\",\"city\":\"Austin\",\"state\":\"TX\",\"zip\":\"78701\"}'\n```\n\n**POST /v1/api/trace/lookup/ on the sandbox, the exact body the first curl above returns. Deterministic: the same request always returns this data (only meta varies).**\n\n```json\n{\n  \"address\": \"123 Main St\",\n  \"city\": \"Austin\",\n  \"state\": \"TX\",\n  \"zip\": \"78701\",\n  \"find_owner\": true,\n  \"hit\": true,\n  \"persons_count\": 1,\n  \"credits_deducted\": 5,\n  \"persons\": [\n    {\n      \"first_name\": \"Sandra\",\n      \"last_name\": \"Dean\",\n      \"full_name\": \"Sandra Dean\",\n      \"dob\": \"1958-12\",\n      \"age\": \"67\",\n      \"deceased\": true,\n      \"property_owner\": true,\n      \"litigator\": false,\n      \"mailing_address\": {\n        \"street\": \"469 Amy Pines Suite 707\",\n        \"city\": \"Christinebury\",\n        \"state\": \"CT\",\n        \"zip\": \"50627\"\n      },\n      \"phones\": [\n        {\n          \"number\": \"5088697674\",\n          \"type\": \"Mobile\",\n          \"dnc\": false,\n          \"tcpa\": false,\n          \"carrier\": \"COMCAST PHONE LLC\",\n          \"rank\": 1\n        },\n        {\n          \"number\": \"6478388352\",\n          \"type\": \"Landline\",\n          \"dnc\": true,\n          \"tcpa\": false,\n          \"carrier\": \"US CELLULAR\",\n          \"rank\": 2\n        }\n      ],\n      \"emails\": [\n        {\n          \"email\": \"mreeves@hotmail.com\",\n          \"rank\": 1\n        }\n      ]\n    }\n  ],\n  \"meta\": {\n    \"request_id\": \"req_b0e2ba54941820e3009e83c0cd14dda6\",\n    \"timestamp\": \"2026-07-20T18:22:05Z\",\n    \"api_version\": \"2026-03-21\"\n  }\n}\n```\n\n**Magic value NO_CREDITS \u2192 402 (deterministic)**\n\n```json\n{\n  \"error\": \"Insufficient credits. Lead Builder lookup requires 10 credits per hit. You have 2 credits.\"\n}\n```\n\n**Reserved token INVALID_TOKEN \u2192 401**\n\n```json\n{\n  \"detail\": \"Authentication credentials were not provided.\"\n}\n```\n\n## Connect via AI Assistants (MCP)\n\nConnect Tracerfy to your AI assistant (e.g. Claude) via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io) and run skip traces, DNC checks, and lead lists in plain English. Same billing as the API: **pay per hit**; misses cost nothing.\n\nGenerate a personal connector link in your profile under **Connect via MCP** (`https://mcp.tracerfy.com/u/<token>/mcp`), the token in the URL authenticates as you, so keep it private. Connect it one of these ways:\n\n- **Custom connector:** in your AI assistant's connector settings, add a custom connector and paste the link as the server URL, most MCP-capable assistants support this.\n- **MCP config file** (MCP-compatible apps &amp; IDEs): use the JSON below.\n- **Programmatic API**: pass the connector in your request's `mcp_servers`, full example below (shown for the Claude API).\n\n**Example prompts:**\n\n- \"Skip trace 123 Main St, Phoenix AZ and check the number against Do-Not-Call.\"\n- \"How many vacant, high-equity homes are in Dallas?\"\n- \"Build me a list of 500 absentee owners in Miami-Dade.\"\n- \"What's my Tracerfy credit balance?\"\n\n**Available tools:**\n\n- `start_trace_queue`: bulk normal, advanced, or enhanced trace queue from rows\n- `trace_lookup` / `enhanced_trace_lookup` / `parcel_lookup`, standard owner contacts by address, enhanced owner or specific-person context, or parcel (APN) lookup\n- `phone_verification`: phone carrier, line type, last-seen, DNC/TCPA flags, and compact associated-person context\n- `dnc_check`: Do-Not-Call / TCPA compliance for a phone\n- `lead_lookup`: full property + owner dossier for an address\n- `preview_lead_list` (free) &amp; `execute_lead_list`, size and build lead lists\n- `get_lead_list_status` / `get_lead_list_rows`, track and fetch results\n- `list_strategies`, `check_balance`: presets/filters and your credits (free)\n\n```bash\ncurl https://api.anthropic.com/v1/messages \\\n  -H \"x-api-key: $ANTHROPIC_API_KEY\" \\\n  -H \"anthropic-version: 2023-06-01\" \\\n  -H \"anthropic-beta: mcp-client-2025-11-20\" \\\n  -H \"content-type: application/json\" \\\n  -d '{\n    \"model\": \"claude-sonnet-5\",\n    \"max_tokens\": 1024,\n    \"messages\": [\n      {\"role\": \"user\", \"content\": \"Skip trace 123 Main St, Phoenix AZ and check the phone against Do-Not-Call.\"}\n    ],\n    \"mcp_servers\": [\n      {\n        \"type\": \"url\",\n        \"url\": \"https://mcp.tracerfy.com/u/<token>/mcp\",\n        \"name\": \"tracerfy\"\n      }\n    ],\n    \"tools\": [\n      {\n        \"type\": \"mcp_toolset\",\n        \"mcp_server_name\": \"tracerfy\"\n      }\n    ]\n  }'\n```\n\n**TypeScript (Anthropic SDK)**\n\n```json\nimport Anthropic from \"@anthropic-ai/sdk\";\n\nconst client = new Anthropic(); // reads ANTHROPIC_API_KEY\n\nconst message = await client.beta.messages.create({\n  model: \"claude-sonnet-5\",\n  max_tokens: 1024,\n  messages: [\n    { role: \"user\", content: \"Skip trace 123 Main St, Phoenix AZ and check the phone against Do-Not-Call.\" },\n  ],\n  mcp_servers: [\n    { type: \"url\", url: \"https://mcp.tracerfy.com/u/<token>/mcp\", name: \"tracerfy\" },\n  ],\n  tools: [\n    { type: \"mcp_toolset\", mcp_server_name: \"tracerfy\" },\n  ],\n  betas: [\"mcp-client-2025-11-20\"],\n});\n\nconsole.log(message.content);\n```\n\n**MCP config file (Claude Desktop & MCP-compatible clients)**\n\n```json\n{\n  \"mcpServers\": {\n    \"tracerfy\": {\n      \"url\": \"https://mcp.tracerfy.com/u/<token>/mcp\"\n    }\n  }\n}\n```"
  },
  "servers": [
    {
      "url": "https://tracerfy.com",
      "description": "Production (uses credits)"
    },
    {
      "url": "https://mock.tracerfy.com",
      "description": "Mock (example data, no credits)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Skip Tracing",
      "description": "Find owners and people, with phones and emails."
    },
    {
      "name": "Phone Verification & DNC",
      "description": "Phone checks, Do-Not-Call scrubs, and litigator checks.\n\n### DNC API Versions (v1 vs v2)\n\nBoth versions are current and supported; **v2 is recommended for new integrations**. Only the DNC endpoints have a v2, everything else stays on `/v1/api/`. Migrating is a URL change: `/v1/api/dnc/scrub/` \u2192 `/v2/api/dnc/scrub/`.\n\n**Unchanged:** authentication, request parameters, pricing, the scrub rate limit, webhooks, queue lifecycle, and the two-CSV output.\n\n**Higher lookup limit on v2:** 120 instant lookups per minute, against 30 on v1.\n\n**v2 adds**\n\n- `state_dnc_list`: *which* state registries matched, not just that one did. Array in JSON, comma-separated in the CSV. State registries currently covered: CO, FL, IN, LA, MA, MO, PA, TN, TX, WY, this list can grow, and any state returned is reflected in `state_dnc_list` whether or not it appears here. Federal DNC and litigator checks are nationwide.\n- Faster batch scrubs: the whole list goes upstream in one request.\n\n**v2 removes**\n\n- `dma`: marketing-preference suppression, not a DNC or TCPA signal. Never affected `is_clean`.\n- `phone_type`: DNC data carries no line type, and v2 does not infer one.\n\n**Result CSV**: v2 replaces `dma` with `state_dnc_list` and drops `phone_type`. Remaining columns keep their names and `Y`/`N` encoding.\n\n- v1: `phone, label, national_dnc, state_dnc, dma, litigator, phone_type, is_clean`\n- v2: `phone, label, national_dnc, state_dnc, state_dnc_list, litigator, is_clean`\n\n`GET /dnc/queue/:id` is the same endpoint on both versions.\n\n```bash\n# v1: unchanged, still supported\ncurl -X POST 'https://tracerfy.com/v1/api/dnc/lookup/' \\\n  -H 'Authorization: Bearer <YOUR_TOKEN>' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"phone\": \"4805551234\"}'\n\n# v2: same request, one character different in the URL\ncurl -X POST 'https://tracerfy.com/v2/api/dnc/lookup/' \\\n  -H 'Authorization: Bearer <YOUR_TOKEN>' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"phone\": \"4805551234\"}'\n\n# Array lookup (up to 15 objects)\ncurl -X POST 'https://tracerfy.com/v2/api/dnc/lookup/' \\\n  -H 'Authorization: Bearer <YOUR_TOKEN>' \\\n  -H 'Content-Type: application/json' \\\n  -d '[{\"phone\":\"4805551234\"},{\"phone\":\"4805559876\"}]'\n```\n\n**v1 response**\n\n```json\n{\n  \"phone\": \"4805551234\",\n  \"hit\": true,\n  \"national_dnc\": true,\n  \"state_dnc\": true,\n  \"dma\": false,\n  \"litigator\": false,\n  \"phone_type\": \"Mobile\",\n  \"is_clean\": false,\n  \"credits_deducted\": 5\n}\n```\n\n**v2 response: same number**\n\n```json\n{\n  \"phone\": \"4805551234\",\n  \"hit\": true,\n  \"national_dnc\": true,\n  \"state_dnc\": true,\n  \"state_dnc_list\": [\n    \"FL\"\n  ],\n  \"litigator\": false,\n  \"is_clean\": false,\n  \"credits_deducted\": 5\n}\n```"
    },
    {
      "name": "Property Search",
      "description": "Search U.S. property records, build lead lists, and look up one property.\n\n### Filter Reference\n\nEvery key accepted in `filter_overrides`, grouped for readability. Unknown keys are rejected with a 400, as are invalid values for keys that accept a fixed set (see `property_type` and `search_range` below).\n\n| Group | Keys |\n| --- | --- |\n| Property | `property_type` (string: one of `\"SFR\"`, `\"MFR\"`, `\"LAND\"`, `\"CONDO\"`, `\"MOBILE\"` (mobile/manufactured homes), or `\"COMMERCIAL\"`; any other value is rejected with a 400), `property_types` (array of those same values, 2 or more are combined into an OR query, e.g. `[\"SFR\", \"CONDO\"]`), `beds_min`, `beds_max`, `baths_min`, `baths_max`, `units_min`, `units_max`, `building_size_min`, `building_size_max`, `lot_size_min`, `lot_size_max`, `year_built_min`, `year_built_max`, `stories_min`, `stories_max`, `rooms_min`, `rooms_max`, `pool`, `garage`, `basement`, `deck`, `mfh_2to4`, `mfh_5plus` |\n| Value &amp; Equity | `value_min`, `value_max`, `assessed_value_min`, `assessed_value_max`, `estimated_equity`, `estimated_equity_min`, `estimated_equity_max`, `equity`, `equity_operator`, `high_equity`, `free_clear`, `ltv_min`, `ltv_max` |\n| Ownership | `absentee_owner` (boolean: `true` when the owner's mailing address differs from the property), `owner_occupied` (boolean, opposite of `absentee_owner`; `owner_occupied: true` is translated to `absentee_owner: false` before the upstream query, and the preview response echoes it back as `absentee_owner` in `filters_applied`. Sending both keys in the same request is rejected with a 400), `in_state_owner`, `out_of_state_owner`, `individual_owned`, `trust_owned`, `corporate_owned`, `cash_buyer`, `investor_buyer`, `private_lender`, `properties_owned_min`, `properties_owned_max`, `years_owned_min`, `years_owned_max` |\n| Portfolio signals | `portfolio_value_min/max`, `portfolio_equity_min/max`, `portfolio_mortgage_balance_min/max`, `portfolio_purchased_last6_min/max`, `portfolio_purchased_last12_min/max` |\n| Distress | `vacant`, `pre_foreclosure`, `pre_foreclosure_date_min`, `pre_foreclosure_date_max`, `foreclosure` (boolean, active foreclosure, further along than `pre_foreclosure`), `auction`, `reo`, `notice_type`, `tax_lien` (boolean, a tax lien is recorded against the property), `tax_delinquent_year_min`, `tax_delinquent_year_max` (int, year (window in which the owner became tax delinquent), `quit_claim` (boolean) last transfer recorded via quitclaim deed), `search_range`, pair this with `pre_foreclosure`, `auction`, or `reo` to restrict results to filings within the last N months. Without it, those filters return every historical match. Accepted values: `\"1_MONTH\"`, `\"3_MONTH\"`, `\"6_MONTH\"`. |\n| MLS | `mls_active`, `mls_pending`, `mls_cancelled`, `mls_sold`, `mls_failed` (boolean, listing came off the market without selling), `mls_days_on_market_min`, `mls_days_on_market_max`, `mls_listing_price_min` |\n| Mortgage | `mortgage_min`, `mortgage_max`, `adjustable_rate`, `assumable`, `loan_type_code_first`, `open_mortgages_min`, `open_mortgages_max` |\n| Sale history | `last_sale_date_min`, `last_sale_date_max`, `last_sale_price_min`, `last_sale_price_max`, `last_sale_arms_length` |\n| Mailing address | `mail_city`, `mail_state`, `mail_zip`, `mail_county` |\n| Environment | `flood_zone`, `flood_zone_type` |\n| Area demographics | `area_median_income_min`, `area_median_income_max` (number, median household income of the property's surrounding area). Accepted values: 1,000&ndash;99,999, area income data ranges up to $99,999, so values outside that range are rejected with a 400. Use ONE bound per request, sending both in the same request is rejected with a 400. |\n\n### Propensity Scores\n\nEvery row returned by [/rows/](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/rows/), [/lookup/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/lookup/), and the CSV export carries five independent propensity scores. Each score quantifies how strongly the property's signals match a specific use case, selling, refinancing, roof replacement, HVAC replacement, or solar installation. The same property can score High in one and Low in another, so a single lead list can serve multiple downstream campaigns.\n\n**Score range and interpretation**\n\nEach score is an integer from `0` to `100`. The category column rolls the score up into one of three tiers using these thresholds:\n\n| Score range | Category | What it means |\n| --- | --- | --- |\n| **70\u2013100** | **High** | Multiple strong signals are present. Prioritize these leads first. |\n| **40\u201369** | **Medium** | Some positive signals. Worth contacting but expect lower conversion than High. |\n| **0\u201339** | **Low** | Few or weak signals for this use case. Skip unless you have other intent data. |\n\n**Recommended action thresholds**\n\n- **Score \u2265 70 (High):** include in primary outreach. These are your best leads for the corresponding use case.\n- **Score 50\u201369:** include in secondary outreach if your list is small, or as a backup pool when High leads run out.\n- **Score 40\u201349:** typically skip unless you have additional context (local market knowledge, prior contact history, etc.).\n- **Score &lt; 40:** exclude from outreach for this use case. The lead may still be valuable for a different vertical with a higher score.\n\n**Filtering by score in your code**\n\nThe score is a plain integer column, so post-filtering is straightforward in Excel, pandas, SQL, or any CRM:\n\n```\n# pandas\ndf_high_solar = df[df['solar_renovate_propensity_score'] >= 70]\n\n# SQL\nSELECT * FROM rows WHERE refi_propensity_score >= 50 ORDER BY refi_propensity_score DESC;\n\n# Excel filter\nAutoFilter on 'roof_renovate_propensity_category' = 'High'\n```\n\n**Score field schema**\n\nEach of the 5 propensity verticals exposes 3 fields on every row:\n\n| Vertical | Use case | Score field | Category field | Factors field |\n| --- | --- | --- | --- | --- |\n| **Sell** | Wholesalers, real estate investors | `sell_propensity_score` | `sell_propensity_category` | `sell_propensity_factors` |\n| **Refinance** | Mortgage brokers, lenders | `refi_propensity_score` | `refi_propensity_category` | `refi_propensity_factors` |\n| **Roof renovate** | Roofing contractors | `roof_renovate_propensity_score` | `roof_renovate_propensity_category` | `roof_renovate_propensity_factors` |\n| **HVAC renovate** | HVAC contractors | `hvac_renovate_propensity_score` | `hvac_renovate_propensity_category` | `hvac_renovate_propensity_factors` |\n| **Solar renovate** | Solar installers | `solar_renovate_propensity_score` | `solar_renovate_propensity_category` | `solar_renovate_propensity_factors` |\n\n**The factors array: explainability**\n\nEach `*_factors` field is a JSON array of `{name, points, reason}` objects describing exactly which signals fired and how much each contributed to the score. Use this to explain to your end-customer why a lead was prioritized, or to debug why a lead scored higher or lower than expected.\n\n**Important notes**\n\n- **Scores are deterministic snapshots** computed at the time the lead list was built. They are not refreshed automatically.\n- **Same property, different verticals.** A property can score High for solar (owner-occupied, high-equity, sunny region) and Low for sell (no distress signals). This is expected and intentional, the scores measure different things.\n- **The scores are signal-density indicators, not predictions.** A score of 80 means the lead matches more of the relevant signals than a lead at 40, not that it has an 80% probability of conversion. Use them to prioritize, not as a forecast.\n- **Realistic precision target: 65\u201375%.** Of leads scored High, expect 65\u201375% to actually be receptive, better than random selection, but not a guarantee."
    },
    {
      "name": "Property Monitors",
      "description": "Recurring searches that deliver only the new properties."
    },
    {
      "name": "Account",
      "description": "Usage figures for your account."
    },
    {
      "name": "Reverse Append APIs",
      "description": "Phone, email, and name lookup, from our sister product FastAppend.\n\n### Reverse Append APIs: Phone, Email & Name Lookup\n\nStart with a phone number, email address, or a person's name and location to find associated contact and address information. FastAppend supports both instant API lookups and bulk CSV workflows.\n\n**Available reverse append APIs**\n\n- `POST /v1/api/reverse-phone-append/lookup/`: look up a person from a phone number\n- `POST /v1/api/reverse-email-append/lookup/`: look up a person from an email address\n- `POST /v1/api/reverse-name-append/lookup/`: look up a person by name and location\n- Bulk phone, email, and name append workflows are also available.\n\n**FastAppend uses a separate account, API key, and credit balance.** To access these APIs, [create a FastAppend account](https://app.fastappend.com/auth/signup/), then purchase credits in the FastAppend portal. See the [complete FastAppend API documentation](https://app.fastappend.com/api-docs/) for authentication, request fields, examples, and responses."
    },
    {
      "name": "Business Trace API",
      "description": "Business and LLC owner lookup, from our sister product FastAppend.\n\n### Business Trace API: Business & LLC Owner Lookup\n\nStart with a business name and state to find business addresses and the people associated with that company, including available role and contact information. FastAppend supports an instant lookup API and a bulk CSV workflow.\n\n**Available Business Trace APIs**\n\n- `POST /v1/api/business-trace/lookup/`: look up one business synchronously\n- `POST /v1/api/business-trace/`: submit a bulk Business Trace job\n\n**FastAppend uses a separate account, API key, and credit balance.** To access these APIs, [create a FastAppend account](https://app.fastappend.com/auth/signup/), then purchase credits in the FastAppend portal. See the [complete FastAppend API documentation](https://app.fastappend.com/api-docs/) for authentication, request fields, examples, and responses."
    }
  ],
  "paths": {
    "/v1/api/trace/": {
      "post": {
        "tags": [
          "Skip Tracing"
        ],
        "operationId": "batchTrace",
        "summary": "Batch Trace",
        "description": "Asynchronous batch endpoint for processing multiple addresses at once via CSV or JSON. Specify trace_type='normal' (1 credit/lead), 'advanced' (2 credits/lead), or 'enhanced' (15 credits/lead). Enhanced batch traces require first and last name columns and target each supplied person at the associated address. Cleans and de-duplicates rows, then enqueues processing in the background. If credits are insufficient the request is rejected. Returns a queue_id immediately along with `estimated_wait_seconds` (estimated processing time in seconds); results are delivered via download_url when complete. For single-address instant lookups, use the [Instant Trace Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/lookup/) endpoint instead.\n\n**\u26a0\ufe0f API Usage Policy:** Do not abuse API POST calls. Accounts found to be abusing the API will be put on hold. Maximum rate limit is 10 POST trace requests per 5-minute window. Please use the API responsibly and in accordance with our [Terms of Service - API Rate Limits &amp; Abuse Policy](/terms-of-service#api-rate-limits).\n\n**Related endpoints:** [Instant Trace Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/lookup/) \u00b7 [Enhanced Trace Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/enhanced/lookup/) \u00b7 [Parcel ID (APN) Batch Trace](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/parcel/)",
        "x-credits": "Per hit: 1 credit (normal), 2 (advanced), 15 (enhanced). Rows with no match cost nothing.",
        "x-rate-limit": "10 batch trace submissions per 5 minutes per account.",
        "x-mode": "Async: returns a queue ID, results arrive by download link and webhook.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "address_column": {
                    "type": "string",
                    "description": "Column for property address"
                  },
                  "city_column": {
                    "type": "string",
                    "description": "Column for property city"
                  },
                  "state_column": {
                    "type": "string",
                    "description": "Column for property state"
                  },
                  "zip_column": {
                    "type": "string",
                    "description": "Property ZIP. Optional but recommended."
                  },
                  "first_name_column": {
                    "type": "string",
                    "description": "Person first-name column. Required for normal, custom, and enhanced traces. Not used by advanced owner lookup."
                  },
                  "last_name_column": {
                    "type": "string",
                    "description": "Person last-name column. Required for normal, custom, and enhanced traces. Not used by advanced owner lookup."
                  },
                  "mail_address_column": {
                    "type": "string",
                    "description": "Mailing address column. Required for normal traces; optional for advanced/enhanced traces."
                  },
                  "mail_city_column": {
                    "type": "string",
                    "description": "Mailing city column. Required for normal traces; optional for advanced/enhanced traces."
                  },
                  "mail_state_column": {
                    "type": "string",
                    "description": "Mailing state column. Required for normal traces; optional for advanced/enhanced traces."
                  },
                  "mailing_zip_column": {
                    "type": "string",
                    "description": "Mailing ZIP column. Optional."
                  },
                  "trace_type": {
                    "type": "string",
                    "description": "Trace type: 'normal' (1 credit/lead), 'advanced' (2 credits/lead), or 'enhanced' (15 credits/lead). Defaults to 'normal'. Advanced discovers the owner from an address; Enhanced requires first and last name columns."
                  },
                  "csv_file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV file of records. Send exactly one of csv_file or json_data."
                  },
                  "json_data": {
                    "type": "string",
                    "description": "The records as a JSON array, sent as a form field (alternative to csv_file)."
                  }
                },
                "required": [
                  "address_column",
                  "city_column",
                  "state_column"
                ]
              },
              "example": {
                "csv_file": "@/path/to/records.csv",
                "address_column": "address",
                "city_column": "city",
                "state_column": "state",
                "zip_column": "zip",
                "first_name_column": "first_name",
                "last_name_column": "last_name",
                "mail_address_column": "mail_address",
                "mail_city_column": "mail_city",
                "mail_state_column": "mail_state",
                "mailing_zip_column": "mailing_zip",
                "trace_type": "normal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "message": "Queue created",
                      "queue_id": 456,
                      "status": "pending",
                      "created_at": "2025-01-02T10:15:00Z",
                      "rows_uploaded": 100,
                      "trace_type": "normal",
                      "credits_per_lead": 1,
                      "estimated_wait_seconds": 30,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Column not found in your data",
            "content": {
              "application/json": {
                "examples": {
                  "column_not_found_in_your_data": {
                    "summary": "Column not found in your data",
                    "value": {
                      "error": "Error in cleansing the data, please check the data and try again",
                      "details": "'address' Not found in the data or not a valid column name"
                    }
                  },
                  "no_usable_rows": {
                    "summary": "No usable rows",
                    "value": {
                      "error": "No valid rows found after data cleaning. Please check your data and try again."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits (prepaid account)",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits_prepaid_account": {
                    "summary": "Insufficient credits (prepaid account)",
                    "value": {
                      "error": "Insufficient credits for normal trace. You need 40 more credits to complete this request. Your account requires sufficient credits to upload. Please add credits to your account."
                    }
                  },
                  "insufficient_credits_monthly_billing_acc": {
                    "summary": "Insufficient credits (monthly billing account)",
                    "value": {
                      "error": "Insufficient credits for normal trace. You need 40 more credits to complete this request. Please add credits to your account or add a payment method for monthly billing."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 10 batch trace submissions per 5 minutes per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Queue limit exceeded. Max 10 queues per 5 minutes.",
                      "queues_in_window": "10"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Enhanced trace temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "enhanced_trace_temporarily_unavailable": {
                    "summary": "Enhanced trace temporarily unavailable",
                    "value": {
                      "error": "Enhanced trace is temporarily unavailable. Please contact support to enable enhanced bulk traces."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/trace/lookup/": {
      "post": {
        "tags": [
          "Skip Tracing"
        ],
        "operationId": "instantTraceLookup",
        "summary": "Instant Trace Lookup",
        "description": "[Try it free in the API Tester](/skip-tracing-api-documentation/tester/) (Mock mode, no credits)\n\nSynchronous skip trace for one address object or an array of up to 15 address objects. Returns responses immediately as JSON, no queue and no CSV. Ideal for one-off lookups or integrating skip trace data into your own UI at scale.\n\n**Array requests:** wrap up to 15 of the same objects in a JSON array. Results stay in input order, each item is validated and billed independently, and the response returns `results` plus aggregate `credits_deducted`.\n\n**5 credits per hit, 0 credits on miss.** Rate limited to 500 lookup items per minute per account; every object in an array counts as one item.\n\n**Two lookup modes:**\n\n- **find_owner: true** (default): send only address/city/state, returns the property owner(s) and their contact info\n- **find_owner: false**: include first_name + last_name to search for a specific person at the address\n\n**Response includes per person:** name, age, DOB, deceased flag, property owner flag, litigator flag, mailing address, all phones (with DNC + TCPA litigator status, carrier, type, rank), and all emails.\n\n**\u26a0\ufe0f Compliance:** Phones returning `litigator: true` or `dnc: true` should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.\n\n**Related endpoints:** [Enhanced Trace Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/enhanced/lookup/) \u00b7 [Parcel ID (APN) Batch Trace](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/parcel/) \u00b7 [Parcel ID (APN) Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/parcel/lookup/)",
        "x-credits": "5 credits per hit. 0 when nothing is found.",
        "x-rate-limit": "500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "Property street address"
                  },
                  "city": {
                    "type": "string",
                    "description": "Property city"
                  },
                  "state": {
                    "type": "string",
                    "description": "Property state (2-letter abbreviation)"
                  },
                  "zip": {
                    "type": "string",
                    "description": "Property ZIP code. Optional but **strongly recommended**, without it, results may match a different property at a similar address in the same city."
                  },
                  "find_owner": {
                    "type": "boolean",
                    "description": "`true` (default) (find property owner, no name needed. `false`) find a specific person at the address, requires first_name + last_name."
                  },
                  "first_name": {
                    "type": "string",
                    "description": "Person's first name. **Required when find_owner is false.**"
                  },
                  "last_name": {
                    "type": "string",
                    "description": "Person's last name. **Required when find_owner is false.**"
                  }
                },
                "required": [
                  "address",
                  "city",
                  "state"
                ]
              },
              "examples": {
                "owner_lookup_find_property_owner": {
                  "summary": "Owner lookup (find property owner)",
                  "value": {
                    "address": "123 Main St",
                    "city": "Austin",
                    "state": "TX",
                    "zip": "78701",
                    "find_owner": true
                  }
                },
                "person_lookup_find_specific_person_at_ad": {
                  "summary": "Person lookup (find specific person at address)",
                  "value": {
                    "address": "123 Main St",
                    "city": "Austin",
                    "state": "TX",
                    "zip": "78701",
                    "find_owner": false,
                    "first_name": "Jane",
                    "last_name": "Doe"
                  }
                },
                "array_lookup_up_to_15_objects": {
                  "summary": "Array lookup (up to 15 objects)",
                  "value": [
                    {
                      "address": "123 Main St",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701"
                    },
                    {
                      "address": "456 Oak Ave",
                      "city": "Dallas",
                      "state": "TX",
                      "zip": "75201"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Owner lookup hit (find_owner: true): 5 credits deducted",
            "content": {
              "application/json": {
                "examples": {
                  "owner_lookup_hit_find_owner_true_5_credi": {
                    "summary": "Owner lookup hit (find_owner: true): 5 credits deducted",
                    "value": {
                      "address": "123 Main St",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701",
                      "find_owner": true,
                      "hit": true,
                      "persons_count": 1,
                      "credits_deducted": 5,
                      "persons": [
                        {
                          "first_name": "Jane",
                          "last_name": "Doe",
                          "full_name": "Jane Doe",
                          "dob": "1985-03",
                          "age": "41",
                          "deceased": false,
                          "property_owner": true,
                          "litigator": false,
                          "mailing_address": {
                            "street": "PO Box 111",
                            "city": "Austin",
                            "state": "TX",
                            "zip": "78702"
                          },
                          "phones": [
                            {
                              "number": "5125550100",
                              "type": "Mobile",
                              "dnc": false,
                              "tcpa": false,
                              "carrier": "T-MOBILE USA INC.",
                              "rank": 1
                            },
                            {
                              "number": "5125550200",
                              "type": "Landline",
                              "dnc": true,
                              "tcpa": false,
                              "carrier": "AT&T TEXAS",
                              "rank": 2
                            }
                          ],
                          "emails": [
                            {
                              "email": "jane.doe@example.com",
                              "rank": 1
                            }
                          ]
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "person_lookup_hit_find_owner_false_5_cre": {
                    "summary": "Person lookup hit (find_owner: false): 5 credits deducted",
                    "value": {
                      "address": "123 Main St",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701",
                      "find_owner": false,
                      "hit": true,
                      "persons_count": 1,
                      "credits_deducted": 5,
                      "persons": [
                        {
                          "first_name": "John",
                          "last_name": "Smith",
                          "full_name": "John Smith",
                          "dob": "1978-11",
                          "age": "47",
                          "deceased": false,
                          "property_owner": false,
                          "litigator": false,
                          "mailing_address": {
                            "street": "456 Oak Ave",
                            "city": "Dallas",
                            "state": "TX",
                            "zip": "75201"
                          },
                          "phones": [
                            {
                              "number": "2145550300",
                              "type": "Mobile",
                              "dnc": false,
                              "tcpa": false,
                              "carrier": "VERIZON WIRELESS",
                              "rank": 1
                            }
                          ],
                          "emails": [
                            {
                              "email": "john.smith@example.com",
                              "rank": 1
                            }
                          ]
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "miss_no_results_found_0_credits_deducted": {
                    "summary": "Miss: no results found, 0 credits deducted",
                    "value": {
                      "address": "999 Nowhere Blvd",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701",
                      "find_owner": true,
                      "hit": false,
                      "persons_count": 0,
                      "credits_deducted": 0,
                      "persons": [],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "array_response": {
                    "summary": "Array response",
                    "value": {
                      "results": [
                        {
                          "address": "123 Main St",
                          "city": "Austin",
                          "state": "TX",
                          "zip": "78701",
                          "find_owner": true,
                          "hit": true,
                          "persons_count": 1,
                          "credits_deducted": 5,
                          "persons": [
                            {
                              "first_name": "Jane",
                              "last_name": "Doe",
                              "full_name": "Jane Doe",
                              "dob": "1985-03",
                              "age": "41",
                              "deceased": false,
                              "property_owner": true,
                              "litigator": false,
                              "mailing_address": {
                                "street": "PO Box 111",
                                "city": "Austin",
                                "state": "TX",
                                "zip": "78702"
                              },
                              "phones": [
                                {
                                  "number": "5125550100",
                                  "type": "Mobile",
                                  "dnc": false,
                                  "tcpa": false,
                                  "carrier": "T-MOBILE USA INC.",
                                  "rank": 1
                                },
                                {
                                  "number": "5125550200",
                                  "type": "Landline",
                                  "dnc": true,
                                  "tcpa": false,
                                  "carrier": "AT&T TEXAS",
                                  "rank": 2
                                }
                              ],
                              "emails": [
                                {
                                  "email": "jane.doe@example.com",
                                  "rank": 1
                                }
                              ]
                            }
                          ]
                        },
                        {
                          "address": "456 Oak Ave",
                          "city": "Dallas",
                          "state": "TX",
                          "zip": "75201",
                          "find_owner": true,
                          "hit": false,
                          "persons_count": 0,
                          "credits_deducted": 0,
                          "persons": []
                        }
                      ],
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing fields / name required for person lookup",
            "content": {
              "application/json": {
                "examples": {
                  "missing_fields_name_required_for_person_": {
                    "summary": "Missing fields / name required for person lookup",
                    "value": {
                      "non_field_errors": [
                        "first_name and last_name are required when find_owner is false."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. Instant trace requires 5 credits per lookup. You have 0 credits."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Rate limit exceeded. Max 500 lookups per minute.",
                      "lookups_in_window": "501",
                      "retry_after_seconds": "60"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Skip trace service temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "skip_trace_service_temporarily_unavailab": {
                    "summary": "Skip trace service temporarily unavailable",
                    "value": {
                      "error": "Skip trace service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/trace/enhanced/lookup/": {
      "post": {
        "tags": [
          "Skip Tracing"
        ],
        "operationId": "enhancedTraceLookup",
        "summary": "Enhanced Trace Lookup",
        "description": "[Try it free in the API Tester](/skip-tracing-api-documentation/tester/) (Mock mode, no credits)\n\nFind a property owner and enhanced contact data from one address, or target a specific person you already know. Send one object or an array of up to 15 objects.\n\n**Array requests:** results stay in input order, each item is validated and billed independently, and the response returns `results` plus aggregate `credits_deducted`.\n\n**Two search modes:**\n\n- **Owner search:** set `find_owner: true` and enter the property address. No name is needed.\n- **Specific-person search:** set `find_owner: false` or omit it, then enter first name, last name, and the associated address.\n\n**15 credits per hit, 0 credits on miss.** Rate limited to 500 lookup items per minute per account through the shared instant-lookup counter; every object in an array counts as one item.\n\n**Response includes:** available phones, emails, mailing address, linked/historical addresses, age data, and up to 2 relatives or associated people. Every phone, including relatives' phones, comes with `type`, `dnc`, and `tcpa` flags.\n\n**Use this when:** you need more owner or person context than a standard trace provides.\n\n**Related endpoints:** [Parcel ID (APN) Batch Trace](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/parcel/) \u00b7 [Parcel ID (APN) Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/parcel/lookup/) \u00b7 [List Trace Jobs](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queues/)",
        "x-credits": "15 credits per hit. 0 when nothing is found.",
        "x-rate-limit": "500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "find_owner": {
                    "type": "boolean",
                    "description": "Set `true` for an address-only owner search. Set `false` or omit it for a specific-person search."
                  },
                  "first_name": {
                    "type": "string",
                    "description": "Required only for a specific-person search; ignored when `find_owner` is true."
                  },
                  "last_name": {
                    "type": "string",
                    "description": "Required only for a specific-person search; ignored when `find_owner` is true."
                  },
                  "address": {
                    "type": "string",
                    "description": "Property or associated street address."
                  },
                  "city": {
                    "type": "string",
                    "description": "City associated with the address."
                  },
                  "state": {
                    "type": "string",
                    "description": "State associated with the address (2-letter abbreviation)."
                  },
                  "zip": {
                    "type": "string",
                    "description": "Associated ZIP code. Optional but recommended."
                  }
                },
                "required": [
                  "address",
                  "city",
                  "state"
                ]
              },
              "examples": {
                "example": {
                  "summary": "One object",
                  "value": {
                    "find_owner": true,
                    "address": "123 Main St",
                    "city": "Austin",
                    "state": "TX",
                    "zip": "78701"
                  }
                },
                "array_lookup_up_to_15_objects": {
                  "summary": "Array lookup (up to 15 objects)",
                  "value": [
                    {
                      "find_owner": true,
                      "address": "123 Main St",
                      "city": "Austin",
                      "state": "TX"
                    },
                    {
                      "find_owner": true,
                      "address": "456 Oak Ave",
                      "city": "Dallas",
                      "state": "TX"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "address": "123 Main St",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701",
                      "find_owner": true,
                      "hit": true,
                      "persons_count": 1,
                      "relatives_count": 2,
                      "credits_deducted": 15,
                      "persons": [
                        {
                          "first_name": "Jane",
                          "last_name": "Doe",
                          "full_name": "Jane Doe",
                          "dob": "1985-03",
                          "age": "41",
                          "deceased": false,
                          "property_owner": true,
                          "litigator": false,
                          "mailing_address": {
                            "street": "PO Box 111",
                            "city": "Austin",
                            "state": "TX",
                            "zip": "78702"
                          },
                          "phones": [
                            {
                              "number": "5125550100",
                              "type": "Mobile",
                              "dnc": false,
                              "tcpa": false,
                              "carrier": "T-MOBILE USA INC.",
                              "rank": 1
                            }
                          ],
                          "emails": [
                            {
                              "email": "jane.doe@example.com",
                              "rank": 1
                            }
                          ],
                          "address_history": [
                            {
                              "street": "PO Box 111",
                              "city": "Austin",
                              "state": "TX",
                              "zip": "78702",
                              "property_mailing_address": true,
                              "rank": 1
                            },
                            {
                              "street": "456 Oak Ave",
                              "city": "Dallas",
                              "state": "TX",
                              "zip": "75201",
                              "property_mailing_address": false,
                              "rank": 2
                            }
                          ],
                          "relatives": [
                            {
                              "first_name": "John",
                              "middle_name": "",
                              "last_name": "Doe",
                              "full_name": "John Doe",
                              "age": 69,
                              "dob": "1957-04",
                              "deceased": false,
                              "phones": [
                                {
                                  "number": "5125550200",
                                  "type": "Mobile",
                                  "dnc": true,
                                  "tcpa": false,
                                  "carrier": "VERIZON WIRELESS",
                                  "rank": 1
                                }
                              ],
                              "emails": [
                                {
                                  "email": "john.doe@example.com",
                                  "rank": 1
                                }
                              ],
                              "rank": 1
                            },
                            {
                              "first_name": "Mary",
                              "middle_name": "A",
                              "last_name": "Doe",
                              "full_name": "Mary A Doe",
                              "age": 64,
                              "dob": "1962-09",
                              "deceased": false,
                              "phones": [],
                              "emails": [],
                              "rank": 2
                            }
                          ]
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "array_response": {
                    "summary": "Array response",
                    "value": {
                      "results": [
                        {
                          "address": "123 Main St",
                          "city": "Austin",
                          "state": "TX",
                          "zip": "78701",
                          "find_owner": true,
                          "hit": true,
                          "persons_count": 1,
                          "relatives_count": 2,
                          "credits_deducted": 15,
                          "persons": [
                            {
                              "first_name": "Jane",
                              "last_name": "Doe",
                              "full_name": "Jane Doe",
                              "dob": "1985-03",
                              "age": "41",
                              "deceased": false,
                              "property_owner": true,
                              "litigator": false,
                              "mailing_address": {
                                "street": "PO Box 111",
                                "city": "Austin",
                                "state": "TX",
                                "zip": "78702"
                              },
                              "phones": [
                                {
                                  "number": "5125550100",
                                  "type": "Mobile",
                                  "dnc": false,
                                  "tcpa": false,
                                  "carrier": "T-MOBILE USA INC.",
                                  "rank": 1
                                }
                              ],
                              "emails": [
                                {
                                  "email": "jane.doe@example.com",
                                  "rank": 1
                                }
                              ],
                              "address_history": [
                                {
                                  "street": "PO Box 111",
                                  "city": "Austin",
                                  "state": "TX",
                                  "zip": "78702",
                                  "property_mailing_address": true,
                                  "rank": 1
                                },
                                {
                                  "street": "456 Oak Ave",
                                  "city": "Dallas",
                                  "state": "TX",
                                  "zip": "75201",
                                  "property_mailing_address": false,
                                  "rank": 2
                                }
                              ],
                              "relatives": [
                                {
                                  "first_name": "John",
                                  "middle_name": "",
                                  "last_name": "Doe",
                                  "full_name": "John Doe",
                                  "age": 69,
                                  "dob": "1957-04",
                                  "deceased": false,
                                  "phones": [
                                    {
                                      "number": "5125550200",
                                      "type": "Mobile",
                                      "dnc": true,
                                      "tcpa": false,
                                      "carrier": "VERIZON WIRELESS",
                                      "rank": 1
                                    }
                                  ],
                                  "emails": [
                                    {
                                      "email": "john.doe@example.com",
                                      "rank": 1
                                    }
                                  ],
                                  "rank": 1
                                },
                                {
                                  "first_name": "Mary",
                                  "middle_name": "A",
                                  "last_name": "Doe",
                                  "full_name": "Mary A Doe",
                                  "age": 64,
                                  "dob": "1962-09",
                                  "deceased": false,
                                  "phones": [],
                                  "emails": [],
                                  "rank": 2
                                }
                              ]
                            }
                          ]
                        },
                        {
                          "address": "456 Oak Ave",
                          "city": "Dallas",
                          "state": "TX",
                          "zip": "78701",
                          "find_owner": true,
                          "hit": true,
                          "persons_count": 1,
                          "relatives_count": 2,
                          "credits_deducted": 15,
                          "persons": [
                            {
                              "first_name": "Jane",
                              "last_name": "Doe",
                              "full_name": "Jane Doe",
                              "dob": "1985-03",
                              "age": "41",
                              "deceased": false,
                              "property_owner": true,
                              "litigator": false,
                              "mailing_address": {
                                "street": "PO Box 111",
                                "city": "Austin",
                                "state": "TX",
                                "zip": "78702"
                              },
                              "phones": [
                                {
                                  "number": "5125550100",
                                  "type": "Mobile",
                                  "dnc": false,
                                  "tcpa": false,
                                  "carrier": "T-MOBILE USA INC.",
                                  "rank": 1
                                }
                              ],
                              "emails": [
                                {
                                  "email": "jane.doe@example.com",
                                  "rank": 1
                                }
                              ],
                              "address_history": [
                                {
                                  "street": "PO Box 111",
                                  "city": "Austin",
                                  "state": "TX",
                                  "zip": "78702",
                                  "property_mailing_address": true,
                                  "rank": 1
                                },
                                {
                                  "street": "456 Oak Ave",
                                  "city": "Dallas",
                                  "state": "TX",
                                  "zip": "75201",
                                  "property_mailing_address": false,
                                  "rank": 2
                                }
                              ],
                              "relatives": [
                                {
                                  "first_name": "John",
                                  "middle_name": "",
                                  "last_name": "Doe",
                                  "full_name": "John Doe",
                                  "age": 69,
                                  "dob": "1957-04",
                                  "deceased": false,
                                  "phones": [
                                    {
                                      "number": "5125550200",
                                      "type": "Mobile",
                                      "dnc": true,
                                      "tcpa": false,
                                      "carrier": "VERIZON WIRELESS",
                                      "rank": 1
                                    }
                                  ],
                                  "emails": [
                                    {
                                      "email": "john.doe@example.com",
                                      "rank": 1
                                    }
                                  ],
                                  "rank": 1
                                },
                                {
                                  "first_name": "Mary",
                                  "middle_name": "A",
                                  "last_name": "Doe",
                                  "full_name": "Mary A Doe",
                                  "age": 64,
                                  "dob": "1962-09",
                                  "deceased": false,
                                  "phones": [],
                                  "emails": [],
                                  "rank": 2
                                }
                              ]
                            }
                          ]
                        }
                      ],
                      "credits_deducted": 30,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Person name required in named mode",
            "content": {
              "application/json": {
                "examples": {
                  "person_name_required_in_named_mode": {
                    "summary": "Person name required in named mode",
                    "value": {
                      "first_name": [
                        "This field is required."
                      ],
                      "last_name": [
                        "This field is required."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. Enhanced trace requires 15 credits per hit. You have 0 credits."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Rate limit exceeded. Max 500 lookups per minute.",
                      "lookups_in_window": "501",
                      "retry_after_seconds": "60"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Enhanced trace temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "enhanced_trace_temporarily_unavailable": {
                    "summary": "Enhanced trace temporarily unavailable",
                    "value": {
                      "error": "Enhanced trace is temporarily unavailable. Please contact support to enable enhanced lookups."
                    }
                  },
                  "owner_mode_find_owner_true_temporarily_u": {
                    "summary": "Owner mode (find_owner: true) temporarily unavailable",
                    "value": {
                      "error": "Address-only Enhanced Trace is temporarily unavailable. Please try a named-person lookup."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/trace/parcel/": {
      "post": {
        "tags": [
          "Skip Tracing"
        ],
        "operationId": "parcelIDApnBatchTrace",
        "summary": "Parcel ID (APN) Batch Trace",
        "description": "Submit a batch of parcel IDs (APNs) for skip tracing. Each parcel is looked up to find the property owner's contact information, name, mailing address, phones with DNC + TCPA litigator flags and carrier, and emails.\n\n**5 credits per hit, 0 on miss.** Rows with no match still appear in the CSV with empty contact columns.\n\nResults are delivered asynchronously via a CSV download URL. Poll the queue endpoint `GET /v1/api/trace/parcel/queue/:id` for status, or set a webhook URL in your account to get notified on completion.\n\n**APN format:** the `#` prefix is optional and will be stripped automatically. Parcel IDs are formatted internally to match the standard APN format for each county.\n\n**Rate limit:** refused while your account has 10 batch trace submissions in the last 5 minutes.\n\n**Related endpoints:** [Parcel ID (APN) Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/parcel/lookup/) \u00b7 [List Trace Jobs](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queues/) \u00b7 [Get One Trace Job](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queue/{id})",
        "x-credits": "5 credits per hit. Rows with no match cost nothing.",
        "x-rate-limit": "Refused while your account has 10 batch trace submissions in the last 5 minutes.",
        "x-mode": "Async: returns a queue ID, results arrive by download link and webhook.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "csv_file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV file with parcel ID, county, and state columns."
                  },
                  "parcel_id_column": {
                    "type": "string",
                    "description": "Name of the column containing parcel IDs."
                  },
                  "county_column": {
                    "type": "string",
                    "description": "Name of the column containing county names."
                  },
                  "state_column": {
                    "type": "string",
                    "description": "Name of the column containing state abbreviations (e.g. FL, TX)."
                  }
                },
                "required": [
                  "csv_file",
                  "parcel_id_column",
                  "county_column",
                  "state_column"
                ]
              },
              "example": {
                "csv_file": "@parcels.csv",
                "parcel_id_column": "parcel_id",
                "county_column": "county",
                "state_column": "state"
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "parcel_id_column": {
                    "type": "string",
                    "description": "Name of the column containing parcel IDs."
                  },
                  "county_column": {
                    "type": "string",
                    "description": "Name of the column containing county names."
                  },
                  "state_column": {
                    "type": "string",
                    "description": "Name of the column containing state abbreviations (e.g. FL, TX)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "message": "Parcel trace started",
                      "parcel_queue_id": 42,
                      "created_at": "2026-04-07T12:00:00Z",
                      "status": "pending",
                      "rows_uploaded": 500,
                      "credits_per_parcel": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Column not found in your data",
            "content": {
              "application/json": {
                "examples": {
                  "column_not_found_in_your_data": {
                    "summary": "Column not found in your data",
                    "value": {
                      "error": "Column \"parcel_id\" not found in data. Available: ['apn', 'county', 'state']"
                    }
                  },
                  "no_usable_parcel_ids": {
                    "summary": "No usable parcel IDs",
                    "value": {
                      "error": "No valid parcel IDs found after cleaning."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. Parcel trace requires 5 credits per hit (worst case 2500 credits for 500 parcels). You have 0 credits."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Account suspended (unpaid invoices)",
            "content": {
              "application/json": {
                "examples": {
                  "account_suspended_unpaid_invoices": {
                    "summary": "Account suspended (unpaid invoices)",
                    "value": {
                      "error": "Your account has been temporarily suspended due to unpaid invoices. Please contact support@tracerfy.com to resolve outstanding payments."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: Refused while your account has 10 batch trace submissions in the last 5 minutes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Queue limit exceeded. Max 10 queues per 5 minutes.",
                      "queues_in_window": "10"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/trace/parcel/lookup/": {
      "post": {
        "tags": [
          "Skip Tracing"
        ],
        "operationId": "parcelIDApnLookup",
        "summary": "Parcel ID (APN) Lookup",
        "description": "Synchronous parcel skip trace for one parcel object or an array of up to 15 parcel objects. Returns owner contact info immediately as JSON, no queue, no CSV, no polling.\n\n**Array requests:** results stay in input order, each item is validated and billed independently, and the response returns `results` plus aggregate `credits_deducted`.\n\n**5 credits per hit, 0 on miss.**\n\nThe response includes the owner contact fields the batch CSV delivers: owner name, mailing address, all phones with DNC + TCPA litigator flags and carrier, emails, plus `property_owner`, `deceased`, `litigator`, and `age`.\n\n**APN format:** the `#` prefix is optional.\n\n**Rate limit:** 500 lookup items per minute per account; every object in an array counts as one item.\n\n**\u26a0\ufe0f Compliance:** Phones returning `litigator: true` or `dnc: true` should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.\n\n**Related endpoints:** [List Trace Jobs](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queues/) \u00b7 [Get One Trace Job](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queue/{id}) \u00b7 [Batch Trace](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/)",
        "x-credits": "5 credits per hit. 0 when nothing is found.",
        "x-rate-limit": "500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "parcel_id": {
                    "type": "string",
                    "description": "The parcel ID (APN). The '#' prefix is optional and will be stripped automatically."
                  },
                  "county": {
                    "type": "string",
                    "description": "County name (e.g. 'Palm Beach')."
                  },
                  "state": {
                    "type": "string",
                    "description": "State abbreviation (e.g. 'FL')."
                  }
                },
                "required": [
                  "parcel_id",
                  "county",
                  "state"
                ]
              },
              "examples": {
                "example": {
                  "summary": "One object",
                  "value": {
                    "parcel_id": "#00424109000007550",
                    "county": "Palm Beach",
                    "state": "FL"
                  }
                },
                "array_lookup_up_to_15_objects": {
                  "summary": "Array lookup (up to 15 objects)",
                  "value": [
                    {
                      "parcel_id": "00424109000007550",
                      "county": "Palm Beach",
                      "state": "FL"
                    },
                    {
                      "parcel_id": "00424109000007560",
                      "county": "Palm Beach",
                      "state": "FL"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hit: 5 credits deducted",
            "content": {
              "application/json": {
                "examples": {
                  "hit_5_credits_deducted": {
                    "summary": "Hit: 5 credits deducted",
                    "value": {
                      "parcel_id": "#00424109000007550",
                      "county": "Palm Beach",
                      "state": "FL",
                      "hit": true,
                      "persons_count": 1,
                      "credits_deducted": 5,
                      "persons": [
                        {
                          "first_name": "John",
                          "last_name": "Smith",
                          "full_name": "John Smith",
                          "dob": "1975-03",
                          "age": "51",
                          "deceased": false,
                          "property_owner": true,
                          "litigator": false,
                          "mailing_address": {
                            "street": "456 Oak Ave",
                            "city": "West Palm Beach",
                            "state": "FL",
                            "zip": "33401"
                          },
                          "phones": [
                            {
                              "number": "5615550100",
                              "type": "Mobile",
                              "dnc": false,
                              "tcpa": false,
                              "carrier": "T-MOBILE USA INC.",
                              "rank": 1
                            },
                            {
                              "number": "5615550200",
                              "type": "Landline",
                              "dnc": true,
                              "tcpa": false,
                              "carrier": "BELLSOUTH TELECOMM INC",
                              "rank": 2
                            }
                          ],
                          "emails": [
                            {
                              "email": "jsmith@example.com",
                              "rank": 1
                            },
                            {
                              "email": "john.smith@example.net",
                              "rank": 2
                            }
                          ]
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "miss_0_credits": {
                    "summary": "Miss: 0 credits",
                    "value": {
                      "parcel_id": "#00404033000001190",
                      "county": "Palm Beach",
                      "state": "FL",
                      "hit": false,
                      "persons_count": 0,
                      "credits_deducted": 0,
                      "persons": [],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "array_response": {
                    "summary": "Array response",
                    "value": {
                      "results": [
                        {
                          "parcel_id": "00424109000007550",
                          "county": "Palm Beach",
                          "state": "FL",
                          "hit": true,
                          "persons_count": 1,
                          "credits_deducted": 5,
                          "persons": [
                            {
                              "first_name": "John",
                              "last_name": "Smith",
                              "full_name": "John Smith",
                              "dob": "1975-03",
                              "age": "51",
                              "deceased": false,
                              "property_owner": true,
                              "litigator": false,
                              "mailing_address": {
                                "street": "456 Oak Ave",
                                "city": "West Palm Beach",
                                "state": "FL",
                                "zip": "33401"
                              },
                              "phones": [
                                {
                                  "number": "5615550100",
                                  "type": "Mobile",
                                  "dnc": false,
                                  "tcpa": false,
                                  "carrier": "T-MOBILE USA INC.",
                                  "rank": 1
                                },
                                {
                                  "number": "5615550200",
                                  "type": "Landline",
                                  "dnc": true,
                                  "tcpa": false,
                                  "carrier": "BELLSOUTH TELECOMM INC",
                                  "rank": 2
                                }
                              ],
                              "emails": [
                                {
                                  "email": "jsmith@example.com",
                                  "rank": 1
                                },
                                {
                                  "email": "john.smith@example.net",
                                  "rank": 2
                                }
                              ]
                            }
                          ]
                        },
                        {
                          "parcel_id": "00424109000007560",
                          "county": "Palm Beach",
                          "state": "FL",
                          "hit": false,
                          "persons_count": 0,
                          "credits_deducted": 0,
                          "persons": []
                        }
                      ],
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing parcel_id / county / state",
            "content": {
              "application/json": {
                "examples": {
                  "missing_parcel_id_county_state": {
                    "summary": "Missing parcel_id / county / state",
                    "value": {
                      "parcel_id": [
                        "This field is required."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. Parcel trace requires 5 credits per lookup. You have 0 credits."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Account suspended (unpaid invoices)",
            "content": {
              "application/json": {
                "examples": {
                  "account_suspended_unpaid_invoices": {
                    "summary": "Account suspended (unpaid invoices)",
                    "value": {
                      "error": "Your account has been temporarily suspended due to unpaid invoices. Please contact support@tracerfy.com to resolve outstanding payments."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Rate limit exceeded. Max 500 lookups per minute.",
                      "lookups_in_window": "501",
                      "retry_after_seconds": "60"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Skip trace service temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "skip_trace_service_temporarily_unavailab": {
                    "summary": "Skip trace service temporarily unavailable",
                    "value": {
                      "error": "Skip trace service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/queues/": {
      "get": {
        "tags": [
          "Skip Tracing"
        ],
        "operationId": "listTraceJobs",
        "summary": "List Trace Jobs",
        "description": "Returns the authenticated user's queues as a JSON array, ordered by most recent first. Each queue represents a trace job created via API or the app. While a queue is pending, `rows_uploaded` and `credits_deducted` are hidden; when complete, `download_url` is populated with a CSV link.\n\nUp to **100 queues per page**. Pass `?page=N` to walk back through history. Pagination metadata is in the response headers, `X-Total-Count` for the total, and `Link` for navigation:\n\n**Related endpoints:** [Get One Trace Job](/skip-tracing-api-documentation/tag/skip-tracing/GET/v1/api/queue/{id}) \u00b7 [Batch Trace](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/) \u00b7 [Instant Trace Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/lookup/)",
        "x-credits": "Free.",
        "x-rate-limit": "1 request per 20 seconds per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page number to return. Default: 1. 100 queues per page."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": [
                      {
                        "id": 124,
                        "created_at": "2025-01-02T09:30:00Z",
                        "pending": true,
                        "download_url": null,
                        "queue_type": "api",
                        "trace_type": "normal",
                        "credits_per_lead": 1
                      },
                      {
                        "id": 123,
                        "created_at": "2025-01-01T12:00:00Z",
                        "pending": false,
                        "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/9a584124-77c2-4612-b8e9-f9efe6fbdc3d.csv",
                        "rows_uploaded": 2500,
                        "credits_deducted": 2500,
                        "queue_type": "api",
                        "trace_type": "normal",
                        "credits_per_lead": 1
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit reached: 1 request per 20 seconds per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "error": "Rate limit exceeded. Retry in intervals of 20 seconds.",
                      "retry_in": "3 seconds"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/queue/{id}": {
      "get": {
        "tags": [
          "Skip Tracing"
        ],
        "operationId": "getOneTraceJob",
        "summary": "Get One Trace Job",
        "description": "Returns the property records associated with a queue's posted addresses. Object-level permission enforced: only the queue owner can access. Null contact fields are normalized to empty strings in the response.\n\n**One record per input row that produced a match.** Input rows where no person was found at the address don't appear in this response, there's no record to return. For the full row-aligned view (every input row alongside whatever was found, including misses), use the CSV at `download_url` on the queue object, that file contains all rows you submitted, with empty contact columns for rows that didn't match.\n\n**Response varies based on trace_type:**\n\n- **Normal Trace** (trace_type='normal'): Returns basic property contact data (phones and emails)\n- **Advanced Trace** (trace_type='advanced'): Finds the property owner and returns their contact data (name, phones, emails and mailing address)\n- **Enhanced Trace** (trace_type='enhanced'): Targets the supplied person by name and address, returning enhanced contact context such as linked addresses and possible relatives when available\n\n**Related endpoints:** [Batch Trace](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/) \u00b7 [Instant Trace Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/lookup/) \u00b7 [Enhanced Trace Lookup](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/enhanced/lookup/)",
        "x-credits": "Free.",
        "x-rate-limit": "No limit.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Queue ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Normal Trace Response (trace_type='normal')",
            "content": {
              "application/json": {
                "examples": {
                  "normal_trace_response_trace_type_normal": {
                    "summary": "Normal Trace Response (trace_type='normal')",
                    "value": [
                      {
                        "address": "123 Main St",
                        "city": "Austin",
                        "state": "TX",
                        "mail_address": "PO Box 111",
                        "mail_city": "Austin",
                        "mail_state": "TX",
                        "first_name": "Jane",
                        "last_name": "Doe",
                        "primary_phone": "5125550100",
                        "primary_phone_type": "Mobile",
                        "email_1": "jane@example.com",
                        "email_2": "",
                        "email_3": "",
                        "email_4": "",
                        "email_5": "",
                        "mobile_1": "5125550100",
                        "mobile_2": "",
                        "mobile_3": "",
                        "mobile_4": "",
                        "mobile_5": "",
                        "landline_1": "",
                        "landline_2": "",
                        "landline_3": ""
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Queue belongs to another account",
            "content": {
              "application/json": {
                "examples": {
                  "queue_belongs_to_another_account": {
                    "summary": "Queue belongs to another account",
                    "value": {
                      "error": "You do not have permission to access this queue."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No queue with that ID",
            "content": {
              "application/json": {
                "examples": {
                  "no_queue_with_that_id": {
                    "summary": "No queue with that ID",
                    "value": {
                      "error": "No Queue Found with ID 123"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/phone/verify/": {
      "post": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "phoneVerification",
        "summary": "Phone Verification",
        "description": "[Try it free in the API Tester](/skip-tracing-api-documentation/tester/) (Mock mode, no credits)\n\nSynchronous phone intelligence endpoint. Send one phone object or an array of up to 15 phone objects and get back line type, carrier, last-seen date, returned DNC/TCPA flags, returned state DNC codes, contactability, and light associated-person context.\n\n**Array requests:** results stay in input order, each item is validated and billed independently, and the response returns `results` plus aggregate `credits_deducted`.\n\n**5 credits per hit, 0 credits on miss.** Rate limited to 500 lookup items per minute per account through the shared instant-lookup counter; every object in an array counts as one item.\n\n**Different from reverse phone append:** this endpoint is not meant to return every person, address, email, and phone connected to the number. It verifies the searched phone itself and returns compact CRM-safe status fields.\n\n**state_dnc:** returned as an array of state codes, for example `[\"TX\"]`. An empty array means no provider-returned state DNC flag was found; it is not a full legal clearance across every state registry.\n\n**contactable:** true only when the returned suppression fields are not flagged. It is not legal advice and does not create consent.\n\n**Related endpoints:** [DNC Scrub](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub/) \u00b7 [DNC Scrub from a Trace](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub-from-queue/) \u00b7 [DNC Lookup](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/lookup/)",
        "x-credits": "5 credits per hit. 0 when nothing is found.",
        "x-rate-limit": "500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "description": "10-digit US phone number. Formatting is stripped automatically, including dashes, spaces, parentheses, and a leading country code 1."
                  }
                },
                "required": [
                  "phone"
                ]
              },
              "examples": {
                "example": {
                  "summary": "One object",
                  "value": {
                    "phone": "(512) 555-0100"
                  }
                },
                "array_lookup_up_to_15_objects": {
                  "summary": "Array lookup (up to 15 objects)",
                  "value": [
                    {
                      "phone": "5125550100"
                    },
                    {
                      "phone": "5125550101"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hit: 5 credits deducted",
            "content": {
              "application/json": {
                "examples": {
                  "hit_5_credits_deducted": {
                    "summary": "Hit: 5 credits deducted",
                    "value": {
                      "phone": "5125550100",
                      "hit": true,
                      "line_type": "Mobile",
                      "carrier": "T-MOBILE USA INC.",
                      "last_seen": "2026-07-01",
                      "dnc": false,
                      "tcpa": false,
                      "state_dnc": [],
                      "contactable": true,
                      "associated_persons_count": 1,
                      "associated_persons": [
                        {
                          "first_name": "Jane",
                          "last_name": "Doe",
                          "full_name": "Jane Doe",
                          "age": "41",
                          "city": "Austin",
                          "state": "TX"
                        }
                      ],
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "hit_with_returned_suppression_flags_dete": {
                    "summary": "Hit with returned suppression flags (determined based on dnc flags), 5 credits deducted",
                    "value": {
                      "phone": "5125550100",
                      "hit": true,
                      "line_type": "Mobile",
                      "carrier": "T-MOBILE USA INC.",
                      "last_seen": "2026-07-01",
                      "dnc": true,
                      "tcpa": false,
                      "state_dnc": [
                        "TX"
                      ],
                      "contactable": false,
                      "associated_persons_count": 1,
                      "associated_persons": [
                        {
                          "first_name": "Jane",
                          "last_name": "Doe",
                          "full_name": "Jane Doe",
                          "age": "41",
                          "city": "Austin",
                          "state": "TX"
                        }
                      ],
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "miss_0_credits_deducted": {
                    "summary": "Miss: 0 credits deducted",
                    "value": {
                      "phone": "5125559999",
                      "hit": false,
                      "line_type": "",
                      "carrier": "",
                      "last_seen": "",
                      "dnc": false,
                      "tcpa": false,
                      "state_dnc": [],
                      "contactable": false,
                      "associated_persons_count": 0,
                      "associated_persons": [],
                      "credits_deducted": 0,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "array_response": {
                    "summary": "Array response",
                    "value": {
                      "results": [
                        {
                          "phone": "5125550100",
                          "hit": true,
                          "line_type": "Mobile",
                          "carrier": "T-MOBILE USA INC.",
                          "last_seen": "2026-07-01",
                          "dnc": false,
                          "tcpa": false,
                          "state_dnc": [],
                          "contactable": true,
                          "associated_persons_count": 1,
                          "associated_persons": [
                            {
                              "first_name": "Jane",
                              "last_name": "Doe",
                              "full_name": "Jane Doe",
                              "age": "41",
                              "city": "Austin",
                              "state": "TX"
                            }
                          ],
                          "credits_deducted": 5
                        },
                        {
                          "phone": "5125550101",
                          "hit": false,
                          "line_type": "",
                          "carrier": "",
                          "last_seen": "",
                          "dnc": false,
                          "tcpa": false,
                          "state_dnc": [],
                          "contactable": false,
                          "associated_persons_count": 0,
                          "associated_persons": [],
                          "credits_deducted": 0
                        }
                      ],
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid phone",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_phone": {
                    "summary": "Invalid phone",
                    "value": {
                      "phone": [
                        "Enter a valid 10-digit US phone number."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. Phone verification requires 5 credits per hit. You have 0 credits."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Rate limit exceeded. Max 500 lookups per minute.",
                      "lookups_in_window": "501",
                      "retry_after_seconds": "60"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Phone verification temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "phone_verification_temporarily_unavailab": {
                    "summary": "Phone verification temporarily unavailable",
                    "value": {
                      "error": "Phone verification is temporarily unavailable. Please contact support to enable phone verification."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/api/dnc/scrub/": {
      "post": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "dncScrub",
        "summary": "DNC Scrub",
        "description": "Submit a phone list for DNC (Do Not Call) scrubbing. Upload a CSV with one or more phone columns, or pass a JSON array of phone numbers directly. Each phone is checked against the Federal DNC registry, state DNC registries, and known TCPA litigator records. 1 credit per phone checked.\n\nSee [DNC API Versions](/skip-tracing-api-documentation/tag/phone-verification-dnc) for the result fields.\n\n**Input options (pick one):**\n\n- **CSV with single column**: csv_file + phone_column (string)\n- **CSV with multiple columns**: csv_file + phone_columns (array), phones are merged &amp; deduplicated\n- **JSON phone list**: phones array via application/json\n\n**Result CSV columns:** `phone, label, national_dnc, state_dnc, state_dnc_list, litigator, is_clean`.\n\n**Related endpoints:** [DNC Scrub from a Trace](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub-from-queue/) \u00b7 [DNC Lookup](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/lookup/) \u00b7 [Get One DNC Job](/skip-tracing-api-documentation/tag/phone-verification-dnc/GET/v2/api/dnc/queue/{id})",
        "x-credits": "1 credit per phone checked, charged when the job finishes.",
        "x-rate-limit": "10 scrubs per 5 minutes per account.",
        "x-mode": "Async: returns a job ID, results arrive by download link and webhook.",
        "requestBody": {
          "required": false,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "csv_file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV file containing phone numbers. Required for Options 1 & 2. Do not send with phones."
                  },
                  "phone_column": {
                    "type": "string",
                    "description": "Single column name containing phone numbers (Option 1). Internally normalized to phone_columns. Mutually exclusive with phone_columns."
                  },
                  "phone_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of column names containing phone numbers (Option 2). Phones are merged & deduplicated. When multiple columns are used, labels are prefixed with the column name, e.g. '(Phone_1) John Doe'. Mutually exclusive with phone_column."
                  },
                  "label_column": {
                    "type": "string",
                    "description": "Single column to label each phone (e.g., name). Internally normalized to label_columns. Mutually exclusive with label_columns."
                  },
                  "label_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of columns to combine as a label for each phone (e.g., [\"address\", \"city\", \"state\"]). Values are joined with commas. When using multiple phone_columns, labels are also prefixed with the column name."
                  },
                  "phones": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Direct list of phone numbers via JSON body (Option 3). Do not send with csv_file."
                  }
                }
              },
              "example": {
                "csv_file": "@/path/to/phones.csv",
                "phone_column": "Phone",
                "label_column": "Name"
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone_column": {
                    "type": "string",
                    "description": "Single column name containing phone numbers (Option 1). Internally normalized to phone_columns. Mutually exclusive with phone_columns."
                  },
                  "phone_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of column names containing phone numbers (Option 2). Phones are merged & deduplicated. When multiple columns are used, labels are prefixed with the column name, e.g. '(Phone_1) John Doe'. Mutually exclusive with phone_column."
                  },
                  "label_column": {
                    "type": "string",
                    "description": "Single column to label each phone (e.g., name). Internally normalized to label_columns. Mutually exclusive with label_columns."
                  },
                  "label_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of columns to combine as a label for each phone (e.g., [\"address\", \"city\", \"state\"]). Values are joined with commas. When using multiple phone_columns, labels are also prefixed with the column name."
                  },
                  "phones": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Direct list of phone numbers via JSON body (Option 3). Do not send with csv_file."
                  }
                }
              },
              "examples": {
                "json_phone_list_no_csv": {
                  "summary": "JSON phone list (no CSV)",
                  "value": {
                    "phones": [
                      "5125550100",
                      "5125550101",
                      "5125550102"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "message": "DNC scrub started",
                      "dnc_queue_id": 5,
                      "created_at": "2025-01-15T09:30:00Z",
                      "status": "pending",
                      "phones_to_check": 150,
                      "credits_per_phone": 1,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Phone column not found in your CSV",
            "content": {
              "application/json": {
                "examples": {
                  "phone_column_not_found_in_your_csv": {
                    "summary": "Phone column not found in your CSV",
                    "value": {
                      "error": "Column \"Phone\" not found in CSV"
                    }
                  },
                  "no_usable_phone_numbers": {
                    "summary": "No usable phone numbers",
                    "value": {
                      "error": "No valid phone numbers found"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. You need 150 credits for DNC scrubbing. You have 0."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Account suspended (unpaid invoices)",
            "content": {
              "application/json": {
                "examples": {
                  "account_suspended_unpaid_invoices": {
                    "summary": "Account suspended (unpaid invoices)",
                    "value": {
                      "error": "Account suspended due to unpaid invoices."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 10 scrubs per 5 minutes per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "DNC scrub limit exceeded. Max 10 scrubs per 5 minutes.",
                      "queues_in_window": "10"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/api/dnc/scrub-from-queue/": {
      "post": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "dncScrubFromATrace",
        "summary": "DNC Scrub from a Trace",
        "description": "Extract phone numbers from a completed trace queue and submit them for DNC scrubbing. Optionally specify which phone columns to include. Phones are deduplicated across all selected columns. 1 credit per phone checked.\n\n**Valid phone_columns:** primary_phone, mobile_1, mobile_2, mobile_3, mobile_4, mobile_5, landline_1, landline_2, landline_3\nIf phone_columns is omitted, all 9 phone fields are included by default.\n\n**Related endpoints:** [DNC Lookup](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/lookup/) \u00b7 [Get One DNC Job](/skip-tracing-api-documentation/tag/phone-verification-dnc/GET/v2/api/dnc/queue/{id}) \u00b7 [DNC Scrub (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/scrub/)",
        "x-credits": "1 credit per phone checked, charged when the job finishes.",
        "x-rate-limit": "10 scrubs per 5 minutes per account.",
        "x-mode": "Async: returns a job ID, results arrive by download link and webhook.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "queue_id": {
                    "type": "integer",
                    "description": "ID of a completed trace queue to extract phones from."
                  },
                  "phone_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of phone field names to include. Defaults to all 9 phone fields."
                  }
                },
                "required": [
                  "queue_id"
                ]
              },
              "examples": {
                "example": {
                  "summary": "Example",
                  "value": {
                    "queue_id": 37360,
                    "phone_columns": [
                      "primary_phone",
                      "mobile_1",
                      "mobile_2"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "message": "DNC scrub started",
                      "dnc_queue_id": 8,
                      "created_at": "2025-01-15T10:00:00Z",
                      "source_queue_id": 37360,
                      "status": "pending",
                      "phones_to_check": 23,
                      "phone_columns_used": [
                        "primary_phone",
                        "mobile_1",
                        "mobile_2"
                      ],
                      "credits_per_phone": 1,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Source trace still processing",
            "content": {
              "application/json": {
                "examples": {
                  "source_trace_still_processing": {
                    "summary": "Source trace still processing",
                    "value": {
                      "error": "This trace is still processing. Please wait until it completes."
                    }
                  },
                  "no_phones_in_the_selected_columns": {
                    "summary": "No phones in the selected columns",
                    "value": {
                      "error": "No phone numbers found in this trace for the selected columns."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. You need 23 credits for DNC scrubbing. You have 0."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Source trace queue not found",
            "content": {
              "application/json": {
                "examples": {
                  "source_trace_queue_not_found": {
                    "summary": "Source trace queue not found",
                    "value": {
                      "error": "No trace queue found with ID 37360"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 10 scrubs per 5 minutes per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "DNC scrub limit exceeded. Max 10 scrubs per 5 minutes.",
                      "queues_in_window": "10"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/api/dnc/lookup/": {
      "post": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "dncLookup",
        "summary": "DNC Lookup",
        "description": "[Try it free in the API Tester](/skip-tracing-api-documentation/tester/) (Mock mode, no credits)\n\nSynchronous DNC check. Send one phone object or an array of up to 15 phone objects and get Federal DNC, state DNC, and TCPA litigator flags back immediately. No queue, no CSV, no waiting.\n\n**Array requests:** results stay in input order, each item is validated and billed independently, and the response returns `results` plus aggregate `credits_deducted`. Each phone counts toward the lookup rate limit.\n\n**5 credits per lookup.** Rate limited to 120 lookup items per minute per account.\n\n**Use this when:** you need to check a single number before dialing or as part of a real-time CRM workflow. For bulk scrubbing (100+ phones), use [POST /v2/api/dnc/scrub/](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub/) instead, it isn't subject to the synchronous 120-item-per-minute limit.\n\n**Response fields:**\n\n- `national_dnc`: on the Federal Do Not Call Registry\n- `state_dnc`: on at least one state DNC registry\n- `state_dnc_list`: array of the state codes matched, e.g. `[\"FL\", \"TX\"]`; empty when `state_dnc` is false\n- `litigator`: known TCPA litigator\n- `is_clean`: true only if no flags are set\n\n**Not returned by v2:** `dma` and `phone_type`. See [DNC API Versions](/skip-tracing-api-documentation/tag/phone-verification-dnc).\n\n**\u26a0\ufe0f Compliance:** Phones returning `litigator: true` or `national_dnc: true` should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.\n\n**Related endpoints:** [Get One DNC Job](/skip-tracing-api-documentation/tag/phone-verification-dnc/GET/v2/api/dnc/queue/{id}) \u00b7 [DNC Scrub (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/scrub/) \u00b7 [DNC Scrub from a Trace (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/scrub-from-queue/)",
        "x-credits": "5 credits per lookup. 0 when the DNC service fails.",
        "x-rate-limit": "120 lookups per minute per account. Each array item counts as one.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "description": "10-digit US phone number. Formatting is stripped automatically (dashes, spaces, parentheses, leading 1)."
                  }
                },
                "required": [
                  "phone"
                ]
              },
              "examples": {
                "example": {
                  "summary": "One object",
                  "value": {
                    "phone": "4805551234"
                  }
                },
                "array": {
                  "summary": "Array: up to 15 in one request",
                  "value": [
                    {
                      "phone": "4805551234"
                    },
                    {
                      "phone": "2145550300"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Flagged: not clean",
            "content": {
              "application/json": {
                "examples": {
                  "flagged_not_clean": {
                    "summary": "Flagged: not clean",
                    "value": {
                      "phone": "4805551234",
                      "hit": true,
                      "national_dnc": true,
                      "state_dnc": true,
                      "state_dnc_list": [
                        "FL"
                      ],
                      "litigator": false,
                      "is_clean": false,
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "clean_safe_to_proceed": {
                    "summary": "Clean: safe to proceed",
                    "value": {
                      "phone": "6025559876",
                      "hit": true,
                      "national_dnc": false,
                      "state_dnc": false,
                      "state_dnc_list": [],
                      "litigator": false,
                      "is_clean": true,
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "array_response": {
                    "summary": "Array response",
                    "value": {
                      "results": [
                        {
                          "phone": "4805551234",
                          "hit": true,
                          "national_dnc": true,
                          "state_dnc": true,
                          "state_dnc_list": [
                            "FL"
                          ],
                          "litigator": false,
                          "is_clean": false,
                          "credits_deducted": 5
                        },
                        {
                          "phone": "2145550300",
                          "hit": true,
                          "national_dnc": false,
                          "state_dnc": false,
                          "state_dnc_list": [],
                          "litigator": false,
                          "is_clean": true,
                          "credits_deducted": 5
                        }
                      ],
                      "credits_deducted": 10,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid phone: No phone in body",
            "content": {
              "application/json": {
                "examples": {
                  "missing_or_invalid_phone_no_phone_in_bod": {
                    "summary": "Missing or invalid phone: No phone in body",
                    "value": {
                      "error": "Missing 'phone' field."
                    }
                  },
                  "missing_or_invalid_phone_not_a_10_digit_": {
                    "summary": "Missing or invalid phone: Not a 10-digit US number",
                    "value": {
                      "error": "Invalid phone number. Must be a 10-digit US number."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. DNC lookup requires 5 credits. You have 0 credits."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 120 lookups per minute per account. Each array item counts as one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "DNC lookup limit exceeded. Max 120 lookups per 1 minute(s). For higher volume, use the batch scrub endpoint, which respects upstream rate limits automatically.",
                      "lookups_in_window": "120",
                      "lookups_requested": "1",
                      "retry_after_seconds": "60"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "Upstream temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "upstream_temporarily_unavailable": {
                    "summary": "Upstream temporarily unavailable",
                    "value": {
                      "error": "DNC lookup service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "DNC lookup not configured on this server",
            "content": {
              "application/json": {
                "examples": {
                  "dnc_lookup_not_configured_on_this_server": {
                    "summary": "DNC lookup not configured on this server",
                    "value": {
                      "error": "DNC lookup service is not configured."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/api/dnc/queue/{id}": {
      "get": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "getOneDncJob",
        "summary": "Get One DNC Job",
        "description": "Retrieve the status and results of a DNC scrub job. When complete, two download URLs are provided: download_url (all phones including ones with DNC flags) and clean_download_url (only phones with no DNC flags).\n\nThis endpoint is version-independent: `/v1/api/dnc/queue/:id` and `/v2/api/dnc/queue/:id` are the same endpoint and return the same JSON for any queue you own. The **CSV columns depend on which version created the scrub**:\n\n- v1: `phone, label, national_dnc, state_dnc, dma, litigator, phone_type, is_clean`\n- v2: `phone, label, national_dnc, state_dnc, state_dnc_list, litigator, is_clean`\n\n**Note:** While the queue is still pending, the fields `phones_checked`, `phones_clean`, and `credits_deducted` are omitted from the response. They appear once the scrub completes.\n\n**Related endpoints:** [DNC Scrub (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/scrub/) \u00b7 [DNC Scrub from a Trace (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/scrub-from-queue/) \u00b7 [DNC Lookup (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/lookup/)",
        "x-credits": "Free.",
        "x-rate-limit": "No limit.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "DNC Queue ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "id": 5,
                      "created_at": "2025-01-15T09:30:00Z",
                      "pending": false,
                      "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/full-results.csv",
                      "clean_download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/clean-results.csv",
                      "rows_uploaded": 150,
                      "phones_checked": 150,
                      "phones_clean": 112,
                      "credits_deducted": 150,
                      "source_type": "upload",
                      "source_queue_id": null,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "DNC queue belongs to another account",
            "content": {
              "application/json": {
                "examples": {
                  "dnc_queue_belongs_to_another_account": {
                    "summary": "DNC queue belongs to another account",
                    "value": {
                      "error": "Permission denied"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No DNC queue with that ID",
            "content": {
              "application/json": {
                "examples": {
                  "no_dnc_queue_with_that_id": {
                    "summary": "No DNC queue with that ID",
                    "value": {
                      "error": "No DNC queue found with ID 5"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/filters/": {
      "get": {
        "tags": [
          "Property Search"
        ],
        "operationId": "listStrategiesAndFilters",
        "summary": "List Strategies and Filters",
        "description": "Returns every Lead Builder preset strategy with its human-readable label, description, and the exact filters the preset applies. Use this to enumerate available filters at runtime instead of hard-coding the list in your client. Response is static enough to cache locally for ~1 hour.\n\nFor each strategy, `default_filters` shows the filters that the preset lays down, anything you send in `filter_overrides` on `/preview/` or `/execute/` will merge on top. This lets you see exactly what `'tired_landlord'` does before you use it.\n\nFor the complete list of individual filter keys you can use in `filter_overrides`, see the [Filter Reference](/skip-tracing-api-documentation/tag/property-search) below.\n\n**Related endpoints:** [Preview a Search](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/preview/) \u00b7 [Build a Lead List](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/) \u00b7 [Get Lead List Status](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/)",
        "x-credits": "Free.",
        "x-rate-limit": "No limit.",
        "x-mode": "Sync",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "strategies": [
                        {
                          "key": "pre_foreclosure_motivated",
                          "label": "Pre-Foreclosure",
                          "description": "Active pre-foreclosure filings in the last 6 months.",
                          "default_filters": {
                            "pre_foreclosure": true,
                            "search_range": "6_MONTH"
                          }
                        },
                        {
                          "key": "probate_inherited",
                          "label": "Inherited",
                          "description": "Inherited properties with high-intent sellers.",
                          "default_filters": {
                            "inherited": true
                          }
                        },
                        {
                          "key": "vacant",
                          "label": "Vacant Homes",
                          "description": "Vacant properties with no one residing at the address.",
                          "default_filters": {
                            "vacant": true
                          }
                        },
                        {
                          "key": "high_equity_absentee",
                          "label": "High Equity Absentee",
                          "description": "Absentee owners with the high-equity flag and strong seller motivation.",
                          "default_filters": {
                            "absentee_owner": true,
                            "high_equity": true
                          }
                        },
                        {
                          "key": "tired_landlord",
                          "label": "Tired Landlord",
                          "description": "Absentee owners who have held 7+ years and own 2+ properties.",
                          "default_filters": {
                            "absentee_owner": true,
                            "years_owned_min": 7,
                            "properties_owned_min": 2
                          }
                        },
                        {
                          "key": "reo_bank_owned",
                          "label": "REO / Bank-Owned",
                          "description": "Bank-owned (REO) properties and post-foreclosure distressed inventory.",
                          "default_filters": {
                            "reo": true
                          }
                        },
                        {
                          "key": "cash_buyer_investor",
                          "label": "Cash Buyer",
                          "description": "Recent cash buyers for wholesaling disposition lists.",
                          "default_filters": {
                            "cash_buyer": true
                          }
                        },
                        {
                          "key": "free_and_clear",
                          "label": "Free & Clear",
                          "description": "Properties owned outright with no active mortgage.",
                          "default_filters": {
                            "free_clear": true
                          }
                        },
                        {
                          "key": "auction_property",
                          "label": "Auction Properties",
                          "description": "Properties scheduled for auction with distressed seller potential.",
                          "default_filters": {
                            "auction": true
                          }
                        },
                        {
                          "key": "judgment_lien",
                          "label": "Judgment / Lien",
                          "description": "Properties whose owners have court judgments and financial distress.",
                          "default_filters": {
                            "judgment": true
                          }
                        },
                        {
                          "key": "owner_deceased",
                          "label": "Owner Deceased",
                          "description": "Properties with a deceased owner of record and potential estate sales.",
                          "default_filters": {
                            "death": true
                          }
                        },
                        {
                          "key": "active_flipper",
                          "label": "Active Flipper",
                          "description": "Investors who bought 2+ properties in the last 12 months.",
                          "default_filters": {
                            "investor_buyer": true,
                            "portfolio_purchased_last12_min": 2
                          }
                        },
                        {
                          "key": "zombie_property",
                          "label": "Zombie Property",
                          "description": "Vacant homes with an active pre-foreclosure filing, possibly abandoned mid-foreclosure.",
                          "default_filters": {
                            "vacant": true,
                            "pre_foreclosure": true
                          }
                        },
                        {
                          "key": "tax_delinquent",
                          "label": "Tax Delinquent",
                          "description": "Owners who fell behind on property taxes within the last 3 years.",
                          "default_filters": {
                            "tax_delinquent_year_min": 2023,
                            "tax_delinquent_year_max": 2026
                          }
                        },
                        {
                          "key": "low_equity",
                          "label": "Low Equity",
                          "description": "Properties with roughly 30% equity or less for refinance and short-sale outreach.",
                          "default_filters": {
                            "ltv_min": 70
                          }
                        },
                        {
                          "key": "vacant_land",
                          "label": "Vacant Land",
                          "description": "Undeveloped land parcels for land flipping and infill development.",
                          "default_filters": {
                            "property_type": "LAND"
                          }
                        },
                        {
                          "key": "expired_mls",
                          "label": "Expired MLS Listings",
                          "description": "Properties that were listed for sale but failed to sell, indicating possible seller motivation.",
                          "default_filters": {
                            "mls_cancelled": true
                          }
                        },
                        {
                          "key": "failed_listing",
                          "label": "Failed Listing",
                          "description": "Listings that came off the market without selling and may be ready to relist.",
                          "default_filters": {
                            "mls_failed": true
                          }
                        },
                        {
                          "key": "recent_homeowner",
                          "label": "Recent Homeowner",
                          "description": "Bought in the last 6 months for home improvement, refinance, and warranty outreach.",
                          "default_filters": {
                            "last_sale_date_min": "2026-04-05",
                            "absentee_owner": false
                          }
                        },
                        {
                          "key": "long_term_owner_listing_opportunity",
                          "label": "Long-Term Owner",
                          "description": "Owner-occupied for 10+ years with potential listing leads.",
                          "default_filters": {
                            "years_owned_min": 10,
                            "absentee_owner": false
                          }
                        },
                        {
                          "key": "high_equity_refi_candidate",
                          "label": "High Equity Refi",
                          "description": "Owner-occupied with the high-equity flag for refinance outreach.",
                          "default_filters": {
                            "absentee_owner": false,
                            "high_equity": true
                          }
                        },
                        {
                          "key": "solar_owner_occupied_high_value",
                          "label": "Solar (Owner-Occupied, High Value)",
                          "description": "SFRs built before 2015, owner-occupied, high equity, $300k+ value.",
                          "default_filters": {
                            "property_type": "SFR",
                            "absentee_owner": false,
                            "value_min": 300000,
                            "year_built_max": 2015,
                            "high_equity": true
                          }
                        },
                        {
                          "key": "roofing_older_home_high_equity",
                          "label": "Roofing (Older Home, High Equity)",
                          "description": "SFRs built before 2005, owner-occupied, high equity.",
                          "default_filters": {
                            "property_type": "SFR",
                            "year_built_max": 2005,
                            "high_equity": true,
                            "absentee_owner": false
                          }
                        },
                        {
                          "key": "hvac_older_home_owner_occupied",
                          "label": "HVAC (Older Home, Owner-Occupied)",
                          "description": "SFRs built before 2000, owner-occupied. Aging HVAC replacement market.",
                          "default_filters": {
                            "property_type": "SFR",
                            "year_built_max": 2000,
                            "absentee_owner": false
                          }
                        },
                        {
                          "key": "custom",
                          "label": "Custom",
                          "description": "A blank slate for configuring every filter manually or through an AI prompt.",
                          "default_filters": {}
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/api/property-search/preview/": {
      "post": {
        "tags": [
          "Property Search"
        ],
        "operationId": "previewASearch",
        "summary": "Preview a Search",
        "description": "Preview a lead list before charging. Returns the total match count, the capped count (the lower of total_matches and your requested_count), and the maximum credit cost. **Preview calls do not charge credits.**\n\nUse this to iterate on filters and geography before committing, safe to call repeatedly. Rate limited to 500 property searches per minute per account.\n\n**About `max_credit_cost`:** 5 credits per row in the delivered CSV. The value is the ceiling, if fewer properties match than `requested_count`, `capped_count` drops and the charge drops with it.\n\n**Filters:** see [List Filters](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/filters/) for preset strategies, or use `'custom'` and supply individual filters via `filter_overrides`. Full key reference at [Filter Reference](/skip-tracing-api-documentation/tag/property-search).\n\n**Geography modes:** `zips`, `city`, `counties`, `states`, `radius`. See the shape examples under the `geography` param below.\n\n**Related endpoints:** [Build a Lead List](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/) \u00b7 [Get Lead List Status](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/) \u00b7 [Get Lead List Rows](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/rows/)",
        "x-credits": "Free.",
        "x-rate-limit": "500 property searches per minute per account.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "strategy": {
                    "type": "string",
                    "description": "Strategy key from [/filters/](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/filters/). Defaults to 'custom'. Supports comma-separated multi-select (e.g. 'pre_foreclosure_motivated,probate_inherited,vacant') to combine multiple lead types with OR logic."
                  },
                  "geography": {
                    "type": "object",
                    "description": "Geography dict with a required `mode` field. Shapes:\n\n- `{\"mode\": \"zips\", \"zip_codes\": [\"85001\",\"85004\"]}`\n- `{\"mode\": \"city\", \"cities\": [\"Phoenix\"], \"states\": [\"AZ\"]}`\n- `{\"mode\": \"counties\", \"counties\": [\"Maricopa\"], \"states\": [\"AZ\"]}`\n- `{\"mode\": \"states\", \"states\": [\"AZ\",\"TX\"]}`\n- `{\"mode\": \"radius\", \"latitude\": 33.45, \"longitude\": -112.07, \"radius\": 5}` (miles)"
                  },
                  "filter_overrides": {
                    "type": "object",
                    "description": "Filters merged on top of the strategy defaults. See [Filter Reference](/skip-tracing-api-documentation/tag/property-search) for every accepted key."
                  },
                  "requested_count": {
                    "type": "integer",
                    "description": "Maximum rows you'd pay for. 1-25000. `capped_count` in the response = min(total_matches, requested_count)."
                  },
                  "include_pins": {
                    "type": "boolean",
                    "description": "When true, the response also includes up to 500 {latitude, longitude} pins for map rendering. Defaults to false for API callers who don't need them."
                  },
                  "dedupe_from_history": {
                    "type": "boolean",
                    "description": "When true, the response returns the post-dedupe count: properties this account has already received from past `/execute/` calls with the **same** filter set are subtracted. The response gains three extra fields: `dedupe_from_history` (echoes the flag), `excluded_from_history` (how many propertyIds would be skipped), and `available_after_dedupe` (the new effective pool size). Defaults to false. Same-filter matching is hash-based and ignores click order of multi-strategy slugs and geography lists."
                  }
                },
                "required": [
                  "geography",
                  "requested_count"
                ]
              },
              "examples": {
                "example": {
                  "summary": "Example",
                  "value": {
                    "strategy": "high_equity_absentee",
                    "geography": {
                      "mode": "city",
                      "cities": [
                        "Phoenix"
                      ],
                      "states": [
                        "AZ"
                      ]
                    },
                    "filter_overrides": {
                      "year_built_max": 2015
                    },
                    "requested_count": 500,
                    "dedupe_from_history": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview with dedupe_from_history=true",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "count": 2340,
                      "capped_count": 500,
                      "requested_count": 500,
                      "max_credit_cost": 2500,
                      "max_credit_cost_usd": 50.0,
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "filters_applied": {
                        "absentee_owner": true,
                        "high_equity": true,
                        "state": "AZ",
                        "city": "Phoenix"
                      },
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "preview_with_dedupe_from_history_true": {
                    "summary": "Preview with dedupe_from_history=true",
                    "value": {
                      "count": 2340,
                      "capped_count": 500,
                      "requested_count": 500,
                      "max_credit_cost": 2500,
                      "max_credit_cost_usd": 50.0,
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "filters_applied": {
                        "absentee_owner": true,
                        "high_equity": true,
                        "state": "AZ",
                        "city": "Phoenix"
                      },
                      "dedupe_from_history": true,
                      "excluded_from_history": 1200,
                      "available_after_dedupe": 1140
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unknown strategy",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_strategy": {
                    "summary": "Unknown strategy",
                    "value": {
                      "strategy": [
                        "Unknown strategy 'not_a_real_strategy'. Valid options: ['active_flipper', 'auction_property', 'cash_buyer_investor', 'custom', 'expired_mls', 'failed_listing', 'free_and_clear', 'high_equity_absentee', 'high_equity_refi_candidate', 'hvac_older_home_owner_occupied', 'judgment_lien', 'long_term_owner_listing_opportunity', 'low_equity', 'owner_deceased', 'pre_foreclosure_motivated', 'probate_inherited', 'recent_homeowner', 'reo_bank_owned', 'roofing_older_home_high_equity', 'solar_owner_occupied_high_value', 'tax_delinquent', 'tired_landlord', 'vacant', 'vacant_land', 'zombie_property']"
                      ]
                    }
                  },
                  "disallowed_filter_key": {
                    "summary": "Disallowed filter key",
                    "value": {
                      "filter_overrides": [
                        "Disallowed filter keys: ['not_a_key']. See ALLOWED_FILTER_KEYS in app.lead_builder_strategies for the full whitelist."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit reached: 500 property searches per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "error": "Rate limit exceeded. Please retry in 60 seconds."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Upstream temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "upstream_temporarily_unavailable": {
                    "summary": "Upstream temporarily unavailable",
                    "value": {
                      "error": "Lead preview service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/execute/": {
      "post": {
        "tags": [
          "Property Search"
        ],
        "operationId": "buildALeadList",
        "summary": "Build a Lead List",
        "description": "Create a lead list and dispatch the build task. This is the charged path, 5 credits per *delivered* row.\n\nReturns a 202 with the new `id` and a `poll_url`. The build runs asynchronously and typically takes 1-5 minutes depending on `requested_count`. Poll [the status endpoint](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/) until completion, or configure your [account webhook](/skip-tracing-api-documentation/webhook/POST/leadlistcompleted) to get notified automatically.\n\n**Related endpoints:** [Get Lead List Status](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/) \u00b7 [Get Lead List Rows](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/rows/) \u00b7 [Property Lookup](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/lookup/)",
        "x-credits": "5 credits per row delivered.",
        "x-rate-limit": "500 property searches per minute per account.",
        "x-mode": "Async: returns a lead list ID, rows arrive by webhook and the rows endpoint.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "strategy": {
                    "type": "string",
                    "description": "Same as /preview/. Defaults to 'custom'."
                  },
                  "geography": {
                    "type": "object",
                    "description": "Same shape as /preview/."
                  },
                  "filter_overrides": {
                    "type": "object",
                    "description": "Same shape as /preview/."
                  },
                  "requested_count": {
                    "type": "integer",
                    "description": "1-25000. Billed at 5 credits per delivered row, capped here."
                  },
                  "name": {
                    "type": "string",
                    "description": "Optional label shown in /lead-lists/ and the status response."
                  },
                  "dedupe_from_history": {
                    "type": "boolean",
                    "description": "When true, the build excludes any propertyId your account has previously received from a past `/execute/` call that used the **same filter set** (strategy + geography + filter_overrides). Useful for re-runs when you only want fresh leads. The match is hash-based, multi-strategy slug order and geography list order are normalized. To keep upstream cost bounded, the build fetches up to **5\u00d7** `requested_count` properties before truncating; if your filter pool is mostly exhausted, the final list may come in under your requested count (`actual_count < requested_count`) and you are only billed for delivered rows. Defaults to false (no exclusion)."
                  }
                },
                "required": [
                  "geography",
                  "requested_count"
                ]
              },
              "examples": {
                "example": {
                  "summary": "Example",
                  "value": {
                    "strategy": "high_equity_absentee",
                    "geography": {
                      "mode": "city",
                      "cities": [
                        "Phoenix"
                      ],
                      "states": [
                        "AZ"
                      ]
                    },
                    "filter_overrides": {
                      "year_built_max": 2015
                    },
                    "requested_count": 500,
                    "name": "Phoenix Q2 Prospects",
                    "dedupe_from_history": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "id": 42,
                      "status": "pending",
                      "progress_stage": "",
                      "created_at": "2026-04-11T18:23:00Z",
                      "requested_count": 500,
                      "max_credit_cost": 2500,
                      "poll_url": "/v1/api/lead-builder/42/",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "examples": {
                  "validation_error": {
                    "summary": "Validation error",
                    "value": {
                      "requested_count": [
                        "Ensure this value is less than or equal to 25000."
                      ]
                    }
                  },
                  "no_matches_widen_your_filters": {
                    "summary": "No matches (widen your filters)",
                    "value": {
                      "error": "No properties match this filter set. Widen your filters and try again.",
                      "matches": 0
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. This lead list requires up to 2500 credits (5 per row \u00d7 500 rows). You have 100 credits.",
                      "matches": 2340,
                      "capped": 500
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Account suspended (unpaid invoices)",
            "content": {
              "application/json": {
                "examples": {
                  "account_suspended_unpaid_invoices": {
                    "summary": "Account suspended (unpaid invoices)",
                    "value": {
                      "error": "Your account has been temporarily suspended due to unpaid invoices. Please contact support@tracerfy.com to resolve outstanding payments."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 500 property searches per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "error": "Rate limit exceeded. Please retry in 60 seconds."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/{id}/": {
      "get": {
        "tags": [
          "Property Search"
        ],
        "operationId": "getLeadListStatus",
        "summary": "Get Lead List Status",
        "description": "Poll a lead list for completion status. Returns the current stage, progress percent, and the CSV `download_url` once the build finishes.\n\n**Stages:** `fetching_properties` \u2192 `skip_tracing` \u2192 `generating_csv` \u2192 *(empty when complete)*.\n\nOwnership is enforced: you can only poll lead lists your account created. Unknown IDs return 404 (same as cross-user access attempts, to prevent ID enumeration).\n\n**Polling cadence:** poll every 2-5 seconds and back off as the stage advances, or skip polling entirely by configuring your [account webhook](/skip-tracing-api-documentation/webhook/POST/leadlistcompleted).\n\n**The CSV:** `download_url` is a time-limited signed URL (valid ~1 hour).\n\n**Related endpoints:** [Get Lead List Rows](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/rows/) \u00b7 [Property Lookup](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/lookup/) \u00b7 [Address Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/autocomplete/)",
        "x-credits": "Free.",
        "x-rate-limit": "No limit.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The LeadList id returned from the execute endpoint."
          }
        ],
        "responses": {
          "200": {
            "description": "Complete: download_url ready",
            "content": {
              "application/json": {
                "examples": {
                  "complete_download_url_ready": {
                    "summary": "Complete: download_url ready",
                    "value": {
                      "id": 42,
                      "name": "Phoenix Q2 Prospects",
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "source": "api",
                      "status": "complete",
                      "progress_stage": "",
                      "progress_percent": 100,
                      "requested_count": 500,
                      "actual_count": 487,
                      "credits_deducted": 2435,
                      "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/lead_list_42_a1b2c3d4.csv",
                      "error_message": "",
                      "created_at": "2026-04-11T18:23:00Z",
                      "completed_at": "2026-04-11T18:37:42Z",
                      "poll_url": "/v1/api/lead-builder/42/",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "pending_still_building": {
                    "summary": "Pending: still building",
                    "value": {
                      "id": 42,
                      "name": "Phoenix Q2 Prospects",
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "source": "api",
                      "status": "pending",
                      "progress_stage": "skip_tracing",
                      "progress_percent": 47,
                      "requested_count": 500,
                      "actual_count": null,
                      "credits_deducted": 0,
                      "download_url": "",
                      "error_message": "",
                      "created_at": "2026-04-11T18:23:00Z",
                      "completed_at": null,
                      "poll_url": "/v1/api/lead-builder/42/",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account lead list ID",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_lead_list_id": {
                    "summary": "Unknown or cross-account lead list ID",
                    "value": {
                      "error": "Lead list not found."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/{id}/rows/": {
      "get": {
        "tags": [
          "Property Search"
        ],
        "operationId": "getLeadListRows",
        "summary": "Get Lead List Rows",
        "description": "Paginated JSON access to the rows in a completed lead list. Same data as the CSV download, delivered as a JSON array, no file parsing needed.\n\n**Use this when:** you want to consume lead data programmatically without downloading and parsing a CSV. Perfect for CRM integrations, webhooks, or piping rows directly into your application.\n\n**No extra charge:** the data was already paid for on [/execute/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/). This endpoint is a free read.\n\n**Pagination: all rows are reachable.** The `500` is a *page-size* limit (most rows per response), **not** a cap on how many rows you can retrieve. `per_page` defaults to 100 (max 500); there's no upper bound on `page`, increment it to pull the whole list, and read `total_rows` / `total_pages` to know when you've reached the end. Returns 409 if the list is still processing.\n\n**Propensity scores included on every row.** Each row carries 5 independent propensity scores so the same lead can be qualified for sell, refi, roof, HVAC, and solar use cases at the same time. See the [Propensity Scores](/skip-tracing-api-documentation/tag/property-search) section below for the full schema, score ranges, and how to filter on them.\n\n**\u26a0\ufe0f Compliance:** Phones returning `litigator: true` or `dnc: true` should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.\n\n**Related endpoints:** [Property Lookup](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/lookup/) \u00b7 [Address Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/autocomplete/) \u00b7 [APN Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/apn-autocomplete/)",
        "x-credits": "Free.",
        "x-rate-limit": "No limit.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The LeadList id from /execute/."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page number (default 1). No upper bound: page through every row."
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Rows per page (response size: not a cap on total rows). 1-500, default 100."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "lead_list_id": 42,
                      "total_rows": 500,
                      "page": 1,
                      "per_page": 100,
                      "total_pages": 5,
                      "rows": [
                        {
                          "address": "742 Evergreen Terrace",
                          "city": "Phoenix",
                          "state": "AZ",
                          "zip_code": "85032",
                          "county": "Maricopa",
                          "latitude": 33.6359,
                          "longitude": -112.0531,
                          "apn": "123-45-6789",
                          "subdivision": "Paradise Park",
                          "property_type": "SFR",
                          "property_use": "Single Family Residence",
                          "land_use": "Residential",
                          "year_built": 1985,
                          "beds": 4,
                          "baths": 2.5,
                          "units_count": 1,
                          "stories": 1,
                          "building_size_sqft": 2140,
                          "lot_size_sqft": 8712,
                          "has_ac": true,
                          "has_garage": true,
                          "has_pool": false,
                          "has_basement": false,
                          "has_deck": true,
                          "roof_material": "Composition Shingle",
                          "roof_construction": "Gable",
                          "price_per_sqft": 227,
                          "estimated_value": 485000,
                          "estimated_equity": 298000,
                          "equity_percent": 61.4,
                          "assessed_value": 362000,
                          "area_median_income": 82500,
                          "last_sale_date": "2009-04-15",
                          "last_sale_price": 187000,
                          "years_owned": 16,
                          "prior_sale_date": "2001-08-22",
                          "prior_sale_price": 142000,
                          "open_mortgage_balance": 134500,
                          "lender_name": "Wells Fargo",
                          "estimated_mortgage_payment": 987,
                          "total_properties_owned": 2,
                          "total_portfolio_value": 910000,
                          "cash_buyer": false,
                          "corporate_owned": false,
                          "document_type": "Warranty Deed",
                          "quit_claim": false,
                          "recording_date": "2009-04-17",
                          "flood_zone": false,
                          "owner_1_first_name": "JANE",
                          "owner_1_last_name": "DOE",
                          "owner_2_first_name": "",
                          "owner_2_last_name": "",
                          "owner_1_age": "72",
                          "owner_2_age": "",
                          "mail_address": "742 Evergreen Terrace",
                          "mail_city": "Phoenix",
                          "mail_state": "AZ",
                          "mail_zip": "85032",
                          "primary_phone": "4805551234",
                          "primary_phone_type": "Mobile",
                          "primary_phone_carrier": "T-Mobile",
                          "primary_phone_dnc": false,
                          "primary_phone_tcpa": false,
                          "mobile_1": "4805559876",
                          "mobile_1_dnc": true,
                          "mobile_1_tcpa": false,
                          "mobile_2": "",
                          "mobile_2_dnc": false,
                          "mobile_2_tcpa": false,
                          "mobile_3": "",
                          "mobile_3_dnc": false,
                          "mobile_3_tcpa": false,
                          "landline_1": "4805551234",
                          "landline_1_dnc": false,
                          "landline_1_tcpa": false,
                          "landline_2": "",
                          "landline_2_dnc": false,
                          "landline_2_tcpa": false,
                          "email_1": "jane.doe@example.com",
                          "email_2": "",
                          "email_3": "",
                          "litigator": false,
                          "has_contact": true,
                          "contact_clean": true,
                          "absentee_owner": false,
                          "owner_occupied": true,
                          "vacant": false,
                          "free_clear": false,
                          "high_equity": true,
                          "pre_foreclosure": false,
                          "foreclosure": false,
                          "tax_delinquent": false,
                          "tax_delinquent_year": null,
                          "tax_lien": false,
                          "inherited": false,
                          "death": false,
                          "judgment": false,
                          "hoa": true,
                          "category": "high_equity_refi_candidate",
                          "mls_active": false,
                          "mls_pending": false,
                          "mls_cancelled": false,
                          "mls_sold": false,
                          "mls_failed": false,
                          "mls_days_on_market": null,
                          "mls_listing_price": null,
                          "adjustable_rate": false,
                          "investor_buyer": false,
                          "sell_propensity_score": 24,
                          "sell_propensity_category": "Low",
                          "sell_propensity_factors": [
                            {
                              "name": "owner_occupied",
                              "points": 8,
                              "reason": "Owner-occupied \u2014 primary residence"
                            },
                            {
                              "name": "years_owned",
                              "points": 7,
                              "reason": "Owned 16 years \u2014 moderate equity accumulation"
                            }
                          ],
                          "refi_propensity_score": 33,
                          "refi_propensity_category": "Low",
                          "refi_propensity_factors": [
                            {
                              "name": "high_equity",
                              "points": 15,
                              "reason": "High equity \u2014 strong candidate for cash-out refi"
                            },
                            {
                              "name": "owner_occupied",
                              "points": 8,
                              "reason": "Owner-occupied \u2014 primary residence refinance more likely"
                            },
                            {
                              "name": "years_owned",
                              "points": 10,
                              "reason": "Owned 16 years \u2014 likely has equity to tap"
                            }
                          ],
                          "roof_renovate_propensity_score": 47,
                          "roof_renovate_propensity_category": "Medium",
                          "roof_renovate_propensity_factors": [
                            {
                              "name": "owner_occupied",
                              "points": 15,
                              "reason": "Owner-occupied \u2014 decision-maker present"
                            },
                            {
                              "name": "high_equity",
                              "points": 12,
                              "reason": "High equity \u2014 affordability for $20K+ project"
                            },
                            {
                              "name": "older_home",
                              "points": 12,
                              "reason": "Built 1985 \u2014 typical roof end-of-life window"
                            }
                          ],
                          "hvac_renovate_propensity_score": 52,
                          "hvac_renovate_propensity_category": "Medium",
                          "hvac_renovate_propensity_factors": [
                            {
                              "name": "owner_occupied",
                              "points": 18,
                              "reason": "Owner-occupied \u2014 decision-maker present"
                            },
                            {
                              "name": "older_home",
                              "points": 14,
                              "reason": "Built 1985 \u2014 HVAC typically replaced every 15-20 years"
                            },
                            {
                              "name": "high_equity",
                              "points": 12,
                              "reason": "High equity \u2014 affordability for system upgrade"
                            }
                          ],
                          "solar_renovate_propensity_score": 71,
                          "solar_renovate_propensity_category": "High",
                          "solar_renovate_propensity_factors": [
                            {
                              "name": "owner_occupied",
                              "points": 20,
                              "reason": "Owner-occupied \u2014 decision-maker for long-term install"
                            },
                            {
                              "name": "high_equity",
                              "points": 18,
                              "reason": "High equity \u2014 financing or cash-out available for install"
                            },
                            {
                              "name": "high_value_property",
                              "points": 18,
                              "reason": "Property value $485K \u2014 high-value home, typically sunny region"
                            }
                          ]
                        },
                        {
                          "address": "1200 Oak Blvd",
                          "city": "Phoenix",
                          "state": "AZ",
                          "zip_code": "85018",
                          "county": "Maricopa",
                          "latitude": 33.4892,
                          "longitude": -111.9874,
                          "apn": "987-65-4321",
                          "subdivision": "Arcadia Heights",
                          "property_type": "SFR",
                          "property_use": "Single Family Residence",
                          "land_use": "Residential",
                          "year_built": 1972,
                          "beds": 3,
                          "baths": 2.0,
                          "units_count": 1,
                          "stories": 1,
                          "building_size_sqft": 1680,
                          "lot_size_sqft": 6200,
                          "has_ac": true,
                          "has_garage": true,
                          "has_pool": true,
                          "has_basement": false,
                          "has_deck": false,
                          "roof_material": "Tile/Clay",
                          "roof_construction": "Hip",
                          "price_per_sqft": 235,
                          "estimated_value": 395000,
                          "estimated_equity": 395000,
                          "equity_percent": 100.0,
                          "assessed_value": 288000,
                          "area_median_income": 61000,
                          "last_sale_date": "1998-11-03",
                          "last_sale_price": 95000,
                          "years_owned": 27,
                          "prior_sale_date": null,
                          "prior_sale_price": null,
                          "open_mortgage_balance": 0,
                          "lender_name": "",
                          "estimated_mortgage_payment": 0,
                          "total_properties_owned": 1,
                          "total_portfolio_value": 395000,
                          "cash_buyer": false,
                          "corporate_owned": false,
                          "document_type": "Warranty Deed",
                          "quit_claim": false,
                          "recording_date": "1998-11-05",
                          "flood_zone": false,
                          "owner_1_first_name": "ROBERT",
                          "owner_1_last_name": "SMITH",
                          "owner_2_first_name": "LINDA",
                          "owner_2_last_name": "SMITH",
                          "owner_1_age": "68",
                          "owner_2_age": "65",
                          "mail_address": "PO Box 4412",
                          "mail_city": "Scottsdale",
                          "mail_state": "AZ",
                          "mail_zip": "85261",
                          "primary_phone": "6025559900",
                          "primary_phone_type": "Landline",
                          "primary_phone_carrier": "CenturyLink",
                          "primary_phone_dnc": false,
                          "primary_phone_tcpa": false,
                          "mobile_1": "",
                          "mobile_1_dnc": false,
                          "mobile_1_tcpa": false,
                          "mobile_2": "",
                          "mobile_2_dnc": false,
                          "mobile_2_tcpa": false,
                          "mobile_3": "",
                          "mobile_3_dnc": false,
                          "mobile_3_tcpa": false,
                          "landline_1": "6025559900",
                          "landline_1_dnc": false,
                          "landline_1_tcpa": false,
                          "landline_2": "",
                          "landline_2_dnc": false,
                          "landline_2_tcpa": false,
                          "email_1": "rsmith72@example.com",
                          "email_2": "",
                          "email_3": "",
                          "litigator": false,
                          "has_contact": true,
                          "contact_clean": true,
                          "absentee_owner": true,
                          "owner_occupied": false,
                          "vacant": false,
                          "free_clear": true,
                          "high_equity": true,
                          "pre_foreclosure": false,
                          "foreclosure": false,
                          "tax_delinquent": false,
                          "tax_delinquent_year": null,
                          "tax_lien": false,
                          "inherited": false,
                          "death": false,
                          "judgment": false,
                          "hoa": false,
                          "category": "high_equity_absentee,free_and_clear",
                          "mls_active": false,
                          "mls_pending": false,
                          "mls_cancelled": false,
                          "mls_sold": false,
                          "mls_failed": false,
                          "mls_days_on_market": null,
                          "mls_listing_price": null,
                          "adjustable_rate": false,
                          "investor_buyer": true,
                          "sell_propensity_score": 47,
                          "sell_propensity_category": "Medium",
                          "sell_propensity_factors": [
                            {
                              "name": "years_owned",
                              "points": 12,
                              "reason": "Owned 27 years \u2014 long tenure, high equity accumulation"
                            },
                            {
                              "name": "absentee_owner",
                              "points": 8,
                              "reason": "Absentee owner \u2014 less attached to property"
                            },
                            {
                              "name": "free_clear",
                              "points": 4,
                              "reason": "Free and clear \u2014 no mortgage friction at sale"
                            },
                            {
                              "name": "aging_property",
                              "points": 4,
                              "reason": "Built 1972 \u2014 significant deferred-maintenance burden"
                            }
                          ],
                          "refi_propensity_score": 18,
                          "refi_propensity_category": "Low",
                          "refi_propensity_factors": [
                            {
                              "name": "free_clear",
                              "points": 6,
                              "reason": "Free and clear \u2014 could take on a new mortgage product"
                            }
                          ],
                          "roof_renovate_propensity_score": 18,
                          "roof_renovate_propensity_category": "Low",
                          "roof_renovate_propensity_factors": [
                            {
                              "name": "high_equity",
                              "points": 12,
                              "reason": "High equity \u2014 affordability for $20K+ project"
                            },
                            {
                              "name": "absentee_penalty",
                              "points": -10,
                              "reason": "Absentee owner \u2014 investors defer discretionary projects"
                            }
                          ],
                          "hvac_renovate_propensity_score": 22,
                          "hvac_renovate_propensity_category": "Low",
                          "hvac_renovate_propensity_factors": [
                            {
                              "name": "high_equity",
                              "points": 12,
                              "reason": "High equity \u2014 affordability for system upgrade"
                            },
                            {
                              "name": "absentee_penalty",
                              "points": -10,
                              "reason": "Absentee owner \u2014 landlords delay HVAC replacement"
                            }
                          ],
                          "solar_renovate_propensity_score": 8,
                          "solar_renovate_propensity_category": "Low",
                          "solar_renovate_propensity_factors": [
                            {
                              "name": "absentee_penalty",
                              "points": -25,
                              "reason": "Absentee owner \u2014 solar installs require resident decision-maker"
                            }
                          ]
                        },
                        "... 98 more rows in this page"
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account lead list ID",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_lead_list_id": {
                    "summary": "Unknown or cross-account lead list ID",
                    "value": {
                      "error": "Lead list not found."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Lead list still processing",
            "content": {
              "application/json": {
                "examples": {
                  "lead_list_still_processing": {
                    "summary": "Lead list still processing",
                    "value": {
                      "error": "Lead list is still processing. Poll the status endpoint until complete.",
                      "status": "pending"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/lookup/": {
      "post": {
        "tags": [
          "Property Search"
        ],
        "operationId": "propertyLookup",
        "summary": "Property Lookup",
        "description": "[Try it free in the API Tester](/skip-tracing-api-documentation/tester/) (Mock mode, no credits)\n\nSynchronous single-address version of [/execute/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/), one address in, one address out. Use this when you already have a specific address and want the complete data (property attributes, owner, full skip trace) in a single API call.\n\n**Two lookup modes (mutually exclusive):**\n\n- **Address**: send `address` + `city` + `state` (+ optional `zip_code`).\n- **APN**: send `apn` + `county` + `state` to enrich a normalized parcel number (e.g. one returned by [APN Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/apn-autocomplete/)). An APN is only unique within a county, so `county` + `state` are required to resolve the right parcel. The response shape is identical to address mode.\nSending both `address` and `apn` in the same request is a `400`.\n\n**Billing: 10 credits per property hit:**\n\n- Property found + skip trace hit \u2192 10 credits, full phones/emails + all compliance flags\n- Property found + skip trace miss \u2192 10 credits, full property data, empty `contacts` block\n- Property NOT found \u2192 0 credits, `hit: false`\n\nPriced at 2\u00d7 the [/v1/api/trace/lookup/](/skip-tracing-api-documentation/tag/skip-tracing/POST/v1/api/trace/lookup/) endpoint (5 credits) because this lookup returns the full property dossier (50+ Attributes) *in addition to* skip-trace contacts. If you only need phones and emails for an address (no property attributes), use instant trace instead, same skip-trace data, half the cost.\n\n**ZIP code:** optional but *strongly recommended*, without it, common street names can match the wrong property in a large city.\n\n**Rate limit:** 500 requests per minute.\n\n**\u26a0\ufe0f Compliance:** Phones returning `litigator: true` or `dnc: true` should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.\n\n**Related endpoints:** [Address Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/autocomplete/) \u00b7 [APN Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/apn-autocomplete/) \u00b7 [TraceAI Assist](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/ai-assist/)",
        "x-credits": "10 credits per property found, with or without contacts. 0 when no property is found.",
        "x-rate-limit": "500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "Address mode: property street address. Example: \"4521 E Monte Cristo Ave\". Required in address mode; omit in APN mode."
                  },
                  "city": {
                    "type": "string",
                    "description": "Address mode: property city. Required in address mode."
                  },
                  "zip_code": {
                    "type": "string",
                    "description": "Address mode: property ZIP. Optional but strongly recommended for accuracy."
                  },
                  "apn": {
                    "type": "string",
                    "description": "APN mode: Assessor's Parcel Number. The leading '#' is optional. Required in APN mode; mutually exclusive with address."
                  },
                  "county": {
                    "type": "string",
                    "description": "APN mode: county the parcel is in. Required in APN mode (an APN is only unique within a county)."
                  },
                  "state": {
                    "type": "string",
                    "description": "Property state (2-letter code). Required in BOTH modes."
                  }
                },
                "required": [
                  "state"
                ]
              },
              "examples": {
                "address_mode": {
                  "summary": "Address mode",
                  "value": {
                    "address": "4521 E Monte Cristo Ave",
                    "city": "Phoenix",
                    "state": "AZ",
                    "zip_code": "85032"
                  }
                },
                "apn_mode_enrich_a_normalized_parcel_numb": {
                  "summary": "APN mode (enrich a normalized parcel number)",
                  "value": {
                    "apn": "123-45-6789",
                    "county": "Maricopa",
                    "state": "AZ"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hit: 10 credits deducted",
            "content": {
              "application/json": {
                "examples": {
                  "hit_10_credits_deducted": {
                    "summary": "Hit: 10 credits deducted",
                    "value": {
                      "hit": true,
                      "credits_deducted": 10,
                      "skip_trace_hit": true,
                      "property": {
                        "address": "4521 E Monte Cristo Ave",
                        "city": "Phoenix",
                        "state": "AZ",
                        "zip_code": "85032",
                        "county": "Maricopa",
                        "latitude": 33.6,
                        "longitude": -112.0,
                        "apn": "123-45-6789",
                        "subdivision": "Paradise Park",
                        "property_type": "SFR",
                        "property_use": "Single Family",
                        "land_use": "Residential",
                        "year_built": 1978,
                        "beds": 4,
                        "baths": 2.5,
                        "units_count": 1,
                        "stories": 1,
                        "building_size_sqft": 2140,
                        "lot_size_sqft": 8712,
                        "has_ac": true,
                        "has_garage": true,
                        "has_pool": false,
                        "has_basement": false,
                        "has_deck": true,
                        "estimated_value": 485000,
                        "estimated_equity": 298000,
                        "equity_percent": 61.4,
                        "assessed_value": 362000,
                        "area_median_income": 82500,
                        "last_sale_date": "2009-04-15",
                        "last_sale_price": 187000,
                        "years_owned": 17,
                        "prior_sale_date": "2001-08-22",
                        "prior_sale_price": 142000,
                        "open_mortgage_balance": 134500,
                        "lender_name": "Wells Fargo",
                        "estimated_mortgage_payment": 987,
                        "total_properties_owned": 2,
                        "total_portfolio_value": 910000,
                        "cash_buyer": false,
                        "corporate_owned": false,
                        "roof_material": "Composition Shingle",
                        "roof_construction": "Gable",
                        "flood_zone": false,
                        "document_type": "Warranty Deed",
                        "quit_claim": false,
                        "recording_date": "2009-04-17",
                        "price_per_sqft": 227,
                        "absentee_owner": false,
                        "owner_occupied": true,
                        "vacant": false,
                        "free_clear": false,
                        "high_equity": true,
                        "pre_foreclosure": false,
                        "foreclosure": false,
                        "tax_delinquent": false,
                        "tax_delinquent_year": null,
                        "tax_lien": false,
                        "inherited": false,
                        "death": false,
                        "judgment": false,
                        "hoa": true,
                        "mls_active": false,
                        "mls_pending": false,
                        "mls_cancelled": false,
                        "mls_sold": false,
                        "mls_failed": false,
                        "mls_days_on_market": null,
                        "mls_listing_price": null,
                        "adjustable_rate": false,
                        "investor_buyer": false,
                        "sell_propensity_score": 24,
                        "sell_propensity_category": "Low",
                        "sell_propensity_factors": [
                          {
                            "name": "owner_occupied",
                            "points": 8,
                            "reason": "Owner-occupied \u2014 primary residence"
                          },
                          {
                            "name": "years_owned",
                            "points": 10,
                            "reason": "Owned 17 years \u2014 significant equity likely"
                          }
                        ],
                        "refi_propensity_score": 33,
                        "refi_propensity_category": "Low",
                        "refi_propensity_factors": [
                          {
                            "name": "high_equity",
                            "points": 15,
                            "reason": "High equity \u2014 strong candidate for cash-out refi"
                          },
                          {
                            "name": "owner_occupied",
                            "points": 8,
                            "reason": "Owner-occupied \u2014 primary residence refinance more likely"
                          },
                          {
                            "name": "years_owned",
                            "points": 10,
                            "reason": "Owned 17 years \u2014 likely has equity to tap"
                          }
                        ],
                        "roof_renovate_propensity_score": 49,
                        "roof_renovate_propensity_category": "Medium",
                        "roof_renovate_propensity_factors": [
                          {
                            "name": "owner_occupied",
                            "points": 15,
                            "reason": "Owner-occupied \u2014 decision-maker present"
                          },
                          {
                            "name": "high_equity",
                            "points": 12,
                            "reason": "High equity \u2014 affordability for $20K+ project"
                          },
                          {
                            "name": "older_home",
                            "points": 14,
                            "reason": "Built 1978 \u2014 typical roof end-of-life window"
                          }
                        ],
                        "hvac_renovate_propensity_score": 54,
                        "hvac_renovate_propensity_category": "Medium",
                        "hvac_renovate_propensity_factors": [
                          {
                            "name": "owner_occupied",
                            "points": 18,
                            "reason": "Owner-occupied \u2014 decision-maker present"
                          },
                          {
                            "name": "older_home",
                            "points": 16,
                            "reason": "Built 1978 \u2014 HVAC typically replaced every 15-20 years"
                          },
                          {
                            "name": "high_equity",
                            "points": 12,
                            "reason": "High equity \u2014 affordability for system upgrade"
                          }
                        ],
                        "solar_renovate_propensity_score": 73,
                        "solar_renovate_propensity_category": "High",
                        "solar_renovate_propensity_factors": [
                          {
                            "name": "owner_occupied",
                            "points": 20,
                            "reason": "Owner-occupied \u2014 decision-maker for long-term install"
                          },
                          {
                            "name": "high_equity",
                            "points": 18,
                            "reason": "High equity \u2014 financing or cash-out available for install"
                          },
                          {
                            "name": "high_value_property",
                            "points": 18,
                            "reason": "Property value $485K \u2014 high-value home, sunny region"
                          }
                        ]
                      },
                      "owners": [
                        {
                          "first_name": "JANET",
                          "last_name": "MORRIS",
                          "age": "76"
                        },
                        {
                          "first_name": "ROBERT",
                          "last_name": "MORRIS",
                          "age": "74"
                        }
                      ],
                      "mailing_address": {
                        "address": "4521 E Monte Cristo Ave",
                        "city": "Phoenix",
                        "state": "AZ",
                        "zip": "85032"
                      },
                      "contacts": {
                        "phones": [
                          {
                            "number": "4805551234",
                            "type": "Mobile",
                            "dnc": false,
                            "tcpa": false,
                            "carrier": "T-Mobile",
                            "rank": 1
                          },
                          {
                            "number": "4805559876",
                            "type": "Mobile",
                            "dnc": true,
                            "tcpa": false,
                            "carrier": "AT&T",
                            "rank": 2
                          },
                          {
                            "number": "4805550100",
                            "type": "Landline",
                            "dnc": false,
                            "tcpa": false,
                            "carrier": "CenturyLink",
                            "rank": 3
                          }
                        ],
                        "emails": [
                          {
                            "email": "janet.morris@example.com",
                            "rank": 1
                          }
                        ],
                        "litigator": false,
                        "has_contact": true,
                        "contact_clean": false
                      },
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "miss_address_not_found_0_credits": {
                    "summary": "Miss: address not found, 0 credits",
                    "value": {
                      "hit": false,
                      "credits_deducted": 0,
                      "address": "999 Nowhere Blvd",
                      "city": "Austin",
                      "state": "TX",
                      "zip_code": "78701",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. Lead Builder lookup requires 10 credits per hit. You have 2 credits."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Account suspended (unpaid invoices)",
            "content": {
              "application/json": {
                "examples": {
                  "account_suspended_unpaid_invoices": {
                    "summary": "Account suspended (unpaid invoices)",
                    "value": {
                      "error": "Your account has been temporarily suspended due to unpaid invoices. Please contact support@tracerfy.com to resolve outstanding payments."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 500 lookups per minute per account, shared with the other instant lookups. Each array item counts as one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Rate limit exceeded. Max 500 lookups per minute.",
                      "lookups_in_window": "501",
                      "retry_after_seconds": "60"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Upstream temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "upstream_temporarily_unavailable": {
                    "summary": "Upstream temporarily unavailable",
                    "value": {
                      "error": "Lookup service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/autocomplete/": {
      "post": {
        "tags": [
          "Property Search"
        ],
        "operationId": "addressAutocomplete",
        "summary": "Address Autocomplete",
        "description": "Resolve a free-text address string to canonical property records. Use this **before** calling [/lookup/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/lookup/) to validate that an address exists in our database, and to get back the canonical city/zip values our lookup endpoint expects.\n\n**FREE: zero credits charged.** This is a pre-flight validation tool. Use it as much as needed before paying for a full lookup.\n\n**When to use it**\n\n- **Before /lookup/ on messy data:** CRM exports, hand-typed lists, web form submissions, any address you're not 100% sure about. Run it through autocomplete first; only pay for /lookup/ on resolved addresses.\n- **Neighborhood-vs-USPS city:** Customers often type neighborhood names (\"Williamsburg\", \"Park Slope\", \"Highland Park\") that USPS canonicalizes to a different city label (\"Long Island City\", \"Brooklyn\", \"Los Angeles\"). Our /lookup/ endpoint requires the canonical city; this endpoint tells you what it is.\n- **Typo / suffix variation:** \"123 Main\" vs \"123 Main St\" vs \"123 Main Street\", autocomplete normalizes all to the canonical form.\n- **Address verification at scale:** validating thousands of addresses without burning credits.\n\n**Rate limit**\n\n30 requests per minute per account. If you exceed this you'll get a **429 Too Many Requests** with an `Autocomplete rate limit exceeded` message, back off and retry. The throttle is purely a fair-use guard so individual accounts can't monopolize the underlying address-resolution capacity.\n**What you get back**\n\nAn array of up to 10 best-match property records. Each record contains:\n\n- **Display**: `title` (the full one-line label, e.g. `\"742 Evergreen Terrace, Brooklyn, NY, 11211\"`).\n- **Canonical address parts**: `street_address`, `house`, `street`, `city`, `state`, `zip`, `county`. The `address` field is the full formatted display string (e.g. `\"742 Evergreen Terrace, Brooklyn, NY, 11211\"`), do not re-pass it as `address` on /lookup/.\n- **Geographic identifiers**: `state_fips`, `county_fips`, `fips` (combined 5-digit code), and `apn` (Assessor's Parcel Number). These are public US-government identifiers, useful for cross-referencing county records.\n- **Geometry**: `latitude`, `longitude`, and `location` (WKT `POINT` format) for mapping.\n\nIf no matches, `results` is an empty array.\n\n**Picking a result programmatically**\n\nEvery result is a property address, so `results[0]` is the best match. Pass `street_address` as `address`, and `city`, `state`, `zip` as-is to [/lookup/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/lookup/):\n\n```\n# Pseudocode\nmatch = resp[\"results\"][0] if resp[\"results\"] else None\nif match:\n    POST /v1/api/property-search/lookup/ {\n        \"address\":  match[\"street_address\"],   # NOT match[\"address\"]\n        \"city\":     match[\"city\"],\n        \"state\":    match[\"state\"],\n        \"zip_code\": match[\"zip\"],\n    }\n```\n\n**Related endpoints:** [APN Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/apn-autocomplete/) \u00b7 [TraceAI Assist](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/ai-assist/) \u00b7 [List Saved Templates](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/templates/)",
        "x-credits": "Free.",
        "x-rate-limit": "30 requests per minute per account.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "description": "The address string to resolve. Minimum 2 characters. Whitespace and casing don't matter, the resolver handles both."
                  }
                },
                "required": [
                  "search"
                ]
              },
              "examples": {
                "example": {
                  "summary": "Example",
                  "value": {
                    "search": "742 Evergreen Terr Williamsburg NY"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "query": "742 Evergreen Terr, Williamsburg NY",
                      "credits_deducted": 0,
                      "results": [
                        {
                          "title": "742 Evergreen Terrace, Brooklyn, NY, 11211",
                          "address": "742 Evergreen Terrace, Brooklyn, NY, 11211",
                          "street_address": "742 Evergreen Terrace",
                          "house": "742",
                          "street": "Evergreen Terrace",
                          "city": "Brooklyn",
                          "state": "NY",
                          "zip": "11211",
                          "county": "Kings County",
                          "state_fips": "36",
                          "county_fips": "047",
                          "fips": "36047",
                          "apn": "03145-0042",
                          "latitude": 40.7081,
                          "longitude": -73.9571,
                          "location": "POINT (-73.9571 40.7081)"
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing search field",
            "content": {
              "application/json": {
                "examples": {
                  "missing_search_field": {
                    "summary": "Missing search field",
                    "value": {
                      "error": "Missing 'search' field. Pass {\"search\": \"<address text>\"} in the request body."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit reached: 30 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Autocomplete rate limit exceeded. Max 30 requests per minute."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Upstream temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "upstream_temporarily_unavailable": {
                    "summary": "Upstream temporarily unavailable",
                    "value": {
                      "error": "Address resolution service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/apn-autocomplete/": {
      "post": {
        "tags": [
          "Property Search"
        ],
        "operationId": "apnAutocomplete",
        "summary": "APN Autocomplete",
        "description": "Resolve a full or partial **Assessor's Parcel Number (APN)** to candidate parcels. **APNs are only unique within a single county.** Each county assessor numbers its parcels independently, so the very same APN value can (and often does) belong to completely different properties in other counties or states. Because of that the endpoint returns *every* matching parcel, each tagged with its `county`, `state`, and `zip` (when available) so you can pick the right one, see the two same-APN matches (Florida and Texas) in the example response below.\n\n**FREE: zero credits charged.** A pre-flight resolver, like [Address Autocomplete](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/autocomplete/) but keyed on APN.\n\n**When to use it**\n\n- **APN typeahead:** power a parcel-search box where the user types an APN and picks the correct parcel from the returned matches.\n- **Disambiguate a raw APN:** turn an APN pulled from a county record into a confirmed `county` / `state` / `zip`, which you can then use to scope a [property search](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/preview/).\n\n**APN format:** the leading `#` is optional and is stripped automatically; other formatting (dashes, spaces) is passed through as-is.\n\n**Rate limit**\n\n30 requests per minute per account. Exceeding it returns **429 Too Many Requests**, back off and retry. The throttle is a fair-use guard so no single account monopolizes the parcel-resolution capacity.\n**What you get back**\n\nAn array of up to 10 best-match parcels. Each record contains:\n\n- **Parcel**: `apn` (Assessor's Parcel Number).\n- **Location**: `county`, `state`, and `zip` (present when known). Use the most specific available to scope a search: ZIP if present, otherwise county + state.\n- **Geographic identifiers**: `state_fips`, `county_fips`, and `fips` (combined 5-digit code). These are public US-government identifiers, useful for cross-referencing county records.\n- **Geometry**: `latitude`, `longitude` for mapping.\n\nIf no matches, `results` is an empty array.\n\n**Related endpoints:** [TraceAI Assist](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/ai-assist/) \u00b7 [List Saved Templates](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/templates/) \u00b7 [Create a Saved Template](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/templates/)",
        "x-credits": "Free.",
        "x-rate-limit": "30 requests per minute per account.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "description": "The APN to resolve. Minimum 2 characters. A leading '#' is optional and stripped automatically."
                  }
                },
                "required": [
                  "search"
                ]
              },
              "examples": {
                "example": {
                  "summary": "Example",
                  "value": {
                    "search": "00424109000007550"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "query": "00424109000007550",
                      "credits_deducted": 0,
                      "results": [
                        {
                          "apn": "00424109000007550",
                          "county": "Palm Beach County",
                          "state": "FL",
                          "zip": "33401",
                          "state_fips": "12",
                          "county_fips": "099",
                          "fips": "12099",
                          "latitude": 26.7153,
                          "longitude": -80.0534
                        },
                        {
                          "apn": "00424109000007550",
                          "county": "Harris County",
                          "state": "TX",
                          "zip": "77002",
                          "state_fips": "48",
                          "county_fips": "201",
                          "fips": "48201",
                          "latitude": 29.7604,
                          "longitude": -95.3698
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing search field",
            "content": {
              "application/json": {
                "examples": {
                  "missing_search_field": {
                    "summary": "Missing search field",
                    "value": {
                      "error": "Missing 'search' field. Pass {\"search\": \"<apn>\"} in the request body."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit reached: 30 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Autocomplete rate limit exceeded. Max 30 requests per minute."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Upstream temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "upstream_temporarily_unavailable": {
                    "summary": "Upstream temporarily unavailable",
                    "value": {
                      "error": "Parcel resolution service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/ai-assist/": {
      "post": {
        "tags": [
          "Property Search"
        ],
        "operationId": "traceaiAssist",
        "summary": "TraceAI Assist",
        "description": "Translate a plain-English description of your ideal customer into a structured `strategy` + `geography` + `filter_overrides` spec you can pipe straight into `/preview/` or `/execute/`. This is the fastest way to build a lead list from code, one call to describe, one call to run.\n\n**Billing:** 1 credit when TraceAI returns a search. A follow-up question (`needs_clarification: true`) and a failed call (503) cost nothing.\n\n**When the AI isn't sure:** if your prompt is ambiguous ('Springfield', 'LA'), the response will include `needs_clarification: true`, a `clarifying_question`, and a `conversation_id`. To reply, pass the same `conversation_id` along with the user's answer in a new call, the AI loads the full conversation history and picks up where it left off.\n\n**Conceptual questions** like \"what is a tired landlord\" return `needs_clarification: true` with the explanation in `rationale.summary`, don't run a search on those, ask the user where they want to target first.\n\n**Neighborhood-level targeting:** say \"plumbing leads in South Side Chicago\" or \"downtown Nashville probate\" and TraceAI will pick the ZIP codes that cover the area from its general knowledge. No need to hand-roll ZIP lists.\n\n**Related endpoints:** [List Saved Templates](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/templates/) \u00b7 [Create a Saved Template](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/templates/) \u00b7 [Get a Saved Template](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/templates/{id}/)",
        "x-credits": "1 credit per search returned. Follow-up questions and failed calls cost nothing.",
        "x-rate-limit": "No fixed limit.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "Plain-English description of the target audience. 5-2000 characters. Example: 'plumbing leads in South Side Chicago' or 'absentee owners with 50%+ equity in Tampa built before 1990'."
                  },
                  "conversation_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "UUID from a previous response. Pass this to continue a clarification thread, the AI loads all prior turns automatically."
                  }
                },
                "required": [
                  "prompt"
                ]
              },
              "examples": {
                "example": {
                  "summary": "Example",
                  "value": {
                    "prompt": "plumbing leads in South Side Chicago"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful: filters applied, ready to pipe into /preview/ or /execute/",
            "content": {
              "application/json": {
                "examples": {
                  "successful_filters_applied_ready_to_pipe": {
                    "summary": "Successful: filters applied, ready to pipe into /preview/ or /execute/",
                    "value": {
                      "strategy": "custom",
                      "geography": {
                        "mode": "zips",
                        "zip_codes": [
                          "60609",
                          "60615",
                          "60617",
                          "60619",
                          "60620",
                          "60621"
                        ]
                      },
                      "filter_overrides": {
                        "property_type": "SFR",
                        "year_built_max": 2000,
                        "absentee_owner": false
                      },
                      "rationale": {
                        "summary": "Owner-occupied single-family homes in the South Side Chicago ZIP codes built before 2000 \u2014 older plumbing systems are common in this age range.",
                        "steps": [],
                        "assumptions": [],
                        "warnings": [
                          "Applied Year Built \u2264 2000. To include rentals, remove the absentee-owner filter."
                        ]
                      },
                      "confidence": 0.88,
                      "needs_clarification": false,
                      "clarifying_question": null,
                      "conversation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                      "credits_deducted": 1,
                      "meta": {
                        "model": "traceai-1-20260321",
                        "provider": "tracerfy",
                        "prompt_version": "v1",
                        "input_tokens": 0,
                        "output_tokens": 0,
                        "latency_ms": 842,
                        "cached": false
                      }
                    }
                  },
                  "clarification_needed_ai_needs_more_info_": {
                    "summary": "Clarification needed: AI needs more info before it can search",
                    "value": {
                      "strategy": "custom",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "(pending)"
                        ]
                      },
                      "filter_overrides": {},
                      "rationale": {
                        "summary": "I can help find leads in Austin, but I need to know what kind. Investors, distressed sellers, homeowners for a service, or something else?",
                        "steps": [],
                        "assumptions": [],
                        "warnings": []
                      },
                      "confidence": 0.3,
                      "needs_clarification": true,
                      "clarifying_question": "What kind of leads are you looking for? Are you targeting investors, distressed sellers, or homeowners for a specific service?",
                      "conversation_id": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
                      "credits_deducted": 1
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing / too-long prompt or bad conversation_id: Empty prompt",
            "content": {
              "application/json": {
                "examples": {
                  "missing_too_long_prompt_or_bad_conversat": {
                    "summary": "Missing / too-long prompt or bad conversation_id: Empty prompt",
                    "value": {
                      "error": "Missing 'prompt' field."
                    }
                  },
                  "missing_too_long_prompt_or_bad_conversat_": {
                    "summary": "Missing / too-long prompt or bad conversation_id: Over 2000 characters",
                    "value": {
                      "error": "Prompt too long (max 2000 characters)."
                    }
                  },
                  "missing_too_long_prompt_or_bad_conversat__": {
                    "summary": "Missing / too-long prompt or bad conversation_id: conversation_id is not a UUID",
                    "value": {
                      "error": "Invalid conversation_id \u2014 must be a UUID."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. You need at least 1 credit(s) to use AI assist. Your balance is 0 credits."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "examples": {
                  "unexpected_error": {
                    "summary": "Unexpected error",
                    "value": {
                      "error": "AI assist hit an unexpected error. Please try again.",
                      "code": "ai_unexpected"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "AI provider error (not charged)",
            "content": {
              "application/json": {
                "examples": {
                  "ai_provider_error_not_charged": {
                    "summary": "AI provider error (not charged)",
                    "value": {
                      "error": "AI assist failed: AI provider error: upstream model error"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "AI assist not configured on this server",
            "content": {
              "application/json": {
                "examples": {
                  "ai_assist_not_configured_on_this_server": {
                    "summary": "AI assist not configured on this server",
                    "value": {
                      "error": "AI assist is not configured on this server.",
                      "code": "ai_not_configured"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/templates/": {
      "get": {
        "tags": [
          "Property Search"
        ],
        "operationId": "listSavedTemplates",
        "summary": "List Saved Templates",
        "description": "A **template** is a saved, reusable lead-list configuration, a strategy, geography, and optional filter overrides you can re-run on demand or attach a [Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/) to. Templates are free to create and store; you're only billed when you actually build a list from one via [/execute/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/) (pass the template's `id` as `template_id`) or when a Monitor delivers.\n\n**GET** returns your active templates. **POST** creates one. Templates are owner-scoped, you only ever see your own.\n\n**Related endpoints:** [Create a Saved Template](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/templates/) \u00b7 [Get a Saved Template](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/templates/{id}/) \u00b7 [Update a Saved Template](/skip-tracing-api-documentation/tag/property-search/PATCH/v1/api/property-search/templates/{id}/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "responses": {
          "200": {
            "description": "GET: 200 (list)",
            "content": {
              "application/json": {
                "examples": {
                  "get_200_list": {
                    "summary": "GET: 200 (list)",
                    "value": {
                      "templates": [
                        {
                          "id": 7,
                          "name": "Phoenix High-Equity Absentee",
                          "strategy": "high_equity_absentee",
                          "geography": {
                            "mode": "city",
                            "cities": [
                              "Phoenix"
                            ],
                            "states": [
                              "AZ"
                            ]
                          },
                          "filter_overrides": {
                            "year_built_max": 2015
                          },
                          "created_at": "2026-07-15T14:02:00Z",
                          "updated_at": "2026-07-15T14:02:00Z",
                          "last_run_at": null,
                          "run_count": 0
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Templates rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Property Search"
        ],
        "operationId": "createASavedTemplate",
        "summary": "Create a Saved Template",
        "description": "A **template** is a saved, reusable lead-list configuration, a strategy, geography, and optional filter overrides you can re-run on demand or attach a [Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/) to. Templates are free to create and store; you're only billed when you actually build a list from one via [/execute/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/) (pass the template's `id` as `template_id`) or when a Monitor delivers.\n\n**GET** returns your active templates. **POST** creates one. Templates are owner-scoped, you only ever see your own.\n\n**Related endpoints:** [Get a Saved Template](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/templates/{id}/) \u00b7 [Update a Saved Template](/skip-tracing-api-documentation/tag/property-search/PATCH/v1/api/property-search/templates/{id}/) \u00b7 [Delete a Saved Template](/skip-tracing-api-documentation/tag/property-search/DELETE/v1/api/property-search/templates/{id}/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Label for the template (max 120 chars)."
                  },
                  "strategy": {
                    "type": "string",
                    "description": "A preset key (or comma-separated keys) from [GET /filters/](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/filters/), or 'custom'."
                  },
                  "geography": {
                    "type": "object",
                    "description": "Same shape as [/execute/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/), e.g. `{\"mode\": \"city\", \"cities\": [\"Phoenix\"], \"states\": [\"AZ\"]}`."
                  },
                  "filter_overrides": {
                    "type": "object",
                    "description": "Optional filters merged on top of the strategy. Validated against the same whitelist as /execute/."
                  }
                },
                "required": [
                  "name",
                  "strategy",
                  "geography"
                ]
              },
              "examples": {
                "create_a_template": {
                  "summary": "Create a template",
                  "value": {
                    "name": "Phoenix High-Equity Absentee",
                    "strategy": "high_equity_absentee",
                    "geography": {
                      "mode": "city",
                      "cities": [
                        "Phoenix"
                      ],
                      "states": [
                        "AZ"
                      ]
                    },
                    "filter_overrides": {
                      "year_built_max": 2015
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "POST: 201 Created",
            "content": {
              "application/json": {
                "examples": {
                  "post_201_created": {
                    "summary": "POST: 201 Created",
                    "value": {
                      "id": 7,
                      "name": "Phoenix High-Equity Absentee",
                      "strategy": "high_equity_absentee",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "Phoenix"
                        ],
                        "states": [
                          "AZ"
                        ]
                      },
                      "filter_overrides": {
                        "year_built_max": 2015
                      },
                      "created_at": "2026-07-15T14:02:00Z",
                      "updated_at": "2026-07-15T14:02:00Z",
                      "last_run_at": null,
                      "run_count": 0,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unknown strategy",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_strategy": {
                    "summary": "Unknown strategy",
                    "value": {
                      "strategy": [
                        "Unknown strategy 'nope'. Valid options: ['active_flipper', 'auction_property', 'cash_buyer_investor', 'custom', 'expired_mls', 'failed_listing', 'free_and_clear', 'high_equity_absentee', 'high_equity_refi_candidate', 'hvac_older_home_owner_occupied', 'judgment_lien', 'long_term_owner_listing_opportunity', 'low_equity', 'owner_deceased', 'pre_foreclosure_motivated', 'probate_inherited', 'recent_homeowner', 'reo_bank_owned', 'roofing_older_home_high_equity', 'solar_owner_occupied_high_value', 'tax_delinquent', 'tired_landlord', 'vacant', 'vacant_land', 'zombie_property']"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Templates rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-search/templates/{id}/": {
      "get": {
        "tags": [
          "Property Search"
        ],
        "operationId": "getASavedTemplate",
        "summary": "Get a Saved Template",
        "description": "Read, rename/retune, or remove a single saved template.\n\n**GET** returns the template. **PATCH** updates any of `name`, `strategy`, `geography`, or `filter_overrides` (partial, send only the fields you're changing). **DELETE** removes it for good (returns `204`); future GETs return 404.\n\nEditing or deleting a template **does not** affect any Monitor already created from it, Monitors snapshot their criteria at creation time. Cross-account IDs return 404.\n\n**Related endpoints:** [Update a Saved Template](/skip-tracing-api-documentation/tag/property-search/PATCH/v1/api/property-search/templates/{id}/) \u00b7 [Delete a Saved Template](/skip-tracing-api-documentation/tag/property-search/DELETE/v1/api/property-search/templates/{id}/) \u00b7 [List Strategies and Filters](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/filters/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The template id."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "id": 7,
                      "name": "Phoenix Q3 Absentee",
                      "strategy": "high_equity_absentee",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "Phoenix"
                        ],
                        "states": [
                          "AZ"
                        ]
                      },
                      "filter_overrides": {
                        "year_built_max": 2015
                      },
                      "created_at": "2026-07-15T14:02:00Z",
                      "updated_at": "2026-07-19T16:10:00Z",
                      "last_run_at": null,
                      "run_count": 0,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account template",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_template": {
                    "summary": "Unknown or cross-account template",
                    "value": {
                      "error": "Template not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Templates rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Property Search"
        ],
        "operationId": "updateASavedTemplate",
        "summary": "Update a Saved Template",
        "description": "Read, rename/retune, or remove a single saved template.\n\n**GET** returns the template. **PATCH** updates any of `name`, `strategy`, `geography`, or `filter_overrides` (partial, send only the fields you're changing). **DELETE** removes it for good (returns `204`); future GETs return 404.\n\nEditing or deleting a template **does not** affect any Monitor already created from it, Monitors snapshot their criteria at creation time. Cross-account IDs return 404.\n\n**Related endpoints:** [Delete a Saved Template](/skip-tracing-api-documentation/tag/property-search/DELETE/v1/api/property-search/templates/{id}/) \u00b7 [List Strategies and Filters](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/filters/) \u00b7 [Preview a Search](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/preview/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The template id."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "(PATCH) New label."
                  },
                  "strategy": {
                    "type": "string",
                    "description": "(PATCH) New strategy key(s)."
                  },
                  "geography": {
                    "type": "object",
                    "description": "(PATCH) New geography object."
                  },
                  "filter_overrides": {
                    "type": "object",
                    "description": "(PATCH) New overrides."
                  }
                }
              },
              "examples": {
                "rename": {
                  "summary": "Rename",
                  "value": {
                    "name": "Phoenix Q3 Absentee"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "id": 7,
                      "name": "Phoenix Q3 Absentee",
                      "strategy": "high_equity_absentee",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "Phoenix"
                        ],
                        "states": [
                          "AZ"
                        ]
                      },
                      "filter_overrides": {
                        "year_built_max": 2015
                      },
                      "created_at": "2026-07-15T14:02:00Z",
                      "updated_at": "2026-07-19T16:10:00Z",
                      "last_run_at": null,
                      "run_count": 0,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account template",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_template": {
                    "summary": "Unknown or cross-account template",
                    "value": {
                      "error": "Template not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Templates rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Property Search"
        ],
        "operationId": "deleteASavedTemplate",
        "summary": "Delete a Saved Template",
        "description": "Read, rename/retune, or remove a single saved template.\n\n**GET** returns the template. **PATCH** updates any of `name`, `strategy`, `geography`, or `filter_overrides` (partial, send only the fields you're changing). **DELETE** removes it for good (returns `204`); future GETs return 404.\n\nEditing or deleting a template **does not** affect any Monitor already created from it, Monitors snapshot their criteria at creation time. Cross-account IDs return 404.\n\n**Related endpoints:** [List Strategies and Filters](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/filters/) \u00b7 [Preview a Search](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/preview/) \u00b7 [Build a Lead List](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The template id."
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted (no body)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account template",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_template": {
                    "summary": "Unknown or cross-account template",
                    "value": {
                      "error": "Template not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Templates rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-monitors/": {
      "post": {
        "tags": [
          "Property Monitors"
        ],
        "operationId": "createAMonitor",
        "summary": "Create a Monitor",
        "description": "A **Monitor** turns a lead-list configuration into a recurring, self-running subscription. On each scheduled run &mdash; **daily or weekly**, your choice &mdash; it computes the **delta**, matching properties in our property database that it hasn't delivered to you before, skip traces only those new ones, and delivers them as a CSV + [webhook](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/). If nothing new matched that run, nothing is delivered and nothing is charged.\n\n**Billing: 25 credits per new delivered lead, you only pay when new matching properties are found.** A day with zero new matches costs zero.\n\n**Two ways to create** (send exactly one form):\n\n- **From a saved template:** pass `template_id`. The template's strategy + geography + overrides are snapshotted onto the Monitor at creation, so later editing or deleting the template never changes what the Monitor delivers.\n- **Inline:** pass `strategy` + `geography` (+ optional `filter_overrides`), exactly like [/execute/](/skip-tracing-api-documentation/tag/property-search/POST/v1/api/property-search/execute/).\n\nSending both forms, or neither, returns `400`. Up to **5 active monitors** per account (higher limits for enterprise/reseller accounts on request).\n\n**Market size limit:** a monitor can track up to **5,000 matching properties**. If your strategy + geography matches more than that, creation returns `400`, narrow it (a tighter area, an equity band, a price range, or a property type).\n\n**First run:** on creation we snapshot everything that already matches as your baseline, those existing properties are *not* delivered or charged. From then on you only receive properties that become new matches *after* you subscribed (a saved-search &ldquo;new since&rdquo; alert).\n\nWhen a Monitor delivers, Tracerfy POSTs to your account [webhook_url](/skip-tracing-api-documentation/webhook/POST/leadlistcompleted) with a `lead_list` payload carrying `monitor_id` / `monitor_name`, non-null only for monitor deliveries, so you can tell them apart from one-shot lists and route them. The payload hands you both URLs directly: `download_url` for the CSV, and `rows_url` to pull structured rows as JSON, no second call to figure out where to pull. Example payload:\n\n```\n{\n  \"id\": 8123,\n  \"type\": \"lead_list\",\n  \"name\": \"Monitor: Phoenix High-Equity Absentee, Jul 20, 2026\",\n  \"strategy\": \"high_equity_absentee\",\n  \"monitor_id\": 12,\n  \"monitor_name\": \"Phoenix High-Equity Absentee\",\n  \"created_at\": \"2026-07-20T11:31:02Z\",\n  \"completed_at\": \"2026-07-20T11:34:18Z\",\n  \"pending\": false,\n  \"download_url\": \"https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/monitor_phoenix-high-equity-absentee_2026-07-20_a1b2c3d4.csv\",\n  \"rows_url\": \"/v1/api/property-search/8123/rows/\",\n  \"requested_count\": 500,\n  \"actual_count\": 37,\n  \"credits_deducted\": 925\n}\n```\n\n**Related endpoints:** [List Monitors](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/) \u00b7 [Get a Monitor](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/{id}/) \u00b7 [Delete a Monitor](/skip-tracing-api-documentation/tag/property-monitors/DELETE/v1/api/property-monitors/{id}/)",
        "x-credits": "Free to create. Each run charges 25 credits per new property it delivers.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync. Runs happen later on the schedule you choose.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "template_id": {
                    "type": "integer",
                    "description": "Clone criteria from one of your saved templates. Mutually exclusive with the inline fields below."
                  },
                  "strategy": {
                    "type": "string",
                    "description": "Inline form: preset key(s) from [GET /filters/](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/filters/). Required when not using template_id."
                  },
                  "geography": {
                    "type": "object",
                    "description": "Inline form: same shape as /execute/. Required when not using template_id."
                  },
                  "filter_overrides": {
                    "type": "object",
                    "description": "Inline form: optional filters merged on top of the strategy."
                  },
                  "name": {
                    "type": "string",
                    "description": "Optional label. Defaults to the template's name when created from a template."
                  },
                  "frequency": {
                    "type": "string",
                    "description": "How often the monitor runs: `daily` or `weekly`. Defaults to `daily`."
                  },
                  "max_rows_per_run": {
                    "type": "integer",
                    "description": "Cap on new leads delivered per run. Default 500, max 25000."
                  },
                  "email_delivery": {
                    "type": "boolean",
                    "description": "Email you each delivery's CSV. Defaults to true (independent of your account email preference)."
                  }
                }
              },
              "examples": {
                "inline_form": {
                  "summary": "Inline form",
                  "value": {
                    "strategy": "high_equity_absentee",
                    "geography": {
                      "mode": "city",
                      "cities": [
                        "Phoenix"
                      ],
                      "states": [
                        "AZ"
                      ]
                    },
                    "filter_overrides": {
                      "year_built_max": 2015
                    },
                    "name": "Phoenix High-Equity Absentee",
                    "frequency": "weekly",
                    "max_rows_per_run": 500,
                    "email_delivery": true
                  }
                },
                "from_a_saved_template_mutually_exclusive": {
                  "summary": "From a saved template (mutually exclusive with the inline fields)",
                  "value": {
                    "template_id": 7,
                    "max_rows_per_run": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "id": 12,
                      "name": "Phoenix High-Equity Absentee",
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "Phoenix"
                        ],
                        "states": [
                          "AZ"
                        ]
                      },
                      "geography_label": "Phoenix, AZ",
                      "frequency": "daily",
                      "max_rows_per_run": 500,
                      "email_delivery": true,
                      "credits_per_row": 25,
                      "baseline_count": 1284,
                      "baseline_ready": true,
                      "status": "active",
                      "last_run_at": null,
                      "next_run_at": "2026-07-20T11:30:00Z",
                      "error_message": "",
                      "consecutive_failures": 0,
                      "created_at": "2026-07-19T16:00:00Z",
                      "last_delivery_count": null,
                      "source": "api",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Both forms supplied",
            "content": {
              "application/json": {
                "examples": {
                  "both_forms_supplied": {
                    "summary": "Both forms supplied",
                    "value": {
                      "non_field_errors": [
                        "Provide EITHER template_id OR inline strategy+geography, not both."
                      ]
                    }
                  },
                  "neither_form_supplied": {
                    "summary": "Neither form supplied",
                    "value": {
                      "non_field_errors": [
                        "Provide either template_id or inline strategy+geography."
                      ]
                    }
                  },
                  "active_monitor_cap_reached": {
                    "summary": "Active monitor cap reached",
                    "value": {
                      "error": "You already have 5 active monitors (the maximum). Pause or delete one before creating another."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Account suspended (unpaid invoices)",
            "content": {
              "application/json": {
                "examples": {
                  "account_suspended_unpaid_invoices": {
                    "summary": "Account suspended (unpaid invoices)",
                    "value": {
                      "error": "Your account has been temporarily suspended due to unpaid invoices. Please contact support@tracerfy.com to resolve outstanding payments."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "template_id not found (or not yours)",
            "content": {
              "application/json": {
                "examples": {
                  "template_id_not_found_or_not_yours": {
                    "summary": "template_id not found (or not yours)",
                    "value": {
                      "error": "Template not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Monitors rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Property Monitors"
        ],
        "operationId": "listMonitors",
        "summary": "List Monitors",
        "description": "**GET /monitors/** lists your monitors. **GET /monitors/&lt;id&gt;/** returns a single monitor with its schedule (`last_run_at`, `next_run_at`), lifecycle `status` (`active` / `paused` / `error`), resolved `credits_per_row`, and `last_delivery_count`. Owner-scoped; unknown or cross-account IDs return 404.\n\n**Related endpoints:** [Get a Monitor](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/{id}/) \u00b7 [Delete a Monitor](/skip-tracing-api-documentation/tag/property-monitors/DELETE/v1/api/property-monitors/{id}/) \u00b7 [Pause a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/{id}/pause/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "responses": {
          "200": {
            "description": "GET /monitors/: 200 (list)",
            "content": {
              "application/json": {
                "examples": {
                  "get_monitors_200_list": {
                    "summary": "GET /monitors/: 200 (list)",
                    "value": {
                      "monitors": [
                        {
                          "id": 12,
                          "name": "Phoenix High-Equity Absentee",
                          "strategy": "high_equity_absentee",
                          "strategy_label": "High Equity Absentee",
                          "geography": {
                            "mode": "city",
                            "cities": [
                              "Phoenix"
                            ],
                            "states": [
                              "AZ"
                            ]
                          },
                          "geography_label": "Phoenix, AZ",
                          "frequency": "daily",
                          "max_rows_per_run": 500,
                          "email_delivery": true,
                          "credits_per_row": 25,
                          "baseline_count": 1284,
                          "baseline_ready": true,
                          "status": "active",
                          "last_run_at": null,
                          "next_run_at": "2026-07-20T11:30:00Z",
                          "error_message": "",
                          "consecutive_failures": 0,
                          "created_at": "2026-07-19T16:00:00Z",
                          "last_delivery_count": null,
                          "source": "api"
                        }
                      ],
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Monitors rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-monitors/{id}/": {
      "get": {
        "tags": [
          "Property Monitors"
        ],
        "operationId": "getAMonitor",
        "summary": "Get a Monitor",
        "description": "**GET /monitors/** lists your monitors. **GET /monitors/&lt;id&gt;/** returns a single monitor with its schedule (`last_run_at`, `next_run_at`), lifecycle `status` (`active` / `paused` / `error`), resolved `credits_per_row`, and `last_delivery_count`. Owner-scoped; unknown or cross-account IDs return 404.\n\n**Related endpoints:** [Delete a Monitor](/skip-tracing-api-documentation/tag/property-monitors/DELETE/v1/api/property-monitors/{id}/) \u00b7 [Pause a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/{id}/pause/) \u00b7 [Resume a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/{id}/resume/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Omit for the list; include for a single monitor."
          }
        ],
        "responses": {
          "200": {
            "description": "GET /monitors/12/: 200 (detail)",
            "content": {
              "application/json": {
                "examples": {
                  "get_monitors_12_200_detail": {
                    "summary": "GET /monitors/12/: 200 (detail)",
                    "value": {
                      "id": 12,
                      "name": "Phoenix High-Equity Absentee",
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "Phoenix"
                        ],
                        "states": [
                          "AZ"
                        ]
                      },
                      "geography_label": "Phoenix, AZ",
                      "frequency": "daily",
                      "max_rows_per_run": 500,
                      "email_delivery": true,
                      "credits_per_row": 25,
                      "baseline_count": 1284,
                      "baseline_ready": true,
                      "status": "active",
                      "last_run_at": null,
                      "next_run_at": "2026-07-20T11:30:00Z",
                      "error_message": "",
                      "consecutive_failures": 0,
                      "created_at": "2026-07-19T16:00:00Z",
                      "last_delivery_count": null,
                      "source": "api",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account monitor",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_monitor": {
                    "summary": "Unknown or cross-account monitor",
                    "value": {
                      "error": "Monitor not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Monitors rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Property Monitors"
        ],
        "operationId": "deleteAMonitor",
        "summary": "Delete a Monitor",
        "description": "Control a monitor's lifecycle:\n\n- **POST /monitors/&lt;id&gt;/pause/**: pause the monitor. It stops running until you resume it, and keeps its history.\n- **POST /monitors/&lt;id&gt;/resume/**: resume a paused monitor. It starts running again on its schedule.\n- **DELETE /monitors/&lt;id&gt;/**: delete the monitor. It stops running and is removed from your account; the lead lists and CSVs it already delivered stay available. Returns `204`.\n\nAll three are owner-scoped; unknown or cross-account IDs return 404.\n\n**Related endpoints:** [Pause a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/{id}/pause/) \u00b7 [Resume a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/{id}/resume/) \u00b7 [Monitor Delivery History](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/{id}/runs/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The monitor id."
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted (no body)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account monitor",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_monitor": {
                    "summary": "Unknown or cross-account monitor",
                    "value": {
                      "error": "Monitor not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Monitors rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-monitors/{id}/pause/": {
      "post": {
        "tags": [
          "Property Monitors"
        ],
        "operationId": "pauseAMonitor",
        "summary": "Pause a Monitor",
        "description": "Control a monitor's lifecycle:\n\n- **POST /monitors/&lt;id&gt;/pause/**: pause the monitor. It stops running until you resume it, and keeps its history.\n- **POST /monitors/&lt;id&gt;/resume/**: resume a paused monitor. It starts running again on its schedule.\n- **DELETE /monitors/&lt;id&gt;/**: delete the monitor. It stops running and is removed from your account; the lead lists and CSVs it already delivered stay available. Returns `204`.\n\nAll three are owner-scoped; unknown or cross-account IDs return 404.\n\n**Related endpoints:** [Resume a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/{id}/resume/) \u00b7 [Monitor Delivery History](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/{id}/runs/) \u00b7 [Create a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The monitor id."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "id": 12,
                      "name": "Phoenix High-Equity Absentee",
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "Phoenix"
                        ],
                        "states": [
                          "AZ"
                        ]
                      },
                      "geography_label": "Phoenix, AZ",
                      "frequency": "daily",
                      "max_rows_per_run": 500,
                      "email_delivery": true,
                      "credits_per_row": 25,
                      "baseline_count": 1284,
                      "baseline_ready": true,
                      "status": "paused",
                      "last_run_at": null,
                      "next_run_at": "2026-07-20T11:30:00Z",
                      "error_message": "",
                      "consecutive_failures": 0,
                      "created_at": "2026-07-19T16:00:00Z",
                      "last_delivery_count": null,
                      "source": "api",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account monitor",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_monitor": {
                    "summary": "Unknown or cross-account monitor",
                    "value": {
                      "error": "Monitor not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Monitors rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-monitors/{id}/resume/": {
      "post": {
        "tags": [
          "Property Monitors"
        ],
        "operationId": "resumeAMonitor",
        "summary": "Resume a Monitor",
        "description": "Control a monitor's lifecycle:\n\n- **POST /monitors/&lt;id&gt;/pause/**: pause the monitor. It stops running until you resume it, and keeps its history.\n- **POST /monitors/&lt;id&gt;/resume/**: resume a paused monitor. It starts running again on its schedule.\n- **DELETE /monitors/&lt;id&gt;/**: delete the monitor. It stops running and is removed from your account; the lead lists and CSVs it already delivered stay available. Returns `204`.\n\nAll three are owner-scoped; unknown or cross-account IDs return 404.\n\n**Related endpoints:** [Monitor Delivery History](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/{id}/runs/) \u00b7 [Create a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/) \u00b7 [List Monitors](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The monitor id."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "id": 12,
                      "name": "Phoenix High-Equity Absentee",
                      "strategy": "high_equity_absentee",
                      "strategy_label": "High Equity Absentee",
                      "geography": {
                        "mode": "city",
                        "cities": [
                          "Phoenix"
                        ],
                        "states": [
                          "AZ"
                        ]
                      },
                      "geography_label": "Phoenix, AZ",
                      "frequency": "daily",
                      "max_rows_per_run": 500,
                      "email_delivery": true,
                      "credits_per_row": 25,
                      "baseline_count": 1284,
                      "baseline_ready": true,
                      "status": "paused",
                      "last_run_at": null,
                      "next_run_at": "2026-07-20T11:30:00Z",
                      "error_message": "",
                      "consecutive_failures": 0,
                      "created_at": "2026-07-19T16:00:00Z",
                      "last_delivery_count": null,
                      "source": "api",
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account monitor",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_monitor": {
                    "summary": "Unknown or cross-account monitor",
                    "value": {
                      "error": "Monitor not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Monitors rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/property-monitors/{id}/runs/": {
      "get": {
        "tags": [
          "Property Monitors"
        ],
        "operationId": "monitorDeliveryHistory",
        "summary": "Monitor Delivery History",
        "description": "Returns the lead lists a monitor has delivered, **newest first**. Each run is a normal Lead Builder list, poll or download it exactly like an /execute/ result. Every run carries a `rows_url` (pull structured rows as JSON) and a `download_url` (CSV) directly, you never have to build those URLs yourself.\n\n**Paginated: full history is always reachable.** The `500` is a *page-size* limit (the most runs a single response returns), **not** a cap on how much history you can retrieve. There's no upper bound on `page`: every delivery a monitor has ever made stays retrievable. `per_page` defaults to 100 (max 500); increment `page` to walk older runs, and read `total_runs` / `total_pages` to know when you've reached the end. Newest first. Runs in progress show `status: \"pending\"` with an empty `download_url` (their `rows_url` returns `409` until the run finishes).\n\n**Related endpoints:** [Create a Monitor](/skip-tracing-api-documentation/tag/property-monitors/POST/v1/api/property-monitors/) \u00b7 [List Monitors](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/) \u00b7 [Get a Monitor](/skip-tracing-api-documentation/tag/property-monitors/GET/v1/api/property-monitors/{id}/)",
        "x-credits": "Free.",
        "x-rate-limit": "60 requests per minute per account.",
        "x-mode": "Sync",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The monitor id."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1-based page number (newest first). Defaults to 1."
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Runs per *page* (response size: not a cap on total history). Defaults to 100, max 500."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "runs": [
                        {
                          "id": 8123,
                          "name": "Monitor: Phoenix High-Equity Absentee \u2014 Jul 20, 2026",
                          "strategy": "high_equity_absentee",
                          "strategy_label": "High Equity Absentee",
                          "status": "complete",
                          "created_at": "2026-07-20T11:31:02Z",
                          "completed_at": "2026-07-20T11:34:18Z",
                          "requested_count": 500,
                          "actual_count": 37,
                          "credits_deducted": 925,
                          "monitor_id": 12,
                          "monitor_name": "Phoenix High-Equity Absentee",
                          "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/monitor_phoenix-high-equity-absentee_2026-07-20_a1b2c3d4.csv",
                          "rows_url": "/v1/api/property-search/8123/rows/"
                        }
                      ],
                      "total_runs": 128,
                      "page": 1,
                      "per_page": 100,
                      "total_pages": 2,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown or cross-account monitor",
            "content": {
              "application/json": {
                "examples": {
                  "unknown_or_cross_account_monitor": {
                    "summary": "Unknown or cross-account monitor",
                    "value": {
                      "error": "Monitor not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 60 requests per minute per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "Monitors rate limit exceeded. Max 60 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/analytics/": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "usageAnalytics",
        "summary": "Usage Analytics",
        "description": "Aggregated summary for your account: total_queues, properties_traced (sum of posted addresses per queue), queues_pending, queues_completed, and current credit balance.",
        "x-credits": "Free.",
        "x-rate-limit": "No limit.",
        "x-mode": "Sync",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "total_queues": 12,
                      "properties_traced": 18350,
                      "queues_pending": 2,
                      "queues_completed": 10,
                      "balance": 940,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/api/dnc/scrub/": {
      "post": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "dncScrubV1",
        "summary": "DNC Scrub (v1)",
        "description": "Submit a phone list for DNC (Do Not Call) scrubbing. Upload a CSV with one or more phone columns, or pass a JSON array of phone numbers directly. Each phone is checked against Federal DNC, State DNC, DMA, and TCPA Litigator databases. 1 credit per phone checked.\n\n**A v2 of this endpoint is available** at [POST /v2/api/dnc/scrub/](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub/) and is recommended for new integrations. Same parameters, same price; see [DNC API Versions](/skip-tracing-api-documentation/tag/phone-verification-dnc).\n\n**Input options (pick one):**\n\n- **CSV with single column**: csv_file + phone_column (string)\n- **CSV with multiple columns**: csv_file + phone_columns (array), phones are merged &amp; deduplicated\n- **JSON phone list**: phones array via application/json\n\n**Related endpoints:** [DNC Scrub from a Trace (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/scrub-from-queue/) \u00b7 [DNC Lookup (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/lookup/) \u00b7 [Phone Verification](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/phone/verify/)",
        "x-credits": "1 credit per phone checked, charged when the job finishes.",
        "x-rate-limit": "10 scrubs per 5 minutes per account.",
        "x-mode": "Async",
        "requestBody": {
          "required": false,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "csv_file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV file containing phone numbers. Required for Options 1 & 2. Do not send with phones."
                  },
                  "phone_column": {
                    "type": "string",
                    "description": "Single column name containing phone numbers (Option 1). Internally normalized to phone_columns. Mutually exclusive with phone_columns."
                  },
                  "phone_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of column names containing phone numbers (Option 2). Phones are merged & deduplicated. When multiple columns are used, labels are prefixed with the column name, e.g. '(Phone_1) John Doe'. Mutually exclusive with phone_column."
                  },
                  "label_column": {
                    "type": "string",
                    "description": "Single column to label each phone (e.g., name). Internally normalized to label_columns. Mutually exclusive with label_columns."
                  },
                  "label_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of columns to combine as a label for each phone (e.g., [\"address\", \"city\", \"state\"]). Values are joined with commas. When using multiple phone_columns, labels are also prefixed with the column name."
                  },
                  "phones": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Direct list of phone numbers via JSON body (Option 3). Do not send with csv_file."
                  }
                }
              },
              "example": {
                "csv_file": "@/path/to/phones.csv",
                "phone_column": "Phone",
                "label_column": "Name"
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone_column": {
                    "type": "string",
                    "description": "Single column name containing phone numbers (Option 1). Internally normalized to phone_columns. Mutually exclusive with phone_columns."
                  },
                  "phone_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of column names containing phone numbers (Option 2). Phones are merged & deduplicated. When multiple columns are used, labels are prefixed with the column name, e.g. '(Phone_1) John Doe'. Mutually exclusive with phone_column."
                  },
                  "label_column": {
                    "type": "string",
                    "description": "Single column to label each phone (e.g., name). Internally normalized to label_columns. Mutually exclusive with label_columns."
                  },
                  "label_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of columns to combine as a label for each phone (e.g., [\"address\", \"city\", \"state\"]). Values are joined with commas. When using multiple phone_columns, labels are also prefixed with the column name."
                  },
                  "phones": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Direct list of phone numbers via JSON body (Option 3). Do not send with csv_file."
                  }
                }
              },
              "examples": {
                "option_3_json_phone_list_no_csv": {
                  "summary": "Option 3: JSON phone list (no CSV)",
                  "value": {
                    "phones": [
                      "5125550100",
                      "5125550101",
                      "5125550102"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "message": "DNC scrub started",
                      "dnc_queue_id": 5,
                      "created_at": "2025-01-15T09:30:00Z",
                      "status": "pending",
                      "phones_to_check": 150,
                      "credits_per_phone": 1,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Phone column not found in your CSV",
            "content": {
              "application/json": {
                "examples": {
                  "phone_column_not_found_in_your_csv": {
                    "summary": "Phone column not found in your CSV",
                    "value": {
                      "error": "Column \"Phone\" not found in CSV"
                    }
                  },
                  "no_usable_phone_numbers": {
                    "summary": "No usable phone numbers",
                    "value": {
                      "error": "No valid phone numbers found"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. You need 150 credits for DNC scrubbing. You have 0."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Account suspended (unpaid invoices)",
            "content": {
              "application/json": {
                "examples": {
                  "account_suspended_unpaid_invoices": {
                    "summary": "Account suspended (unpaid invoices)",
                    "value": {
                      "error": "Account suspended due to unpaid invoices."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 10 scrubs per 5 minutes per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "DNC scrub limit exceeded. Max 10 scrubs per 5 minutes.",
                      "queues_in_window": "10"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/dnc/scrub-from-queue/": {
      "post": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "dncScrubFromATraceV1",
        "summary": "DNC Scrub from a Trace (v1)",
        "description": "Extract phone numbers from a completed trace queue from your skip tracing results and submit them for DNC scrubbing. Optionally specify which phone columns to include. Phones are deduplicated across all selected columns. 1 credit per phone checked.\n\n**A v2 of this endpoint is available** at [POST /v2/api/dnc/scrub-from-queue/](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub-from-queue/). Same parameters, same price; see [DNC API Versions](/skip-tracing-api-documentation/tag/phone-verification-dnc).\n\n**Valid phone_columns:** primary_phone, mobile_1, mobile_2, mobile_3, mobile_4, mobile_5, landline_1, landline_2, landline_3\nIf phone_columns is omitted, all 9 phone fields are included by default.\n\n**Related endpoints:** [DNC Lookup (v1)](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/lookup/) \u00b7 [Phone Verification](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/phone/verify/) \u00b7 [DNC Scrub](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub/)",
        "x-credits": "1 credit per phone checked, charged when the job finishes.",
        "x-rate-limit": "10 scrubs per 5 minutes per account.",
        "x-mode": "Async",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "queue_id": {
                    "type": "integer",
                    "description": "ID of a completed trace queue to extract phones from."
                  },
                  "phone_columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of phone field names to include. Defaults to all 9 phone fields."
                  }
                },
                "required": [
                  "queue_id"
                ]
              },
              "examples": {
                "example": {
                  "summary": "Example",
                  "value": {
                    "queue_id": 37360,
                    "phone_columns": [
                      "primary_phone",
                      "mobile_1",
                      "mobile_2"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "examples": {
                  "example": {
                    "summary": "Example",
                    "value": {
                      "message": "DNC scrub started",
                      "dnc_queue_id": 8,
                      "created_at": "2025-01-15T10:00:00Z",
                      "source_queue_id": 37360,
                      "status": "pending",
                      "phones_to_check": 23,
                      "phone_columns_used": [
                        "primary_phone",
                        "mobile_1",
                        "mobile_2"
                      ],
                      "credits_per_phone": 1,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Source trace still processing",
            "content": {
              "application/json": {
                "examples": {
                  "source_trace_still_processing": {
                    "summary": "Source trace still processing",
                    "value": {
                      "error": "This trace is still processing. Please wait until it completes."
                    }
                  },
                  "no_phones_in_the_selected_columns": {
                    "summary": "No phones in the selected columns",
                    "value": {
                      "error": "No phone numbers found in this trace for the selected columns."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. You need 23 credits for DNC scrubbing. You have 0."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Source trace queue not found",
            "content": {
              "application/json": {
                "examples": {
                  "source_trace_queue_not_found": {
                    "summary": "Source trace queue not found",
                    "value": {
                      "error": "No trace queue found with ID 37360"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 10 scrubs per 5 minutes per account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "DNC scrub limit exceeded. Max 10 scrubs per 5 minutes.",
                      "queues_in_window": "10"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/api/dnc/lookup/": {
      "post": {
        "tags": [
          "Phone Verification & DNC"
        ],
        "operationId": "dncLookupV1",
        "summary": "DNC Lookup (v1)",
        "description": "Synchronous DNC check. Send one phone object or an array of up to 15 phone objects and get back Federal DNC, State DNC, DMA, and TCPA Litigator flags immediately. No queue, no CSV, no waiting.\n\n**Array requests:** results stay in input order, each item is validated and billed independently, and the response returns `results` plus aggregate `credits_deducted`. Each phone counts toward the lookup rate limit.\n\n**5 credits per lookup.** Rate limited to 30 RPM per user.\n\n**A v2 of this endpoint is available** at [POST /v2/api/dnc/lookup/](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/lookup/), which names the matched state registries but drops `dma` and `phone_type`. v2 has its own 120-item-per-minute limit. See [DNC API Versions](/skip-tracing-api-documentation/tag/phone-verification-dnc).\n\n**Use this when:** you need to check a single number before dialing or as part of a real-time CRM workflow. For bulk scrubbing (100+ phones), use [POST /v1/api/dnc/scrub/](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/dnc/scrub/) instead, it self-paces and isn't subject to this 30 RPM limit.\n\n**Response fields:**\n\n- `national_dnc`: on the Federal Do Not Call Registry\n- `state_dnc`: on a State DNC list\n- `dma`: on the Direct Marketing Association list\n- `litigator`: known TCPA litigator\n- `phone_type`: Mobile or Landline\n- `is_clean`: true only if no flags are set\n\n**\u26a0\ufe0f Compliance:** Phones returning `litigator: true` or `national_dnc: true` should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.\n\n**Related endpoints:** [Phone Verification](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v1/api/phone/verify/) \u00b7 [DNC Scrub](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub/) \u00b7 [DNC Scrub from a Trace](/skip-tracing-api-documentation/tag/phone-verification-dnc/POST/v2/api/dnc/scrub-from-queue/)",
        "x-credits": "5 credits per lookup. 0 when the DNC service fails.",
        "x-rate-limit": "30 lookups per minute per account. Each array item counts as one.",
        "x-mode": "Sync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "description": "10-digit US phone number. Formatting is stripped automatically (dashes, spaces, parentheses, leading 1)."
                  }
                },
                "required": [
                  "phone"
                ]
              },
              "examples": {
                "example": {
                  "summary": "One object",
                  "value": {
                    "phone": "4805551234"
                  }
                },
                "array_lookup_up_to_15_objects": {
                  "summary": "Array lookup (up to 15 objects)",
                  "value": [
                    {
                      "phone": "4805551234"
                    },
                    {
                      "phone": "4805559876"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Flagged: not clean",
            "content": {
              "application/json": {
                "examples": {
                  "flagged_not_clean": {
                    "summary": "Flagged: not clean",
                    "value": {
                      "phone": "4805551234",
                      "hit": true,
                      "national_dnc": true,
                      "state_dnc": false,
                      "dma": false,
                      "litigator": false,
                      "phone_type": "Mobile",
                      "is_clean": false,
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "clean_safe_to_proceed": {
                    "summary": "Clean: safe to proceed",
                    "value": {
                      "phone": "6025559876",
                      "hit": true,
                      "national_dnc": false,
                      "state_dnc": false,
                      "dma": false,
                      "litigator": false,
                      "phone_type": "Landline",
                      "is_clean": true,
                      "credits_deducted": 5,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  },
                  "array_response": {
                    "summary": "Array response",
                    "value": {
                      "results": [
                        {
                          "phone": "4805551234",
                          "hit": true,
                          "national_dnc": true,
                          "state_dnc": false,
                          "dma": false,
                          "litigator": false,
                          "phone_type": "Mobile",
                          "is_clean": false,
                          "credits_deducted": 5
                        },
                        {
                          "phone": "4805559876",
                          "hit": true,
                          "national_dnc": false,
                          "state_dnc": false,
                          "dma": false,
                          "litigator": false,
                          "phone_type": "Landline",
                          "is_clean": true,
                          "credits_deducted": 5
                        }
                      ],
                      "credits_deducted": 10,
                      "meta": {
                        "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
                        "timestamp": "2026-07-16T18:22:05Z",
                        "api_version": "2026-03-21"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid phone: No phone in body",
            "content": {
              "application/json": {
                "examples": {
                  "missing_or_invalid_phone_no_phone_in_bod": {
                    "summary": "Missing or invalid phone: No phone in body",
                    "value": {
                      "error": "Missing 'phone' field."
                    }
                  },
                  "missing_or_invalid_phone_not_a_10_digit_": {
                    "summary": "Missing or invalid phone: Not a 10-digit US number",
                    "value": {
                      "error": "Invalid phone number. Must be a 10-digit US number."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "examples": {
                  "insufficient_credits": {
                    "summary": "Insufficient credits",
                    "value": {
                      "error": "Insufficient credits. DNC lookup requires 5 credits. You have 0 credits."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached: 30 lookups per minute per account. Each array item counts as one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "429",
                      "error": "DNC lookup limit exceeded. Max 30 lookups per 1 minute(s). For higher volume, use the batch scrub endpoint, which respects upstream rate limits automatically.",
                      "lookups_in_window": "30",
                      "lookups_requested": "1",
                      "retry_after_seconds": "60"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "Upstream temporarily unavailable",
            "content": {
              "application/json": {
                "examples": {
                  "upstream_temporarily_unavailable": {
                    "summary": "Upstream temporarily unavailable",
                    "value": {
                      "error": "DNC lookup service temporarily unavailable. Please try again."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "DNC lookup not configured on this server",
            "content": {
              "application/json": {
                "examples": {
                  "dnc_lookup_not_configured_on_this_server": {
                    "summary": "DNC lookup not configured on this server",
                    "value": {
                      "error": "DNC lookup service is not configured."
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "traceCompleted": {
      "post": {
        "summary": "Trace Job Completed",
        "description": "When a batch skip trace queue completes, Tracerfy POSTs the result to the webhook URL configured in your account profile. This is per-user and dynamic; no registration endpoint is required.\n\nThree payload shapes can arrive at this endpoint, depending on which trace finished:\n\n- **Normal skip trace**: distinguished by `trace_type: \"normal\"` and `credits_per_lead: 1`.\n- **Advanced skip trace**: distinguished by `trace_type: \"advanced\"` and `credits_per_lead: 2`.\n- **APN / parcel trace**: distinguished by `type: \"parcel_trace\"` and the `parcel_queue_id` field. Different shape (no `trace_type`); uses `credits_per_parcel` instead.\n\nEnhanced batch trace webhooks follow the same skip-trace queue shape; only the `trace_type` string and `credits_per_lead` value differ.\n\nTracerfy sends one of the JSON shapes below to your Account.webhook_url when a trace completes.",
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "normal_skip_trace_completed_1_credit_per": {
                  "summary": "Normal skip trace completed: 1 credit per hit",
                  "value": {
                    "id": 365,
                    "created_at": "2025-07-13T18:55:02.962332Z",
                    "pending": false,
                    "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/9a584124-77c2-4612-b8e9-f9efe6fbdc3d.csv",
                    "rows_uploaded": 12,
                    "credits_deducted": 12,
                    "queue_type": "api",
                    "trace_type": "normal",
                    "credits_per_lead": 1
                  }
                },
                "advanced_skip_trace_completed_2_credits_": {
                  "summary": "Advanced skip trace completed: 2 credits per hit",
                  "value": {
                    "id": 366,
                    "created_at": "2025-07-13T19:02:18.114402Z",
                    "pending": false,
                    "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/2b7e9a44-3812-4ae1-8c0f-1d7e92a4f111.csv",
                    "rows_uploaded": 12,
                    "credits_deducted": 24,
                    "queue_type": "api",
                    "trace_type": "advanced",
                    "credits_per_lead": 2
                  }
                },
                "apn_parcel_trace_completed_5_credits_per": {
                  "summary": "APN / parcel trace completed: 5 credits per hit, different payload shape",
                  "value": {
                    "type": "parcel_trace",
                    "event": "parcel_trace.completed",
                    "parcel_queue_id": 42,
                    "status": "completed",
                    "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/parcel-trace-42.csv",
                    "rows_uploaded": 500,
                    "rows_hit": 423,
                    "credits_deducted": 2115,
                    "credits_per_parcel": 5
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to confirm delivery."
          }
        }
      }
    },
    "dncScrubCompleted": {
      "post": {
        "summary": "DNC Scrub Completed",
        "description": "When a DNC scrub completes, Tracerfy POSTs the result to the webhook URL configured in your account profile. The payload includes a `type: \"dnc_scrub\"` field to distinguish it from trace webhooks, plus DNC-specific fields like clean_download_url, phones_checked, and phones_clean.\n\nTracerfy sends this JSON to your Account.webhook_url when a DNC scrub completes.",
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "payload": {
                  "summary": "Payload",
                  "value": {
                    "id": 5,
                    "type": "dnc_scrub",
                    "created_at": "2025-01-15T09:30:00Z",
                    "pending": false,
                    "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/full-results.csv",
                    "clean_download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/clean-results.csv",
                    "rows_uploaded": 150,
                    "phones_checked": 150,
                    "phones_clean": 112,
                    "credits_deducted": 150,
                    "source_type": "upload"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to confirm delivery."
          }
        }
      }
    },
    "leadListCompleted": {
      "post": {
        "summary": "Lead List Completed",
        "description": "When a Lead Builder list completes, Tracerfy POSTs the result to the `webhook_url` configured on your account, the same account-level URL used for skip trace and DNC webhooks. This eliminates the need to poll [/status/](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/), your server gets notified the moment the CSV is ready.\n\n**How to use:** set your `webhook_url` in your account settings. When a lead list completes successfully, Tracerfy sends a POST with the payload below. Your endpoint should return 2xx within 10 seconds.\n\nWebhooks fire for lists created through the API or the AI connector, and for every Monitor delivery. A non-null `monitor_id` tells you a Monitor produced the list.\n\n**Retry:** Tracerfy does not retry failed webhook deliveries. If your server is down when the webhook fires, use [/status/](/skip-tracing-api-documentation/tag/property-search/GET/v1/api/property-search/{id}/) as a fallback to check completion.\n\nTracerfy sends this JSON to your Account.webhook_url when a lead list completes.",
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "payload": {
                  "summary": "Payload",
                  "value": {
                    "id": 42,
                    "type": "lead_list",
                    "name": "Phoenix Q2 Prospects",
                    "strategy": "high_equity_absentee",
                    "monitor_id": null,
                    "monitor_name": null,
                    "created_at": "2026-04-11T18:23:00Z",
                    "completed_at": "2026-04-11T18:37:42Z",
                    "pending": false,
                    "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/lead_list_a1b2c3d4.csv",
                    "rows_url": "/v1/api/property-search/42/rows/",
                    "requested_count": 500,
                    "actual_count": 487,
                    "credits_deducted": 2435
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to confirm delivery."
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "default": {
                "summary": "No key sent",
                "value": {
                  "detail": "Authentication credentials were not provided."
                }
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your Tracerfy API key."
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "description": "Added to every JSON object response.",
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Quote this when you contact support."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "api_version": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "detail": {
            "type": "string",
            "description": "Used for authentication errors."
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      }
    }
  }
}