{
  "openapi": "3.1.0",
  "info": {
    "title": "CheckThatPhone API",
    "summary": "Real-time phone number validation API for US & Canada. Returns carrier data, line type, portability status, deliverability, and geolocation in a single call. Optional add-ons: TCPA litigator filter, landline SMS eligibility lookup, and a free state-DNC & complainer scrub.",
    "description": "## Introduction\n\nCheck a US or Canada phone number with one request. You get the current carrier and line type from a live carrier dip, whether the number was ported, whether it was deactivated recently, a send-or-unsubscribe recommendation for messaging with the reason, and the location and time zone. A live carrier dip means we ask the carrier network at the moment you call, not a stored list.\n\nOptional add-ons check the number against known TCPA litigators, tell you if a landline can receive SMS, and run free state do-not-call and complainer checks.\n\n## Quick start\n\n1. [Sign up](https://checkthatphone.com/sign-up) and copy your API key from the dashboard. Free accounts get 500 credits a month.\n2. Send a `POST` request to `https://api.checkthatphone.com/v1/lookup`. Put the key in the `Authorization` header and the phone number in a JSON body.\n3. The result is in `data`. `credits_used` shows how many credits the call used.\n\n```bash\ncurl --request POST \\\n  --url https://api.checkthatphone.com/v1/lookup \\\n  --header 'Authorization: Bearer YOUR_API_KEY' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"phone\":\"8182925409\"}'\n```\n\nIf you have the IP address of the person who gave you the number (for example from your signup or lead form), send it in `ip` to get a more exact location than the area code gives. Turn on add-ons for one request with `litigatorFilter`, `landlineSmsLookup`, `dncState` and `dncComplainer`. Every response field is explained in the Response fields section below the endpoint. The Test Request button sends real requests and uses credits from your account.\n\n## Authentication\n\nSend your API key as a bearer token with every request:\n\n| Header | Value |\n| --- | --- |\n| `Authorization` | `Bearer YOUR_API_KEY` |\n| `Content-Type` | `application/json` |\n\nKeep the key secret. Anyone who has it can use your credits. You can create and delete keys in the [dashboard](https://checkthatphone.com/dashboard). A key you type into this page stays in your browser tab. We do not store it.",
    "x-scalar-sdk-installation": [
      {
        "lang": "Node.js",
        "description": "Zero dependencies, Node 18+, TypeScript types included. [Source on GitHub](https://github.com/CheckThatPhone/checkthatphone-node).\n\n```bash\nnpm install checkthatphone\n```"
      },
      {
        "lang": "Python",
        "description": "Standard library only, Python 3.9+. [Source on GitHub](https://github.com/CheckThatPhone/checkthatphone-python).\n\n```bash\npip install checkthatphone\n```"
      }
    ],
    "version": "1.5.0",
    "contact": {
      "name": "CheckThatPhone",
      "url": "https://checkthatphone.com",
      "email": "hello@checkthatphone.com"
    },
    "termsOfService": "https://checkthatphone.com/terms"
  },
  "servers": [
    {
      "url": "https://api.checkthatphone.com/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Lookup",
      "description": "One endpoint. One POST returns everything we know about a number."
    },
    {
      "name": "Response fields",
      "description": "Everything the `data` object can hold, in the order it is returned. Every value is a string, including `\"true\"` and `\"false\"`, except the two marked as numbers. The first five groups come with every lookup. The last three appear only when you turn the add-on on, and are left out of the response otherwise.\n\n### Subscriber Info\n\nThe number you sent and when we processed it.\n\n| Field | Description |\n| --- | --- |\n| `subscriber` | The phone number that was queried. |\n| `optDate` | ISO 8601 timestamp of when the query was processed. |\n\n### Deliverability\n\nOur verdict, send or unsubscribe, and the reason. Every response has these.\n\n| Field | Description |\n| --- | --- |\n| `action` | Recommended SMS list action. Returns one of: `\"send\"` — the number passed the enabled technical and screening checks. This does not establish consent or legal authorization to contact the subscriber. · `\"unsubscribe\"` — don't message. Triggered by a TCPA litigator match, a non-mobile / non-SMS-capable carrier, an internal blacklist hit, or a carrier deactivation in the last 45 days. Check `reason` for the specific cause and `blackList` / `deactivationDate` for the extras. · `\"error\"` — the request was malformed (missing or invalid `phone`). Retrying produces the same error. |\n| `deliverable` | Composite reachability summary covering line type, blacklist, litigator filter, and 45-day deactivation checks. Always agrees with `action` — `\"true\"` when `action` is `\"send\"`, `\"false\"` when `action` is `\"unsubscribe\"`. Not a real-time delivery probe; carriers do not guarantee actual delivery. |\n| `error` | `\"true\"` if an error occurred while processing this lookup. Inspect `reason` for details. |\n| `reason` | Human-readable explanation for the `action`. The exact strings we return: `\"Associated with TCPA Litigator DO NOT CONTACT\"` · `\"Not a valid mobile number\"` · `\"Blacklisted Subscriber\"` · `\"Number deactivated by carrier id <N> on <date>\"` |\n| `deactivationDate` | Date of the most recent deactivation for this number, when known. Our deactivation data refreshes daily; expect a 1–7 day lag between an actual carrier deactivation and the value appearing here. Entries expire after 45 days, and the field clears as soon as the number is reactivated. Not a reassignment signal: a reactivated number shows no `deactivationDate` whether it went back to the same subscriber or a new one. |\n| `blackList` | `\"true\"` when the number is on our internal blacklist of flagged numbers OR when the litigator filter matched (litigator hits force this flag). Inspect `reason` and `litigator` to disambiguate which check triggered it. Distinct from the do-not-call checks — those are the `dnc*` fields returned by the free `dncState` and `dncComplainer` checks. |\n| `smsEligible` | Present as `\"true\"` when the number is eligible to receive SMS — an active mobile, or a landline confirmed SMS-capable when `landlineSmsLookup: true` is set. Omitted entirely when not eligible. The inverse of `doNotSms`. |\n| `doNotSms` | Present as `\"true\"` when the number is NOT eligible to receive SMS — either undeliverable (not a mobile, deactivated, or blacklisted) or a known TCPA litigator. Omitted entirely otherwise. The inverse of `smsEligible`. |\n\n### NANP\n\nLine type and carrier from the North American Numbering Plan records, the number's original assignment.\n\n| Field | Description |\n| --- | --- |\n| `nanpType` | Line type per the North American Numbering Plan. Values: `\"mobile\"`, `\"landline\"`, `\"not-mobile\"`. |\n| `nanpCarrier` | Carrier name per NANP. Not authoritative due to number porting — prefer `dipCarrier` when available. |\n\n### Carrier DIP\n\nThe live carrier dip: current carrier, line type, and whether the number was ported.\n\n| Field | Description |\n| --- | --- |\n| `dip` | Status of the live carrier dip lookup. One of `\"success\"`, `\"error\"`, `\"invalid\"`. |\n| `dipLrn` | Local Routing Number — the number used for actual call/SMS routing. Critical for ported numbers. |\n| `dipPorted` | `\"true\"` when `dipLrn` differs from `subscriber` — the standard industry method for detecting that a number has been ported (transferred) to a different carrier than originally assigned. |\n| `dipOcn` | Operating Carrier Numeric ID — unique identifier code for the current carrier operating this number. |\n| `dipCarrier` | Authoritative carrier name from DIP lookup. |\n| `dipCarrierType` | Broad carrier type. One of `\"mobile\"`, `\"landline\"`, `\"invalid\"`, `\"undefined\"`. |\n| `dipCarrierSubType` | Carrier sub-type, as the carrier records classify the company that serves the number. Values: `WIRELESS` Wireless (mobile carrier) · `PCS` Personal Communications Service (mobile) · `PCSR` Personal Communications Service Reseller · `WRSL` Wireless Reseller (MVNO) · `PAGING` Paging and Messaging · `ILEC` Incumbent Local Exchange Carrier (landline) · `CLEC` Competitive Local Exchange Carrier (landline) · `ULEC` Unbundled Local Exchange Carrier · `RBOC` Regional Bell Operating Company · `ICO` Independent Telephone Company · `CAP` Competitive Access Provider · `IXC` Inter-exchange Carrier · `LRSL` Local Reseller · `IPES` Internet Protocol Enabled Services (VoIP) · `ETHX` Ethernet Exchange · `INTL` International Telecommunications Service Provider · `GENERAL` Unclassified The literal string `\"undefined\"` sometimes appears as noise in the carrier records; it is not a classification. |\n\n### IP & Geolocation\n\nLocation and time zone. From the area code by default; more exact when you send `ip`.\n\n| Field | Description |\n| --- | --- |\n| `ipResult` | Validation result for the IP address provided with the request. Examples: `\"valid-v4\"`, `\"valid-v6\"`. Only populated when an `ip` parameter is included. |\n| `geoCountry` | Two-letter country code where the number is registered. |\n| `geoState` | Two-letter US state code. |\n| `geoCity` | City associated with the phone number, derived from the area code or the provided IP address. |\n| `geoMetro` (number) | Metro area code (DMA code) for the geographic region of the phone number. |\n| `geoSource` | Source of the geographic data. `\"ip\"` when derived from a provided IP address, `\"area-code\"` when derived from the phone number itself. |\n| `timezone` | IANA timezone identifier for the phone number's location. |\n| `tzOffset` (number) | UTC offset in hours for the phone number's timezone. |\n\n### Litigator Filter\n\nOnly with `litigatorFilter` (+1 credit).\n\n| Field | Description |\n| --- | --- |\n| `litigator` | `\"true\"` if the subscriber is a suspected TCPA litigator. Do not contact. Returned when `litigatorFilter: true` is set on the request. |\n| `litigator_type` | Litigator classification. One of `\"litigator\"`, `\"plaintiff\"`, `\"agitator\"`. All three carry the same recommended action (`\"unsubscribe\"`) — the value is informational about how the match was classified in our source data; treat the action identically across all three. |\n| `litigator_name` | Name on record for the matched litigator. Present when a likely name is on record; not all matches have a name. Treat as potentially sensitive — handle carefully and do not log unnecessarily. |\n\n### Landline SMS Lookup\n\nOnly with `landlineSmsLookup` (+1 credit, charged for landlines only). Left out of the response otherwise.\n\n| Field | Description |\n| --- | --- |\n| `dipMessagingLookup` | Present only when `landlineSmsLookup: true` is set and the lookup actually ran, i.e. the number is a landline: `\"true\"`. Absent for mobile numbers (the lookup does not apply and is not charged) and when the add-on is not requested. |\n| `dipMessagingEnabled` | Returned only when `landlineSmsLookup: true` is set. `\"true\"` if landline messaging is enabled for this number. Only meaningful alongside `dipMessagingLookup: \"true\"`. |\n| `dipMessagingProvider` | Name of the messaging provider serving this landline number. Populated only when the landline messaging lookup returned a positive match. |\n| `dipMessagingRefId` | Messaging provider's reference ID for this number. |\n| `dipMessagingCountryCode` | Two-letter country code of the messaging provider. |\n\n### State DNC & Complainers\n\nOnly with `dncState` and `dncComplainer` (free). A missing `*Checked` field means the check did not run, not that the number is clear.\n\n| Field | Description |\n| --- | --- |\n| `dncStateChecked` | Present only when the state DNC check ran: `\"true\"`, or `\"error\"` if it could not be completed (treat the state result as unavailable, never as clear). Absent when `dncState` was not requested, and for numbers in the 12 states the state check does not cover: Colorado, Florida, Indiana, Louisiana, Massachusetts, Mississippi, Missouri, Oklahoma, Pennsylvania, Tennessee, Texas and Wyoming. Absent always means \"not checked\", never \"clear\". |\n| `dncStateResult` | `\"STATE DNC\"` when the state do-not-call check matches the number; an empty string when it does not. Present only when `dncStateChecked` is `\"true\"`. The state check covers 38 states plus DC, refreshed weekly. |\n| `dncComplainerChecked` | Present only when the complainer check ran: `\"true\"`, or `\"error\"` if it could not be completed (treat the result as unavailable, never as clear). Absent only when `dncComplainer` was not requested. |\n| `dncComplainerResult` | `\"DNC COMPLAINER\"` when the number is on our national complainer list; an empty string when it is not. Present only when `dncComplainerChecked` is `\"true\"`. The list holds roughly 700,000 numbers belonging to people who have lodged complaints against telemarketers but have not sent a demand letter or filed suit. Informational: a match never changes `action`. |\n| `dncOtherChecked` (deprecated) | Legacy. `\"true\"` when either DNC check ran, `\"error\"` if it failed; absent when neither ran. Use `dncStateChecked` and `dncComplainerChecked`, which report each check separately. |\n| `dncStateCovered` (deprecated) | Deprecated: use `dncStateChecked`. Returned whenever the state check is requested: `\"true\"` when `dncStateChecked` is `\"true\"`, `\"false\"` otherwise. Kept so existing integrations keep working. |"
    },
    {
      "name": "Credits and add-ons",
      "description": "A lookup costs one credit. Each paid add-on adds one credit. The two DNC checks are free. Failed requests (any 4xx or 5xx response) never use credits.\n\n| Request flag | What it adds to `data` | Cost |\n| --- | --- | --- |\n| none | carrier and line type (live carrier dip), ported or not, recent deactivation, deliverability (send or unsubscribe, with the reason), location and time zone | 1 credit |\n| `litigatorFilter` | TCPA litigator check: `litigator`, `litigator_type`, `litigator_name` | +1 credit |\n| `landlineSmsLookup` | Can this landline receive SMS: the `dipMessaging*` fields | +1 credit, only for landlines |\n| `dncState` | State do-not-call check: `dncStateChecked`, `dncStateResult` | free |\n| `dncComplainer` | National complainer list check: `dncComplainerChecked`, `dncComplainerResult` | free |\n\n`credits_used` in the response and the `X-Credits-Used` header both show the exact number of credits used.\n\nThe state check covers 38 states and DC. Numbers in the other 12 states (Colorado, Florida, Indiana, Louisiana, Massachusetts, Mississippi, Missouri, Oklahoma, Pennsylvania, Tennessee, Texas and Wyoming) are not checked, and the response has no `dncStateChecked` field. A missing `*Checked` field means \"not checked\", not \"clear\". The DNC checks do not look at the federal Do Not Call registry, and they do not change `action`."
    },
    {
      "name": "Official SDKs",
      "description": "Official clients for Node.js and Python. They have no dependencies and cover the full API, including every add-on. Both are open source (MIT) on [GitHub](https://github.com/CheckThatPhone).\n\n- **Node.js**: `npm install checkthatphone` ([checkthatphone-node](https://github.com/CheckThatPhone/checkthatphone-node)). Node 18 or newer. TypeScript types included.\n- **Python**: `pip install checkthatphone` ([checkthatphone-python](https://github.com/CheckThatPhone/checkthatphone-python)). Python 3.9 or newer. Standard library only.\n\nThe code samples on the endpoint above include both SDKs."
    },
    {
      "name": "Errors and retries",
      "description": "The API uses standard HTTP status codes. An error response looks like `{ \"error\": \"...\", \"detail\": \"...\" }`. Each status is listed on the endpoint above. In short:\n\n- `400`: the request is wrong, for example a bad phone number. Fix it before you retry. The same request will fail again.\n- `401`: the API key is missing or wrong.\n- `402`: requests are paused. Either your account reached its safety limit for this billing period (contact us and we will raise it), or your last invoice is unpaid (pay it on the billing page and requests start again by themselves).\n- `429`: you sent requests too fast, or a Free account used its 500 credits for the month. Slow down, or upgrade. There is no fixed published rate limit. Each account's limit grows with its billing history.\n- `502` and `503`: a temporary problem on our side. Wait a moment and retry. On a 503, wait the number of seconds given in the `Retry-After` header."
    },
    {
      "name": "Bulk lists",
      "description": "Have a large list? Upload a CSV in your dashboard instead of writing code. Up to 1,000,000 rows per file, the same fields for every row, and the same price per number as this API. See [Features: two ways to call](https://checkthatphone.com/features#bulk)."
    },
    {
      "name": "Markdown and OpenAPI",
      "description": "This reference is also available as [Markdown](https://checkthatphone.com/docs.md) for AI agents and as an [OpenAPI 3.1 file](https://checkthatphone.com/.well-known/openapi.json) for code generators."
    }
  ],
  "paths": {
    "/lookup": {
      "post": {
        "operationId": "validatePhoneNumber",
        "tags": [
          "Lookup"
        ],
        "summary": "Validate a US or Canada phone number",
        "description": "Returns the carrier and line type from a live carrier dip, whether the number was ported, whether it was deactivated recently, deliverability (a send or unsubscribe recommendation with the reason), and the location and time zone for a US or Canada number. Add the IP address of the person who gave you the number for a more exact location. Add-on flags run a TCPA litigator check, a landline SMS check, and free state do-not-call and complainer checks.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LookupRequest"
              },
              "examples": {
                "phoneOnly": {
                  "summary": "Phone number only",
                  "value": {
                    "phone": "8182925409"
                  }
                },
                "withIp": {
                  "summary": "Phone number and IP address",
                  "value": {
                    "phone": "8182925409",
                    "ip": "136.38.145.14"
                  }
                },
                "addOns": {
                  "summary": "All add-ons",
                  "value": {
                    "phone": "8182925409",
                    "ip": "136.38.145.14",
                    "litigatorFilter": true,
                    "landlineSmsLookup": true,
                    "dncState": true,
                    "dncComplainer": true
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "javascript",
            "label": "Node SDK",
            "source": "// npm install checkthatphone\nimport CheckThatPhone from 'checkthatphone';\n\nconst client = new CheckThatPhone(process.env.CHECKTHATPHONE_API_KEY);\n\nconst result = await client.lookup('8182925409');\nconsole.log(result.data.nanpType);    // \"mobile\"\nconsole.log(result.data.dipCarrier);  // \"AT&T\"\nconsole.log(result.creditsUsed);      // 1"
          },
          {
            "lang": "python",
            "label": "Python SDK",
            "source": "# pip install checkthatphone\nimport os\nfrom checkthatphone import CheckThatPhone\n\nclient = CheckThatPhone(api_key=os.environ[\"CHECKTHATPHONE_API_KEY\"])\n\nresult = client.lookup(\"8182925409\")\nprint(result.data[\"nanpType\"])    # \"mobile\"\nprint(result.data[\"dipCarrier\"])  # \"AT&T\"\nprint(result.credits_used)        # 1"
          }
        ],
        "responses": {
          "200": {
            "description": "Phone validation result",
            "headers": {
              "X-Credits-Used": {
                "description": "Credits this call consumed.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LookupResponse"
                },
                "examples": {
                  "phoneOnly": {
                    "summary": "Phone number only",
                    "value": {
                      "success": true,
                      "credits_used": 1,
                      "data": {
                        "subscriber": "8182925409",
                        "optDate": "2026-05-21T18:55:56.532Z",
                        "action": "send",
                        "deliverable": "true",
                        "blackList": "false",
                        "nanpType": "mobile",
                        "nanpCarrier": "verizon",
                        "dip": "success",
                        "dipLrn": "8182925409",
                        "dipPorted": "false",
                        "dipOcn": "6010",
                        "dipCarrier": "AT&T",
                        "dipCarrierType": "mobile",
                        "dipCarrierSubType": "WIRELESS",
                        "geoCountry": "US",
                        "geoState": "CA",
                        "geoCity": "Riverside",
                        "geoMetro": 803,
                        "geoSource": "area-code",
                        "timezone": "America/Los_Angeles",
                        "tzOffset": 8,
                        "smsEligible": "true"
                      }
                    }
                  },
                  "withIp": {
                    "summary": "Phone number and IP address",
                    "value": {
                      "success": true,
                      "credits_used": 1,
                      "data": {
                        "subscriber": "8182925409",
                        "optDate": "2026-05-21T18:55:56.532Z",
                        "action": "send",
                        "deliverable": "true",
                        "blackList": "false",
                        "nanpType": "mobile",
                        "nanpCarrier": "verizon",
                        "dip": "success",
                        "dipLrn": "8182925409",
                        "dipPorted": "false",
                        "dipOcn": "6010",
                        "dipCarrier": "AT&T",
                        "dipCarrierType": "mobile",
                        "dipCarrierSubType": "WIRELESS",
                        "ipResult": "valid-v4",
                        "geoCountry": "US",
                        "geoState": "CA",
                        "geoCity": "Riverside",
                        "geoMetro": 803,
                        "geoSource": "ip",
                        "timezone": "America/Los_Angeles",
                        "tzOffset": 8,
                        "smsEligible": "true"
                      }
                    }
                  },
                  "addOns": {
                    "summary": "All add-ons",
                    "value": {
                      "success": true,
                      "credits_used": 2,
                      "data": {
                        "subscriber": "8182925409",
                        "optDate": "2026-05-21T18:55:56.532Z",
                        "action": "send",
                        "deliverable": "true",
                        "blackList": "false",
                        "nanpType": "mobile",
                        "nanpCarrier": "verizon",
                        "dip": "success",
                        "dipLrn": "8182925409",
                        "dipPorted": "false",
                        "dipOcn": "6010",
                        "dipCarrier": "AT&T",
                        "dipCarrierType": "mobile",
                        "dipCarrierSubType": "WIRELESS",
                        "ipResult": "valid-v4",
                        "geoCountry": "US",
                        "geoState": "CA",
                        "geoCity": "Riverside",
                        "geoMetro": 803,
                        "geoSource": "ip",
                        "timezone": "America/Los_Angeles",
                        "tzOffset": 8,
                        "smsEligible": "true",
                        "litigator": "false",
                        "litigator_type": "",
                        "litigator_name": "",
                        "dncStateChecked": "true",
                        "dncStateResult": "",
                        "dncStateCovered": "true",
                        "dncComplainerChecked": "true",
                        "dncComplainerResult": ""
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is wrong: the phone number is missing or not valid (it must be 10 digits, or 11 starting with 1), or the body is not valid JSON. No credit is charged. The same request will fail again, so fix it before you retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or wrong.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Requests are paused. Either the account reached its safety limit for this billing period (a protective cap on paid plans; contact support and we will raise it, and requests start again when the limit rises or the next period starts), or the latest invoice is unpaid (pay it on the billing page and requests start again by themselves). No credit is charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: the rate limit was exceeded, or a Free account used its monthly credits (quota). Slow down and retry, or upgrade the plan. No credit is charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Our validation network returned an error. No credit is charged. Safe to retry. Contact support if it keeps happening.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "The service is busy for a moment. Wait the number of seconds in the Retry-After header, then retry. No credit is charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your API key from the CheckThatPhone dashboard."
      }
    },
    "schemas": {
      "LookupRequest": {
        "type": "object",
        "required": [
          "phone"
        ],
        "properties": {
          "phone": {
            "type": "string",
            "pattern": "^\\D*(\\d\\D*){10,11}$",
            "example": "8182925409",
            "description": "US or Canada phone number: 10 digits, or 11 digits starting with 1. Spaces and punctuation are ignored."
          },
          "ip": {
            "type": "string",
            "example": "136.38.145.14",
            "description": "The IP address (IPv4 or IPv6) of the person who gave you the number, for example from your signup or lead form. With it, the location comes from the IP address, which is more exact than the area code."
          },
          "litigatorFilter": {
            "type": "boolean",
            "default": false,
            "description": "Check the number against our TCPA litigator database (+1 credit). Adds litigator, litigator_type and litigator_name to the response."
          },
          "landlineSmsLookup": {
            "type": "boolean",
            "default": false,
            "description": "Check whether a landline can receive SMS (+1 credit), charged only when the number is a landline. Adds the dipMessaging* fields. Mobile numbers are not affected."
          },
          "dncState": {
            "type": "boolean",
            "default": false,
            "description": "Run the state do-not-call check (free). Adds dncStateChecked and dncStateResult. Covers 38 states and DC. Numbers in the other 12 states are not checked, and dncStateChecked is then missing, which means \"not checked\", not \"clear\"."
          },
          "dncComplainer": {
            "type": "boolean",
            "default": false,
            "description": "Check the number against our national complainer list (free). Adds dncComplainerChecked and dncComplainerResult."
          },
          "dncOther": {
            "type": "boolean",
            "default": false,
            "deprecated": true,
            "description": "Deprecated. Use dncState and dncComplainer instead. Turns on both checks. Responses to requests that send it include a Deprecation header."
          }
        }
      },
      "LookupResponse": {
        "type": "object",
        "required": [
          "success",
          "credits_used",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "description": "True if the lookup completed."
          },
          "credits_used": {
            "type": "integer",
            "description": "Credits this call consumed (1 base, plus 1 per enabled paid add-on; the DNC checks are free). Also returned in the X-Credits-Used response header."
          },
          "data": {
            "$ref": "#/components/schemas/LookupData"
          }
        }
      },
      "LookupData": {
        "type": "object",
        "description": "Validation result. Add-on fields appear only when their request flag is set, and smsEligible / doNotSms are omitted entirely when they do not apply.",
        "properties": {
          "subscriber": {
            "type": "string",
            "description": "The phone number that was queried.",
            "example": "8182925409"
          },
          "optDate": {
            "type": "string",
            "description": "ISO 8601 timestamp of when the query was processed.",
            "format": "date-time",
            "example": "2026-05-21T18:55:56.532Z"
          },
          "action": {
            "type": "string",
            "description": "Recommended SMS list action. Returns one of:\n\n- `\"send\"` — the number passed the enabled technical and screening checks. This does not establish consent or legal authorization to contact the subscriber.\n- `\"unsubscribe\"` — don't message. Triggered by a TCPA litigator match, a non-mobile / non-SMS-capable carrier, an internal blacklist hit, or a carrier deactivation in the last 45 days. Check `reason` for the specific cause and `blackList` / `deactivationDate` for the extras.\n- `\"error\"` — the request was malformed (missing or invalid `phone`). Retrying produces the same error.",
            "enum": [
              "send",
              "unsubscribe",
              "error"
            ],
            "example": "send"
          },
          "deliverable": {
            "type": "string",
            "description": "Composite reachability summary covering line type, blacklist, litigator filter, and 45-day deactivation checks. Always agrees with `action` — `\"true\"` when `action` is `\"send\"`, `\"false\"` when `action` is `\"unsubscribe\"`. Not a real-time delivery probe; carriers do not guarantee actual delivery.",
            "enum": [
              "true",
              "false"
            ],
            "example": "true"
          },
          "error": {
            "type": "string",
            "description": "`\"true\"` if an error occurred while processing this lookup. Inspect `reason` for details.",
            "enum": [
              "true",
              "false"
            ],
            "example": "false"
          },
          "reason": {
            "type": "string",
            "description": "Human-readable explanation for the `action`. The exact strings we return:\n\n- `\"Associated with TCPA Litigator DO NOT CONTACT\"`\n- `\"Not a valid mobile number\"`\n- `\"Blacklisted Subscriber\"`\n- `\"Number deactivated by carrier id <N> on <date>\"`",
            "example": "Number deactivated by carrier id 6529 on 2025-12-04"
          },
          "deactivationDate": {
            "type": "string",
            "description": "Date of the most recent deactivation for this number, when known. Our deactivation data refreshes daily; expect a 1–7 day lag between an actual carrier deactivation and the value appearing here. Entries expire after 45 days, and the field clears as soon as the number is reactivated. Not a reassignment signal: a reactivated number shows no `deactivationDate` whether it went back to the same subscriber or a new one.",
            "example": "2019-06-01"
          },
          "blackList": {
            "type": "string",
            "description": "`\"true\"` when the number is on our internal blacklist of flagged numbers OR when the litigator filter matched (litigator hits force this flag). Inspect `reason` and `litigator` to disambiguate which check triggered it. Distinct from the do-not-call checks — those are the `dnc*` fields returned by the free `dncState` and `dncComplainer` checks.",
            "enum": [
              "true",
              "false"
            ],
            "example": "false"
          },
          "smsEligible": {
            "type": "string",
            "description": "Present as `\"true\"` when the number is eligible to receive SMS — an active mobile, or a landline confirmed SMS-capable when `landlineSmsLookup: true` is set. Omitted entirely when not eligible. The inverse of `doNotSms`.",
            "enum": [
              "true"
            ],
            "example": "true"
          },
          "doNotSms": {
            "type": "string",
            "description": "Present as `\"true\"` when the number is NOT eligible to receive SMS — either undeliverable (not a mobile, deactivated, or blacklisted) or a known TCPA litigator. Omitted entirely otherwise. The inverse of `smsEligible`.",
            "enum": [
              "true"
            ],
            "example": "true"
          },
          "nanpType": {
            "type": "string",
            "description": "Line type per the North American Numbering Plan. Values: `\"mobile\"`, `\"landline\"`, `\"not-mobile\"`.",
            "enum": [
              "mobile",
              "landline",
              "not-mobile"
            ],
            "example": "mobile"
          },
          "nanpCarrier": {
            "type": "string",
            "description": "Carrier name per NANP. Not authoritative due to number porting — prefer `dipCarrier` when available.",
            "example": "verizon"
          },
          "dip": {
            "type": "string",
            "description": "Status of the live carrier dip lookup. One of `\"success\"`, `\"error\"`, `\"invalid\"`.",
            "enum": [
              "success",
              "error",
              "invalid"
            ],
            "example": "success"
          },
          "dipLrn": {
            "type": "string",
            "description": "Local Routing Number — the number used for actual call/SMS routing. Critical for ported numbers.",
            "example": "8182925409"
          },
          "dipPorted": {
            "type": "string",
            "description": "`\"true\"` when `dipLrn` differs from `subscriber` — the standard industry method for detecting that a number has been ported (transferred) to a different carrier than originally assigned.",
            "enum": [
              "true",
              "false"
            ],
            "example": "false"
          },
          "dipOcn": {
            "type": "string",
            "description": "Operating Carrier Numeric ID — unique identifier code for the current carrier operating this number.",
            "example": "6010"
          },
          "dipCarrier": {
            "type": "string",
            "description": "Authoritative carrier name from DIP lookup.",
            "example": "AT&T"
          },
          "dipCarrierType": {
            "type": "string",
            "description": "Broad carrier type. One of `\"mobile\"`, `\"landline\"`, `\"invalid\"`, `\"undefined\"`.",
            "enum": [
              "mobile",
              "landline",
              "invalid",
              "undefined"
            ],
            "example": "mobile"
          },
          "dipCarrierSubType": {
            "type": "string",
            "description": "Carrier sub-type, as the carrier records classify the company that serves the number. Values:\n\n- `WIRELESS` Wireless (mobile carrier)\n- `PCS` Personal Communications Service (mobile)\n- `PCSR` Personal Communications Service Reseller\n- `WRSL` Wireless Reseller (MVNO)\n- `PAGING` Paging and Messaging\n- `ILEC` Incumbent Local Exchange Carrier (landline)\n- `CLEC` Competitive Local Exchange Carrier (landline)\n- `ULEC` Unbundled Local Exchange Carrier\n- `RBOC` Regional Bell Operating Company\n- `ICO` Independent Telephone Company\n- `CAP` Competitive Access Provider\n- `IXC` Inter-exchange Carrier\n- `LRSL` Local Reseller\n- `IPES` Internet Protocol Enabled Services (VoIP)\n- `ETHX` Ethernet Exchange\n- `INTL` International Telecommunications Service Provider\n- `GENERAL` Unclassified\n\nThe literal string `\"undefined\"` sometimes appears as noise in the carrier records; it is not a classification.",
            "enum": [
              "WIRELESS",
              "PCS",
              "PCSR",
              "WRSL",
              "PAGING",
              "ILEC",
              "CLEC",
              "ULEC",
              "RBOC",
              "ICO",
              "CAP",
              "IXC",
              "LRSL",
              "IPES",
              "ETHX",
              "INTL",
              "GENERAL",
              "undefined"
            ],
            "example": "WIRELESS"
          },
          "dipMessagingLookup": {
            "type": "string",
            "description": "Present only when `landlineSmsLookup: true` is set and the lookup actually ran, i.e. the number is a landline: `\"true\"`. Absent for mobile numbers (the lookup does not apply and is not charged) and when the add-on is not requested.",
            "enum": [
              "true",
              "false"
            ],
            "example": "true"
          },
          "dipMessagingEnabled": {
            "type": "string",
            "description": "Returned only when `landlineSmsLookup: true` is set. `\"true\"` if landline messaging is enabled for this number. Only meaningful alongside `dipMessagingLookup: \"true\"`.",
            "enum": [
              "true",
              "false"
            ],
            "example": "false"
          },
          "dipMessagingProvider": {
            "type": "string",
            "description": "Name of the messaging provider serving this landline number. Populated only when the landline messaging lookup returned a positive match.",
            "example": "Google (Grand Central) - SVR"
          },
          "dipMessagingRefId": {
            "type": "string",
            "description": "Messaging provider's reference ID for this number.",
            "example": "us_acme"
          },
          "dipMessagingCountryCode": {
            "type": "string",
            "description": "Two-letter country code of the messaging provider.",
            "example": "US"
          },
          "litigator": {
            "type": "string",
            "description": "`\"true\"` if the subscriber is a suspected TCPA litigator. Do not contact. Returned when `litigatorFilter: true` is set on the request.",
            "enum": [
              "true",
              "false"
            ],
            "example": "false"
          },
          "litigator_type": {
            "type": "string",
            "description": "Litigator classification. One of `\"litigator\"`, `\"plaintiff\"`, `\"agitator\"`. All three carry the same recommended action (`\"unsubscribe\"`) — the value is informational about how the match was classified in our source data; treat the action identically across all three.",
            "enum": [
              "litigator",
              "plaintiff",
              "agitator",
              ""
            ],
            "example": "plaintiff"
          },
          "litigator_name": {
            "type": "string",
            "description": "Name on record for the matched litigator. Present when a likely name is on record; not all matches have a name. Treat as potentially sensitive — handle carefully and do not log unnecessarily.",
            "example": "John Smith"
          },
          "dncStateChecked": {
            "type": "string",
            "description": "Present only when the state DNC check ran: `\"true\"`, or `\"error\"` if it could not be completed (treat the state result as unavailable, never as clear). Absent when `dncState` was not requested, and for numbers in the 12 states the state check does not cover: Colorado, Florida, Indiana, Louisiana, Massachusetts, Mississippi, Missouri, Oklahoma, Pennsylvania, Tennessee, Texas and Wyoming. Absent always means \"not checked\", never \"clear\".",
            "enum": [
              "true",
              "error"
            ],
            "example": "true"
          },
          "dncStateResult": {
            "type": "string",
            "description": "`\"STATE DNC\"` when the state do-not-call check matches the number; an empty string when it does not. Present only when `dncStateChecked` is `\"true\"`. The state check covers 38 states plus DC, refreshed weekly.",
            "enum": [
              "STATE DNC",
              ""
            ],
            "example": "STATE DNC"
          },
          "dncComplainerChecked": {
            "type": "string",
            "description": "Present only when the complainer check ran: `\"true\"`, or `\"error\"` if it could not be completed (treat the result as unavailable, never as clear). Absent only when `dncComplainer` was not requested.",
            "enum": [
              "true",
              "error"
            ],
            "example": "true"
          },
          "dncComplainerResult": {
            "type": "string",
            "description": "`\"DNC COMPLAINER\"` when the number is on our national complainer list; an empty string when it is not. Present only when `dncComplainerChecked` is `\"true\"`. The list holds roughly 700,000 numbers belonging to people who have lodged complaints against telemarketers but have not sent a demand letter or filed suit. Informational: a match never changes `action`.",
            "enum": [
              "DNC COMPLAINER",
              ""
            ],
            "example": ""
          },
          "dncOtherChecked": {
            "type": "string",
            "description": "Legacy. `\"true\"` when either DNC check ran, `\"error\"` if it failed; absent when neither ran. Use `dncStateChecked` and `dncComplainerChecked`, which report each check separately.",
            "enum": [
              "true",
              "error"
            ],
            "deprecated": true,
            "example": "true"
          },
          "dncStateCovered": {
            "type": "string",
            "description": "Deprecated: use `dncStateChecked`. Returned whenever the state check is requested: `\"true\"` when `dncStateChecked` is `\"true\"`, `\"false\"` otherwise. Kept so existing integrations keep working.",
            "enum": [
              "true",
              "false"
            ],
            "deprecated": true,
            "example": "true"
          },
          "ipResult": {
            "type": "string",
            "description": "Validation result for the IP address provided with the request. Examples: `\"valid-v4\"`, `\"valid-v6\"`. Only populated when an `ip` parameter is included.",
            "example": "valid-v4"
          },
          "geoCountry": {
            "type": "string",
            "description": "Two-letter country code where the number is registered.",
            "example": "US"
          },
          "geoState": {
            "type": "string",
            "description": "Two-letter US state code.",
            "example": "CA"
          },
          "geoCity": {
            "type": "string",
            "description": "City associated with the phone number, derived from the area code or the provided IP address.",
            "example": "Riverside"
          },
          "geoMetro": {
            "type": "number",
            "description": "Metro area code (DMA code) for the geographic region of the phone number.",
            "example": 803
          },
          "geoSource": {
            "type": "string",
            "description": "Source of the geographic data. `\"ip\"` when derived from a provided IP address, `\"area-code\"` when derived from the phone number itself.",
            "enum": [
              "ip",
              "area-code"
            ],
            "example": "ip"
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone identifier for the phone number's location.",
            "example": "America/Los_Angeles"
          },
          "tzOffset": {
            "type": "number",
            "description": "UTC offset in hours for the phone number's timezone.",
            "example": 8
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Short error label.",
            "example": "Bad Request"
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation of what went wrong."
          }
        }
      }
    }
  }
}
