From 816db6a9efe1e316985590237dfbcdf9a8d75305 Mon Sep 17 00:00:00 2001 From: Taylor Richards Date: Tue, 16 Jun 2026 19:27:11 -0400 Subject: [PATCH] feat(mcp): add doc facet frontmatter scheme and versioning IA Add lifecycle/topic/keywords facets to the docs source schema so the build-time MCP corpus generator can read them off page data without scraping MDX. Apply facets to authored person, property, and operational reference pages. The auto-generated OpenAPI reference pages get facets injected during generation via a per-path map, so hand-edits are never needed. Extract Versioning & Breaking Changes from the Support page into its own references group, and surface trial exhaustion (Limit Exceeded) in rate limits with clearer wording and search keywords. --- .../person-search/confidence-scores.mdx | 7 ++ .../person-search/filter-by-age-range.mdx | 6 + .../person-search/fuzzy-matching.mdx | 7 ++ .../documentation/person-search/index.mdx | 7 ++ .../person-search/pagination.mdx | 7 ++ .../person-search/partial-name-search.mdx | 6 + .../person-search/reverse-phone-lookup.mdx | 7 ++ .../person-search/search-by-address.mdx | 7 ++ .../person-search/search-by-radius.mdx | 7 ++ .../docs/documentation/property-search.mdx | 8 ++ .../account/get_account_usage_data.mdx | 8 ++ content/docs/references/authentication.mdx | 7 ++ .../billing-prior-to-2026-06-01.mdx | 6 + content/docs/references/billing.mdx | 7 ++ content/docs/references/events/get_event.mdx | 5 + .../docs/references/events/search_events.mdx | 5 + content/docs/references/meta.json | 1 + .../person-v2/get_person_by_id_v2.mdx | 6 + ...rch_person_by_name_phone_or_address_v2.mdx | 10 ++ .../property-v2/get_property_by_id_v2.mdx | 5 + .../property-v2/search_property_v2.mdx | 8 ++ content/docs/references/rate-limits.mdx | 24 +++- .../docs/references/regions/list_counties.mdx | 4 + .../docs/references/regions/list_states.mdx | 4 + .../support-and-incident-response.mdx | 100 ++------------- .../versioning/breaking-changes-policy.mdx | 79 ++++++++++++ .../versioning/change-notifications.mdx | 36 ++++++ content/docs/references/versioning/meta.json | 5 + .../references/webhooks/create_webhook.mdx | 6 + .../references/webhooks/delete_webhook.mdx | 5 + .../docs/references/webhooks/get_webhook.mdx | 5 + .../references/webhooks/list_webhooks.mdx | 5 + .../docs/references/webhooks/test_webhook.mdx | 5 + .../references/webhooks/update_webhook.mdx | 5 + .../generators/openapi/openapi.facets.test.ts | 101 +++++++++++++++ scripts/generators/openapi/openapi.facets.ts | 115 ++++++++++++++++++ .../generators/openapi/openapi.generator.ts | 18 ++- source.config.ts | 3 +- src/lib/facets.ts | 20 +++ 39 files changed, 577 insertions(+), 100 deletions(-) create mode 100644 content/docs/references/versioning/breaking-changes-policy.mdx create mode 100644 content/docs/references/versioning/change-notifications.mdx create mode 100644 content/docs/references/versioning/meta.json create mode 100644 scripts/generators/openapi/openapi.facets.test.ts create mode 100644 scripts/generators/openapi/openapi.facets.ts create mode 100644 src/lib/facets.ts diff --git a/content/docs/documentation/person-search/confidence-scores.mdx b/content/docs/documentation/person-search/confidence-scores.mdx index a676a6f..5ec1cd5 100644 --- a/content/docs/documentation/person-search/confidence-scores.mdx +++ b/content/docs/documentation/person-search/confidence-scores.mdx @@ -1,6 +1,13 @@ --- title: Confidence Scores description: How to interpret person, phone, and email confidence scores +lifecycle: current +topic: person +keywords: + - "confidence score" + - "match score" + - "how accurate is a result" + - "score interpretation" --- Person search responses include confidence scores on three levels: the person record itself, each phone number, and each email address. All scores range from **0 to 100** and represent relative confidence — a higher score means stronger evidence of association. diff --git a/content/docs/documentation/person-search/filter-by-age-range.mdx b/content/docs/documentation/person-search/filter-by-age-range.mdx index de0fd19..2cb2086 100644 --- a/content/docs/documentation/person-search/filter-by-age-range.mdx +++ b/content/docs/documentation/person-search/filter-by-age-range.mdx @@ -1,6 +1,12 @@ --- title: Filter by Age Range description: Narrow person search results using minimum and maximum age filters +lifecycle: current +topic: person +keywords: + - "filter by age" + - "age range" + - "min age max age" --- Use the `min_age` and `max_age` parameters to filter person search results by age range. This is useful when you need to find individuals within a specific age bracket. diff --git a/content/docs/documentation/person-search/fuzzy-matching.mdx b/content/docs/documentation/person-search/fuzzy-matching.mdx index bae60e7..2529651 100644 --- a/content/docs/documentation/person-search/fuzzy-matching.mdx +++ b/content/docs/documentation/person-search/fuzzy-matching.mdx @@ -1,6 +1,13 @@ --- title: Fuzzy Matching description: Broaden person search results with phonetic, nickname, and misspelling matching +lifecycle: current +topic: person +keywords: + - "fuzzy matching" + - "nickname matching" + - "misspelled name" + - "phonetic match" --- Use the `include_fuzzy_matching` parameter to enable fuzzy name matching. When enabled, the search runs additional phonetic, nickname, and common misspelling matching logic at the cost of additional latency. diff --git a/content/docs/documentation/person-search/index.mdx b/content/docs/documentation/person-search/index.mdx index 70d248d..25989e6 100644 --- a/content/docs/documentation/person-search/index.mdx +++ b/content/docs/documentation/person-search/index.mdx @@ -1,6 +1,13 @@ --- title: Person Search description: Look up individuals by name, phone, or address +lifecycle: current +topic: person +keywords: + - "person search" + - "people search" + - "find a person" + - "look up a person" --- The Person Search API finds matching records in the Whitepages dataset based on name, location, phone number, or address. Use it to verify identities, find contact information, or enrich customer data. diff --git a/content/docs/documentation/person-search/pagination.mdx b/content/docs/documentation/person-search/pagination.mdx index 46e6332..d61962f 100644 --- a/content/docs/documentation/person-search/pagination.mdx +++ b/content/docs/documentation/person-search/pagination.mdx @@ -1,6 +1,13 @@ --- title: Pagination description: Page through person search results using the page and page_size parameters +lifecycle: current +topic: person +keywords: + - "pagination" + - "page through results" + - "page size" + - "next page of results" --- Person search returns up to 15 results per request by default. Use the `page` and `page_size` parameters to retrieve additional results when a query matches more records than a single page can return. diff --git a/content/docs/documentation/person-search/partial-name-search.mdx b/content/docs/documentation/person-search/partial-name-search.mdx index 736e4cd..8022383 100644 --- a/content/docs/documentation/person-search/partial-name-search.mdx +++ b/content/docs/documentation/person-search/partial-name-search.mdx @@ -1,6 +1,12 @@ --- title: Search for Person by Partial Name description: Search for people using partial or incomplete name information +lifecycle: current +topic: person +keywords: + - "partial name search" + - "incomplete name" + - "first name last name search" --- When you only have partial name information, use the individual name parameters (`first_name`, `middle_name`, `last_name`) to search more precisely than using the combined `name` parameter. diff --git a/content/docs/documentation/person-search/reverse-phone-lookup.mdx b/content/docs/documentation/person-search/reverse-phone-lookup.mdx index c69e917..b3bd392 100644 --- a/content/docs/documentation/person-search/reverse-phone-lookup.mdx +++ b/content/docs/documentation/person-search/reverse-phone-lookup.mdx @@ -1,6 +1,13 @@ --- title: Reverse Phone Lookup description: Find the owner of a phone number +lifecycle: current +topic: person +keywords: + - "reverse phone lookup" + - "phone search" + - "who owns this number" + - "find owner of a phone number" --- Use the `phone` parameter to perform a reverse phone lookup and identify who owns a phone number. This returns person records associated with the phone number, including their name, address, and other contact information. diff --git a/content/docs/documentation/person-search/search-by-address.mdx b/content/docs/documentation/person-search/search-by-address.mdx index 6ee52a7..60bf0f2 100644 --- a/content/docs/documentation/person-search/search-by-address.mdx +++ b/content/docs/documentation/person-search/search-by-address.mdx @@ -1,6 +1,13 @@ --- title: Search by Address description: Find people by current or historical addresses +lifecycle: current +topic: person +keywords: + - "search by address" + - "who lives at this address" + - "residents at an address" + - "historical addresses" --- Use address parameters to find people associated with a specific location. By default, searches match only current addresses. Enable `include_historical_locations` to also search historical addresses. diff --git a/content/docs/documentation/person-search/search-by-radius.mdx b/content/docs/documentation/person-search/search-by-radius.mdx index 25677fb..8bbd381 100644 --- a/content/docs/documentation/person-search/search-by-radius.mdx +++ b/content/docs/documentation/person-search/search-by-radius.mdx @@ -1,6 +1,13 @@ --- title: Search by Radius description: Find people within a specified distance of a location +lifecycle: current +topic: person +keywords: + - "search by radius" + - "people near a location" + - "proximity search" + - "distance search" --- Use the `radius` parameter to find people within a specific distance of a location. This enables proximity-based searches, such as finding all people within 10 miles of a given address or city. diff --git a/content/docs/documentation/property-search.mdx b/content/docs/documentation/property-search.mdx index e53ee44..870a6d7 100644 --- a/content/docs/documentation/property-search.mdx +++ b/content/docs/documentation/property-search.mdx @@ -2,6 +2,14 @@ title: Property Search description: Get ownership and resident data for any property icon: House +lifecycle: current +topic: property +keywords: + - "property search" + - "who owns this property" + - "property owner" + - "ownership data" + - "residents at a property" --- The Property Search API returns ownership and resident information for a given property. Use it to identify property owners, find current residents, or verify property details. diff --git a/content/docs/references/account/get_account_usage_data.mdx b/content/docs/references/account/get_account_usage_data.mdx index f4582d3..75f0603 100644 --- a/content/docs/references/account/get_account_usage_data.mdx +++ b/content/docs/references/account/get_account_usage_data.mdx @@ -1,4 +1,12 @@ --- +lifecycle: current +topic: account-billing +keywords: + - "account usage" + - "usage data" + - "remaining quota" + - "how many queries left" + - "query count" title: Retrieve usage data for a specific time range description: |- Retrieve API usage data for a specified date range. diff --git a/content/docs/references/authentication.mdx b/content/docs/references/authentication.mdx index 50d9d85..da38e99 100644 --- a/content/docs/references/authentication.mdx +++ b/content/docs/references/authentication.mdx @@ -2,6 +2,13 @@ title: Authentication description: Learn how to authenticate your requests to the Whitepages API. icon: KeyRound +lifecycle: current +topic: account-billing +keywords: + - "authentication" + - "api key" + - "x-api-key header" + - "how to authenticate" --- import { Callout } from "fumadocs-ui/components/callout"; diff --git a/content/docs/references/billing-prior-to-2026-06-01.mdx b/content/docs/references/billing-prior-to-2026-06-01.mdx index ec4c367..b0c7c11 100644 --- a/content/docs/references/billing-prior-to-2026-06-01.mdx +++ b/content/docs/references/billing-prior-to-2026-06-01.mdx @@ -1,6 +1,12 @@ --- title: Billing Policy For Usage Prior to 2026-06-01 description: Billing rules that applied to usage on or before May 31, 2026. +lifecycle: deprecated +topic: account-billing +keywords: + - "legacy billing" + - "old billing policy" + - "billing before 2026-06-01" --- import { Callout } from "fumadocs-ui/components/callout"; diff --git a/content/docs/references/billing.mdx b/content/docs/references/billing.mdx index e769765..6bdbbce 100644 --- a/content/docs/references/billing.mdx +++ b/content/docs/references/billing.mdx @@ -2,6 +2,13 @@ title: Billing description: Understand how API usage is tracked and billed. icon: CreditCard +lifecycle: current +topic: account-billing +keywords: + - "billing" + - "how am I billed" + - "usage tracking" + - "what counts as billable" --- import { Callout } from "fumadocs-ui/components/callout"; diff --git a/content/docs/references/events/get_event.mdx b/content/docs/references/events/get_event.mdx index 50a9ecc..184c513 100644 --- a/content/docs/references/events/get_event.mdx +++ b/content/docs/references/events/get_event.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: deed-events +keywords: + - "event by id" + - "event details" title: Retrieve a single event by ID description: Return a single event by its unique identifier. full: true diff --git a/content/docs/references/events/search_events.mdx b/content/docs/references/events/search_events.mdx index 04d8ccf..62a91da 100644 --- a/content/docs/references/events/search_events.mdx +++ b/content/docs/references/events/search_events.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: deed-events +keywords: + - "search events" + - "event query" title: Search all deed events description: |- Search historical deed events by region and optional filters. diff --git a/content/docs/references/meta.json b/content/docs/references/meta.json index df66d59..7de6dcc 100644 --- a/content/docs/references/meta.json +++ b/content/docs/references/meta.json @@ -9,6 +9,7 @@ "rate-limits", "billing", "support-and-incident-response", + "versioning", "person-v2", "webhooks", "events", diff --git a/content/docs/references/person-v2/get_person_by_id_v2.mdx b/content/docs/references/person-v2/get_person_by_id_v2.mdx index 12de61e..e02f7c6 100644 --- a/content/docs/references/person-v2/get_person_by_id_v2.mdx +++ b/content/docs/references/person-v2/get_person_by_id_v2.mdx @@ -1,4 +1,10 @@ --- +lifecycle: current +topic: person +keywords: + - "person by id" + - "person details" + - "hydrate person" title: Gets person details by id description: Retrieve detailed person information by Whitepages person ID. full: true diff --git a/content/docs/references/person-v2/search_person_by_name_phone_or_address_v2.mdx b/content/docs/references/person-v2/search_person_by_name_phone_or_address_v2.mdx index c5981c9..466fcc6 100644 --- a/content/docs/references/person-v2/search_person_by_name_phone_or_address_v2.mdx +++ b/content/docs/references/person-v2/search_person_by_name_phone_or_address_v2.mdx @@ -1,4 +1,14 @@ --- +lifecycle: current +topic: person +keywords: + - "reverse phone lookup" + - "phone search" + - "who lives at this address" + - "people search" + - "name lookup" + - "address lookup" + - "find a person" title: Search for a person by name, phone number, and address description: Retrieve person information with match scores and enriched emails. full: true diff --git a/content/docs/references/property-v2/get_property_by_id_v2.mdx b/content/docs/references/property-v2/get_property_by_id_v2.mdx index 9d975de..db45a2a 100644 --- a/content/docs/references/property-v2/get_property_by_id_v2.mdx +++ b/content/docs/references/property-v2/get_property_by_id_v2.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: property +keywords: + - "property by id" + - "property details" title: Get property details by ID description: |- Retrieve detailed property information by Whitepages property ID. diff --git a/content/docs/references/property-v2/search_property_v2.mdx b/content/docs/references/property-v2/search_property_v2.mdx index 1885897..4ad656f 100644 --- a/content/docs/references/property-v2/search_property_v2.mdx +++ b/content/docs/references/property-v2/search_property_v2.mdx @@ -1,4 +1,12 @@ --- +lifecycle: current +topic: property +keywords: + - "who owns this property" + - "property owner" + - "property search" + - "ownership info" + - "residents at an address" title: Search for property by address description: |- Search for property by address parameters. diff --git a/content/docs/references/rate-limits.mdx b/content/docs/references/rate-limits.mdx index fd17301..d956b89 100644 --- a/content/docs/references/rate-limits.mdx +++ b/content/docs/references/rate-limits.mdx @@ -1,7 +1,18 @@ --- title: Rate Limits -description: Understand the rate limiting policies for the Whitepages API. +description: Understand the rate limiting policies for the Whitepages API, including monthly query limits and trial exhaustion. icon: Gauge +lifecycle: current +topic: account-billing +keywords: + - "rate limit" + - "429 too many requests" + - "monthly query limit" + - "limit exceeded" + - "trial exhausted" + - "trial ran out" + - "out of queries" + - "quota exceeded" --- import { Callout } from "fumadocs-ui/components/callout"; @@ -23,9 +34,9 @@ When you exceed the rate limit, the API returns a `429 Too Many Requests` status exponential backoff in your application for best results. -## Monthly Query Limits +## Monthly Query Limits & Trial Exhaustion -Your API plan includes a monthly query limit. When exceeded, you will receive: +Your API plan includes a monthly query limit, and trial keys include a fixed trial allowance. When you exhaust either, the API returns: ```json { @@ -33,10 +44,11 @@ Your API plan includes a monthly query limit. When exceeded, you will receive: } ``` -This indicates you have hit your monthly query limit. You can either: +This `Limit Exceeded` response means you have used up your monthly query limit or your trial allowance. It is distinct from the `429 Too Many Requests` response above: `429` is short-term throttling that clears on its own, while `Limit Exceeded` persists until your quota resets or you upgrade. You can either: -- Wait until the next month when your limit resets -- Contact support for additional queries or a plan upgrade +- Wait until the next month, when a plan's monthly limit resets +- [Purchase a plan or additional queries](/documentation/purchasing-api), or contact support at api@whitepages.com +- If you are on a trial, [purchase a plan](/documentation/purchasing-api) to keep going once your trial allowance is exhausted ## Best Practices diff --git a/content/docs/references/regions/list_counties.mdx b/content/docs/references/regions/list_counties.mdx index 180a33b..b4f08fc 100644 --- a/content/docs/references/regions/list_counties.mdx +++ b/content/docs/references/regions/list_counties.mdx @@ -1,4 +1,8 @@ --- +lifecycle: current +keywords: + - "list counties" + - "counties by state" title: List counties for a state description: Retrieve a list of counties for a given state. full: true diff --git a/content/docs/references/regions/list_states.mdx b/content/docs/references/regions/list_states.mdx index 0fb126f..1598213 100644 --- a/content/docs/references/regions/list_states.mdx +++ b/content/docs/references/regions/list_states.mdx @@ -1,4 +1,8 @@ --- +lifecycle: current +keywords: + - "list states" + - "supported states" title: List all US states and territories description: Retrieve a list of all US states and territories. full: true diff --git a/content/docs/references/support-and-incident-response.mdx b/content/docs/references/support-and-incident-response.mdx index 1ce7a00..b9d4411 100644 --- a/content/docs/references/support-and-incident-response.mdx +++ b/content/docs/references/support-and-incident-response.mdx @@ -1,7 +1,15 @@ --- title: Support & Incident Response -description: Learn about our support channels, incident response times, breaking change policies, and how we communicate critical updates. +description: Learn about our support channels, incident response times, and how to get help during an outage. icon: Shield +lifecycle: current +keywords: + - "support" + - "contact support" + - "incident response" + - "outage" + - "get help" + - "report a problem" --- import { Callout } from "fumadocs-ui/components/callout"; @@ -52,91 +60,9 @@ If you suspect an outage or are experiencing unexpected errors: - Error responses you are receiving - Approximate time the issue started -## Breaking Changes Policy +## Versioning & Breaking Changes -We avoid breaking changes at nearly all cost. Backward compatibility is a top priority, and our goal is to minimize disruption to your integrations. +Our versioning approach, what we count as a breaking change, and how we announce changes now live in their own reference section: -### Our Commitments - -- **Breaking changes are always introduced in a new API version.** Your existing integration continues to work on the current version. -- **No unannounced breaking changes.** Every breaking change is communicated in advance. -- **Minimum 30-day notice** before any breaking change takes effect. -- **Migration guides** — as a matter of practice, breaking changes are accompanied by a migration guide with before-and-after examples. -- **Deprecation notices** are communicated via email and changelog before anything is removed. -- **Version support** — when a new version introduces breaking changes, the previous version remains available for at least 3 months after the new version is released. - -### What We Consider a Breaking Change - -- Removing or renaming an endpoint or data tool you call -- Removing or renaming a field from a response body -- Changing the type of an existing response field -- Adding a new required parameter to an endpoint or data tool call -- Changing authentication or authorization behavior -- Modifying error response formats - -### What We Do Not Consider a Breaking Change - -- Adding a new optional request parameter -- Adding a new tool to the MCP server -- Adding a new endpoint to the API -- Adding new fields to an existing response shape we return -- Adding new values to an existing enumerated field -- Text or wording changes to error messages or descriptions - - - We recommend that your integration ignores unknown fields in API responses and - MCP data-tool responses. This allows us to add new fields without affecting - your application. - - -The same policy applies wherever we expose the API. What it means in practice depends on the surface you use. - -### REST / HTTP Endpoints - -Breaking changes ship in a new API version at a new path (for example, `/v2/`), so your current integration keeps working untouched. We announce the change with the notice and support windows above. Within a version, an endpoint's type signature — the parameters it accepts and the fields it returns — only grows: we may add new optional parameters and new response fields, but we do not remove, rename, or change the type of those already there. - -### MCP Server & Tools - -Our Breaking Changes policy covers only the [MCP server's](/documentation/mcp) **data tools**. Data tools fetch live data or change your account and **require your API key to run** — person search, property lookup, account usage, and the like. - -The other tools available via the MCP server are not subject to this Breaking Changes policy, as they are advisory, documentation, or navigation assistance rather than integration points. - -Data tools are agent-ready wrappers for the existing REST endpoints, and are therefore governed under the same breaking-changes policy as the rest of the API. - -Clarifications for breaking and non-breaking changes within the MCP server: - -- Changes to a data tool's **name, inputs, and outputs** are considered breaking changes. -- All other changes to a tool's description or tool-definition metadata are **not** breaking changes. -- Data tools are **deprecated and removed on the same schedule as their associated endpoint**, and disappear from the server when the endpoint does. -- Data tools can be **removed independently of the endpoint**; in that case the tool follows the standard deprecated → removed timeline above (minimum 30-day notice). -- **Deprecation notices name the exact tools affected**, so you know what a given change touches. -- Changes to the **server URL, transport, authentication, or supported protocol versions** are considered breaking changes. - -How much any of this affects you depends on how you connect: - -- **Conversational clients** — Claude Desktop, Cursor, or any freeform agent pointed at the server — re-read the tool list every session and adapt to renamed tools or changed fields on their own. Only a change to the server URL, authentication, or transport, or the removal of a tool with no replacement, needs action from you. -- **Brokered or hard-coded integrations** — a router mapping fixed tool names to actions, or code that reads specific fields out of a result — should treat a data-tool change exactly like the equivalent REST change and migrate within the announced window. - -## Change Notifications - -We notify you about critical changes through multiple channels to ensure you never miss an important update. - -### Notification Types - -| Type | Channel | Lead Time | -| ------------------------- | ---------------- | ------------------- | -| **Breaking changes** | Email, changelog | 30 days minimum | -| **Deprecation notices** | Email, changelog | 30 days minimum | -| **New features** | Email, changelog | At release | -| **Scheduled maintenance** | Email | 7 days minimum | -| **Emergency maintenance** | Email | As soon as possible | - -### Staying Informed - -- **Changelog** — All API changes are documented in our [changelog](/changelog) with detailed descriptions -- **Email notifications** — Sent to the email address associated with your API account. Ensure your contact information is up to date. - - - Make sure your account email is current. Critical notifications about breaking - changes and security updates are sent exclusively to your registered email. - +- [Breaking Changes Policy](/references/versioning/breaking-changes-policy) — what counts as breaking, our commitments, and how the policy applies to REST endpoints and the MCP server +- [Change Notifications](/references/versioning/change-notifications) — notification types, lead times, and how to stay informed diff --git a/content/docs/references/versioning/breaking-changes-policy.mdx b/content/docs/references/versioning/breaking-changes-policy.mdx new file mode 100644 index 0000000..b702f90 --- /dev/null +++ b/content/docs/references/versioning/breaking-changes-policy.mdx @@ -0,0 +1,79 @@ +--- +title: Breaking Changes Policy +description: How we define, announce, and version breaking changes across the REST API and the MCP server. +icon: GitBranch +lifecycle: current +keywords: + - "breaking changes" + - "breaking change policy" + - "what counts as a breaking change" + - "api versioning" + - "deprecation" + - "backward compatibility" + - "version support window" +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +We avoid breaking changes at nearly all cost. Backward compatibility is a top priority, and our goal is to minimize disruption to your integrations. + +## Our Commitments + +- **Breaking changes are always introduced in a new API version.** Your existing integration continues to work on the current version. +- **No unannounced breaking changes.** Every breaking change is communicated in advance. +- **Minimum 30-day notice** before any breaking change takes effect. +- **Migration guides** — as a matter of practice, breaking changes are accompanied by a migration guide with before-and-after examples. +- **Deprecation notices** are communicated via email and changelog before anything is removed. +- **Version support** — when a new version introduces breaking changes, the previous version remains available for at least 3 months after the new version is released. + +## What We Consider a Breaking Change + +- Removing or renaming an endpoint or data tool you call +- Removing or renaming a field from a response body +- Changing the type of an existing response field +- Adding a new required parameter to an endpoint or data tool call +- Changing authentication or authorization behavior +- Modifying error response formats + +## What We Do Not Consider a Breaking Change + +- Adding a new optional request parameter +- Adding a new tool to the MCP server +- Adding a new endpoint to the API +- Adding new fields to an existing response shape we return +- Adding new values to an existing enumerated field +- Text or wording changes to error messages or descriptions + + + We recommend that your integration ignores unknown fields in API responses and + MCP data-tool responses. This allows us to add new fields without affecting + your application. + + +The same policy applies wherever we expose the API. What it means in practice depends on the surface you use. + +## REST / HTTP Endpoints + +Breaking changes ship in a new API version at a new path (for example, `/v2/`), so your current integration keeps working untouched. We announce the change with the notice and support windows above. Within a version, an endpoint's type signature — the parameters it accepts and the fields it returns — only grows: we may add new optional parameters and new response fields, but we do not remove, rename, or change the type of those already there. + +## MCP Server & Tools + +Our Breaking Changes policy covers only the [MCP server's](/documentation/mcp) **data tools**. Data tools fetch live data or change your account and **require your API key to run** — person search, property lookup, account usage, and the like. + +The other tools available via the MCP server are not subject to this Breaking Changes policy, as they are advisory, documentation, or navigation assistance rather than integration points. + +Data tools are agent-ready wrappers for the existing REST endpoints, and are therefore governed under the same breaking-changes policy as the rest of the API. + +Clarifications for breaking and non-breaking changes within the MCP server: + +- Changes to a data tool's **name, inputs, and outputs** are considered breaking changes. +- All other changes to a tool's description or tool-definition metadata are **not** breaking changes. +- Data tools are **deprecated and removed on the same schedule as their associated endpoint**, and disappear from the server when the endpoint does. +- Data tools can be **removed independently of the endpoint**; in that case the tool follows the standard deprecated → removed timeline above (minimum 30-day notice). +- **Deprecation notices name the exact tools affected**, so you know what a given change touches. +- Changes to the **server URL, transport, authentication, or supported protocol versions** are considered breaking changes. + +How much any of this affects you depends on how you connect: + +- **Conversational clients** — Claude Desktop, Cursor, or any freeform agent pointed at the server — re-read the tool list every session and adapt to renamed tools or changed fields on their own. Only a change to the server URL, authentication, or transport, or the removal of a tool with no replacement, needs action from you. +- **Brokered or hard-coded integrations** — a router mapping fixed tool names to actions, or code that reads specific fields out of a result — should treat a data-tool change exactly like the equivalent REST change and migrate within the announced window. diff --git a/content/docs/references/versioning/change-notifications.mdx b/content/docs/references/versioning/change-notifications.mdx new file mode 100644 index 0000000..e31c691 --- /dev/null +++ b/content/docs/references/versioning/change-notifications.mdx @@ -0,0 +1,36 @@ +--- +title: Change Notifications +description: How we notify you about breaking changes, deprecations, new features, and maintenance. +icon: Bell +lifecycle: current +keywords: + - "change notifications" + - "deprecation notice" + - "maintenance window" + - "notification lead time" + - "how am I told about changes" +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +We notify you about critical changes through multiple channels to ensure you never miss an important update. + +## Notification Types + +| Type | Channel | Lead Time | +| ------------------------- | ---------------- | ------------------- | +| **Breaking changes** | Email, changelog | 30 days minimum | +| **Deprecation notices** | Email, changelog | 30 days minimum | +| **New features** | Email, changelog | At release | +| **Scheduled maintenance** | Email | 7 days minimum | +| **Emergency maintenance** | Email | As soon as possible | + +## Staying Informed + +- **Changelog** — All API changes are documented in our [changelog](/changelog) with detailed descriptions +- **Email notifications** — Sent to the email address associated with your API account. Ensure your contact information is up to date. + + + Make sure your account email is current. Critical notifications about breaking + changes and security updates are sent exclusively to your registered email. + diff --git a/content/docs/references/versioning/meta.json b/content/docs/references/versioning/meta.json new file mode 100644 index 0000000..4f81635 --- /dev/null +++ b/content/docs/references/versioning/meta.json @@ -0,0 +1,5 @@ +{ + "title": "Versioning & Breaking Changes", + "icon": "GitBranch", + "pages": ["breaking-changes-policy", "change-notifications"] +} diff --git a/content/docs/references/webhooks/create_webhook.mdx b/content/docs/references/webhooks/create_webhook.mdx index 366a385..164f695 100644 --- a/content/docs/references/webhooks/create_webhook.mdx +++ b/content/docs/references/webhooks/create_webhook.mdx @@ -1,4 +1,10 @@ --- +lifecycle: current +topic: webhooks +keywords: + - "create webhook" + - "subscribe to events" + - "register webhook" title: Create a webhook subscription description: >- Register a new webhook subscription for property events. The endpoint URL is diff --git a/content/docs/references/webhooks/delete_webhook.mdx b/content/docs/references/webhooks/delete_webhook.mdx index 935f94e..a7de727 100644 --- a/content/docs/references/webhooks/delete_webhook.mdx +++ b/content/docs/references/webhooks/delete_webhook.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: webhooks +keywords: + - "delete webhook" + - "remove webhook subscription" title: Delete a webhook subscription description: Permanently delete a webhook subscription. This action cannot be undone. full: true diff --git a/content/docs/references/webhooks/get_webhook.mdx b/content/docs/references/webhooks/get_webhook.mdx index 4fd2e48..0f55673 100644 --- a/content/docs/references/webhooks/get_webhook.mdx +++ b/content/docs/references/webhooks/get_webhook.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: webhooks +keywords: + - "webhook details" + - "get webhook" title: Get a webhook subscription description: Retrieve a single webhook subscription by its ID. full: true diff --git a/content/docs/references/webhooks/list_webhooks.mdx b/content/docs/references/webhooks/list_webhooks.mdx index 99ee59e..d7682ba 100644 --- a/content/docs/references/webhooks/list_webhooks.mdx +++ b/content/docs/references/webhooks/list_webhooks.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: webhooks +keywords: + - "list webhooks" + - "webhook subscriptions" title: List webhook subscriptions description: >- List all webhook subscriptions for the authenticated account. Optionally diff --git a/content/docs/references/webhooks/test_webhook.mdx b/content/docs/references/webhooks/test_webhook.mdx index ddee48f..41fdbc9 100644 --- a/content/docs/references/webhooks/test_webhook.mdx +++ b/content/docs/references/webhooks/test_webhook.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: webhooks +keywords: + - "test webhook" + - "send test event" title: Test a webhook delivery description: >- Send a synthetic notification to the webhook endpoint. Uses the same payload diff --git a/content/docs/references/webhooks/update_webhook.mdx b/content/docs/references/webhooks/update_webhook.mdx index e8ce30f..1dfb841 100644 --- a/content/docs/references/webhooks/update_webhook.mdx +++ b/content/docs/references/webhooks/update_webhook.mdx @@ -1,4 +1,9 @@ --- +lifecycle: current +topic: webhooks +keywords: + - "update webhook" + - "modify webhook subscription" title: Update a webhook subscription description: >- Partially update a webhook subscription. Only provided fields are modified; diff --git a/scripts/generators/openapi/openapi.facets.test.ts b/scripts/generators/openapi/openapi.facets.test.ts new file mode 100644 index 0000000..c7164c9 --- /dev/null +++ b/scripts/generators/openapi/openapi.facets.test.ts @@ -0,0 +1,101 @@ +import { describe, expect, test } from "bun:test"; +import { injectFacets, resolveFacets } from "./openapi.facets"; + +describe("resolveFacets", () => { + test("maps the person-v2 directory to the person topic", () => { + const facets = resolveFacets( + "person-v2/search_person_by_name_phone_or_address_v2.mdx", + ); + + expect(facets.topic).toBe("person"); + expect(facets.lifecycle).toBe("current"); + expect(facets.keywords).toContain("reverse phone lookup"); + }); + + test("maps the property-v2 directory to the property topic", () => { + expect(resolveFacets("property-v2/search_property_v2.mdx").topic).toBe( + "property", + ); + }); + + test("maps the account directory to the account-billing topic", () => { + expect(resolveFacets("account/get_account_usage_data.mdx").topic).toBe( + "account-billing", + ); + }); + + test("leaves topic undefined for an unmapped directory", () => { + const facets = resolveFacets("regions/list_states.mdx"); + + expect(facets.topic).toBeUndefined(); + expect(facets.keywords).toEqual(["list states", "supported states"]); + }); + + test("returns empty keywords for an unknown file in a mapped directory", () => { + const facets = resolveFacets("person-v2/unknown_endpoint.mdx"); + + expect(facets.topic).toBe("person"); + expect(facets.keywords).toEqual([]); + }); +}); + +describe("injectFacets", () => { + const sample = "---\ntitle: X\ndescription: Y\n---\n\nbody"; + + test("inserts facets after the opening delimiter, before existing keys", () => { + const out = injectFacets(sample, { + lifecycle: "current", + topic: "person", + keywords: ["a", "b"], + }); + + expect(out).toBe( + '---\nlifecycle: current\ntopic: person\nkeywords:\n - "a"\n - "b"\ntitle: X\ndescription: Y\n---\n\nbody', + ); + }); + + test("omits the topic line when topic is undefined", () => { + const out = injectFacets(sample, { + lifecycle: "current", + keywords: ["a"], + }); + + expect(out).not.toContain("topic:"); + expect(out).toContain("lifecycle: current"); + }); + + test("omits the keywords block when there are no keywords", () => { + const out = injectFacets(sample, { + lifecycle: "current", + topic: "person", + keywords: [], + }); + + expect(out).not.toContain("keywords:"); + }); + + test("quotes keywords so reserved characters stay valid YAML", () => { + const out = injectFacets(sample, { + lifecycle: "current", + keywords: ["who owns this: property"], + }); + + expect(out).toContain(' - "who owns this: property"'); + }); + + test("preserves existing frontmatter and body", () => { + const out = injectFacets(sample, { lifecycle: "current", keywords: [] }); + + expect(out).toContain("title: X"); + expect(out).toContain("description: Y"); + expect(out.endsWith("body")).toBe(true); + }); + + test("returns content unchanged when there is no frontmatter", () => { + const noFrontmatter = "no frontmatter here"; + + expect( + injectFacets(noFrontmatter, { lifecycle: "current", keywords: ["a"] }), + ).toBe(noFrontmatter); + }); +}); diff --git a/scripts/generators/openapi/openapi.facets.ts b/scripts/generators/openapi/openapi.facets.ts new file mode 100644 index 0000000..559cde3 --- /dev/null +++ b/scripts/generators/openapi/openapi.facets.ts @@ -0,0 +1,115 @@ +import type { Lifecycle, Topic } from "../../../src/lib/facets"; + +export interface Facets { + lifecycle: Lifecycle; + topic?: Topic; + keywords: string[]; +} + +const DIRECTORY_TOPICS: Record = { + "person-v2": "person", + "property-v2": "property", + events: "deed-events", + webhooks: "webhooks", + account: "account-billing", +}; + +const FILE_KEYWORDS: Record = { + "person-v2/search_person_by_name_phone_or_address_v2.mdx": [ + "reverse phone lookup", + "phone search", + "who lives at this address", + "people search", + "name lookup", + "address lookup", + "find a person", + ], + "person-v2/get_person_by_id_v2.mdx": [ + "person by id", + "person details", + "hydrate person", + ], + "property-v2/search_property_v2.mdx": [ + "who owns this property", + "property owner", + "property search", + "ownership info", + "residents at an address", + ], + "property-v2/get_property_by_id_v2.mdx": [ + "property by id", + "property details", + ], + "events/search_deed_events.mdx": [ + "deed events", + "property transactions", + "title changes", + ], + "events/search_events.mdx": ["search events", "event query"], + "events/get_event.mdx": ["event by id", "event details"], + "webhooks/create_webhook.mdx": [ + "create webhook", + "subscribe to events", + "register webhook", + ], + "webhooks/delete_webhook.mdx": [ + "delete webhook", + "remove webhook subscription", + ], + "webhooks/get_webhook.mdx": ["webhook details", "get webhook"], + "webhooks/list_webhooks.mdx": ["list webhooks", "webhook subscriptions"], + "webhooks/test_webhook.mdx": ["test webhook", "send test event"], + "webhooks/update_webhook.mdx": [ + "update webhook", + "modify webhook subscription", + ], + "account/get_account_usage_data.mdx": [ + "account usage", + "usage data", + "remaining quota", + "how many queries left", + "query count", + ], + "regions/list_states.mdx": ["list states", "supported states"], + "regions/list_counties.mdx": ["list counties", "counties by state"], +}; + +function topicForPath(filePath: string): Topic | undefined { + const directory = filePath.split("/")[0]; + return DIRECTORY_TOPICS[directory]; +} + +export function resolveFacets(filePath: string): Facets { + return { + lifecycle: "current", + topic: topicForPath(filePath), + keywords: FILE_KEYWORDS[filePath] ?? [], + }; +} + +function serializeFacets(facets: Facets): string { + const lines = [`lifecycle: ${facets.lifecycle}`]; + + if (facets.topic) { + lines.push(`topic: ${facets.topic}`); + } + + if (facets.keywords.length > 0) { + lines.push("keywords:"); + for (const keyword of facets.keywords) { + lines.push(` - ${JSON.stringify(keyword)}`); + } + } + + return lines.join("\n") + "\n"; +} + +export function injectFacets(content: string, facets: Facets): string { + const opener = "---\n"; + + if (!content.startsWith(opener)) { + return content; + } + + return opener + serializeFacets(facets) + content.slice(opener.length); +} diff --git a/scripts/generators/openapi/openapi.generator.ts b/scripts/generators/openapi/openapi.generator.ts index d13beeb..c5adc4f 100644 --- a/scripts/generators/openapi/openapi.generator.ts +++ b/scripts/generators/openapi/openapi.generator.ts @@ -8,6 +8,7 @@ import { tagToDisplayName, } from "./openapi.utils"; import { generateRoutesPageMarkdown } from "./openapi.handler"; +import { injectFacets, resolveFacets } from "./openapi.facets"; const OPENAPI_URL = "https://api.whitepages.com/openapi.json"; const OUTPUT_DIR = "./content/docs/references"; @@ -31,12 +32,17 @@ async function generateApiEndpointDocs(): Promise { groupBy: "tag", beforeWrite(files) { const excludedDirectories = EXCLUDED_TAGS.map(tagToDirectoryName); - const includedFiles = files.filter( - (file) => - !excludedDirectories.some((directory) => - file.path.startsWith(`${directory}/`), - ), - ); + const includedFiles = files + .filter( + (file) => + !excludedDirectories.some((directory) => + file.path.startsWith(`${directory}/`), + ), + ) + .map((file) => ({ + ...file, + content: injectFacets(file.content, resolveFacets(file.path)), + })); files.splice(0, files.length, ...includedFiles); }, }); diff --git a/source.config.ts b/source.config.ts index 1965eca..7332108 100644 --- a/source.config.ts +++ b/source.config.ts @@ -4,13 +4,14 @@ import { frontmatterSchema, metaSchema, } from "fumadocs-mdx/config"; +import { facetFrontmatterFields } from "./src/lib/facets"; // You can customise Zod schemas for frontmatter and `meta.json` here // see https://fumadocs.dev/docs/mdx/collections export const docs = defineDocs({ dir: "content/docs", docs: { - schema: frontmatterSchema, + schema: frontmatterSchema.extend(facetFrontmatterFields), postprocess: { includeProcessedMarkdown: true, }, diff --git a/src/lib/facets.ts b/src/lib/facets.ts new file mode 100644 index 0000000..1e24088 --- /dev/null +++ b/src/lib/facets.ts @@ -0,0 +1,20 @@ +import { z } from "zod"; + +export const LIFECYCLES = ["current", "deprecated"] as const; +export type Lifecycle = (typeof LIFECYCLES)[number]; + +export const TOPICS = [ + "person", + "property", + "deed-events", + "webhooks", + "account-billing", + "getting-started", +] as const; +export type Topic = (typeof TOPICS)[number]; + +export const facetFrontmatterFields = { + lifecycle: z.enum(LIFECYCLES).default("current"), + topic: z.enum(TOPICS).optional(), + keywords: z.array(z.string()).default([]), +};