{"openapi":"3.1.0","info":{"title":"ObituaryMonitor Death Verification API","version":"1.0.0","description":"Programmatic death verification. Submit a name plus at least one disambiguator (state, city+state, county+state, or date of birth) and receive `found`, `possible_match`, or `not_found` with confidence scoring and source attribution. A `not_found` result is not proof the person is alive and is not a government death-registry lookup. Daily County Intelligence is a separate product: GET /api/v1/county-feed/notices returns new obituary notices and accepts state, county_slug, q, since, cursor, from, to, and limit.","contact":{"name":"ObituaryMonitor API","url":"https://obituarymonitor.com/docs/api"}},"servers":[{"url":"https://api.obituarymonitor.com","description":"Production"}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/verify":{"post":{"operationId":"verifyDeath","summary":"Verify whether a person is deceased","description":"Searches stored obituaries, crawled listing inventory, and (for `standard`/`extended` depth) historical web sources. Requires at least one disambiguator.","tags":["Verify"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-generated key (<=255 chars). A retry with the same key and an identical body replays the original response without consuming quota. Reusing a key with a different body returns 422 `idempotency_key_reuse`. Keys persist 24h.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyRequest"},"examples":{"nameStateDob":{"summary":"Name + state + DOB","value":{"first_name":"Margaret","last_name":"Henderson","dob":{"month":3,"year":1942},"address":{"city":"Austin","state":"TX"},"client_ref":"case-88421"}}}}}},"responses":{"200":{"description":"Verification completed. `result` is `found`, `possible_match`, or `not_found`.","headers":{"X-RateLimit-Limit":{"description":"Per-minute request ceiling for your account.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Per-minute requests remaining after this one.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) when the per-minute window resets.","schema":{"type":"integer"}},"X-Quota-Limit":{"description":"Monthly request allotment (omitted when unlimited).","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Monthly requests remaining (omitted when unlimited).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResponse"}}}},"400":{"description":"Validation error (`invalid_request`, `lookback_exceeds_quota`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled or trial expired (`api_access_required`, `trial_expired`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Idempotency-Key reused with a different body (`idempotency_key_reuse`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded (`rate_limited`, `quota_exceeded`).","headers":{"X-RateLimit-Limit":{"description":"Per-minute request ceiling for your account.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Per-minute requests remaining after this one.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) when the per-minute window resets.","schema":{"type":"integer"}},"X-Quota-Limit":{"description":"Monthly request allotment (omitted when unlimited).","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Monthly requests remaining (omitted when unlimited).","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error (`internal_error`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Extended-search concurrency saturated (`extended_capacity`). Retry shortly.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/verify/{verify_request_id}/family":{"post":{"operationId":"unlockVerifyFamily","summary":"Named family for a verified death","description":"Family Insights is included for the Death Verification API. This endpoint does not debit heir tokens and does not return `insufficient_tokens`. `verify_request_id` is the `token_usage.lookup_id` from that verification, and the URL is returned as `family.unlock_url`.\n\nDeath-lookup tokens are unchanged. If extraction has not run yet the response is 202 with a `Retry-After` header. If the obituary names no individuals (only references such as \"his wife\" or \"three children\") the response reports `none_found`.\n\nRequires `family_delivery_mode = tokenized`. Accounts receiving family inline get 409, as there is nothing to unlock. Accounts with family delivery disabled are not given names.","tags":["Verify"],"parameters":[{"name":"verify_request_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"`token_usage.lookup_id` from the verification."}],"responses":{"200":{"description":"Named family delivered. Family Insights is included, so `token_usage.cost` is 0 and `token_usage.charged` is false."},"202":{"description":"Extraction is queued or running. Nothing charged. Retry after the interval in `Retry-After`."},"402":{"description":"Not returned for included Verify Family Insights. Death-lookup token billing is a separate endpoint."},"403":{"description":"Billing suspended."},"404":{"description":"No verification of yours matched a notice under that id."},"409":{"description":"Family is not delivered by unlock on this account (inline or disabled)."},"503":{"description":"Billing configuration unavailable. Nothing charged."}}}},"/api/v1/verify/batch":{"post":{"operationId":"verifyDeathBatch","summary":"Verify up to 50 people in one request","description":"Runs the same verification as POST /api/v1/verify for each item. Results are returned in request order; each item is metered individually. If a rate/quota limit is hit, the remaining items short-circuit with a `rate_limited` error and `Retry-After` is set. Because the request runs synchronously, items still pending when the time budget is reached return a retriable `batch_time_budget_exceeded` error. The response also includes a top-level `batch_time_budget_exceeded` object. When those unfinished rows can be queued, that object contains `async_job.job_id` (and poll/export URLs) for POST /api/v1/verify/batch/jobs. Finished rows are already charged; unfinished rows are not charged on this response and are billed once when the async job runs. Replaying the same Idempotency-Key returns this response and does not create a second job. Otherwise retry the unfinished items in a smaller batch, or submit them to POST /api/v1/verify/batch/jobs. Idempotency-Key is supported and applies to the whole request: a repeated key replays the stored response without re-running or re-charging any item, and the same key with a different `items` array returns 422, because item billing is keyed to position in the submitted array. If the balance runs out partway, items already returned are charged and final, later items return `insufficient_tokens`, and the response lists the charged indexes - retry only the unfinished items under a NEW key.","tags":["Verify"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchRequest"}}}},"responses":{"200":{"description":"Per-item results in request order.","headers":{"Retry-After":{"description":"Present when a rate/quota limit truncated the batch.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"}}}},"400":{"description":"Invalid batch body (`invalid_request`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled or trial expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error (`internal_error`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Sync batch capacity is full (`server_busy`). Nothing was charged. Retry-After is set, or submit the batch to POST /api/v1/verify/batch/jobs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/verify/batch/jobs":{"post":{"operationId":"createVerifyBatchJob","summary":"Queue an async batch verification job","description":"Accepts up to 5,000 verify requests and queues them for background processing (processed in the background). Returns `202` with `job_id`, `poll_url`, and `export_url`. Poll GET /api/v1/verify/batch/jobs/{job_id} (paginated for large jobs) or download GET .../export.csv when finished. When the job completes, subscribed portal webhooks receive a signed `verify.batch.completed` event (`X-OM-Signature`, same scheme as watches). Set `VERIFY_WORKER_ENABLED=false` only to roll back to legacy QStash fan-out. Sync POST /api/v1/verify/batch remains capped at 50 for interactive use.","tags":["Verify"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncBatchRequest"}}}},"responses":{"202":{"description":"Job queued; poll for results.","content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","processing","completed"]},"total":{"type":"integer"},"completed":{"type":"integer"},"errors":{"type":"integer"},"pending":{"type":"integer"},"poll_url":{"type":"string"},"export_url":{"type":"string"},"execution":{"type":"string","enum":["worker","qstash"]}}}}}},"400":{"description":"Invalid batch body (`invalid_request`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Async unavailable when worker flag is off and QStash is not configured (`async_batch_unavailable`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/verify/batch/jobs/{job_id}":{"get":{"operationId":"getVerifyBatchJob","summary":"Poll async batch job status and results","description":"Returns job progress and result rows. Jobs with more than 50 rows (or any job with `offset`/`limit` query params) return a paginated `results` page plus a `pagination` object. Use `export_url` / GET .../export.csv for a full CSV download.","tags":["Verify"],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"default":500}}],"responses":{"200":{"description":"Job progress and per-row results (completed rows include verify output).","content":{"application/json":{"schema":{"type":"object","properties":{"job":{"type":"object"},"results":{"type":"array","items":{"type":"object"}},"export_url":{"type":"string"},"pagination":{"type":"object","properties":{"offset":{"type":"integer"},"limit":{"type":"integer"},"returned":{"type":"integer"},"total":{"type":"integer"},"has_more":{"type":"boolean"}}}}}}}},"404":{"description":"Job not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/verify/batch/jobs/{job_id}/export.csv":{"get":{"operationId":"exportVerifyBatchJobCsv","summary":"Download async batch job results as CSV","tags":["Verify"],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"CSV attachment with all result rows.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Job not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/requests":{"get":{"operationId":"listVerifyRequests","summary":"List your verification request log","description":"Returns your account's recent verify calls (newest first), with filtering and pagination. Add `format=csv` to download the page as CSV. Useful for reconciliation, auditing, and building your own usage dashboards.","tags":["Observability"],"parameters":[{"name":"result","in":"query","required":false,"schema":{"type":"string","enum":["found","possible_match","not_found","error"]}},{"name":"search_depth","in":"query","required":false,"schema":{"type":"string","enum":["recent","standard","extended"]}},{"name":"client_ref","in":"query","required":false,"description":"Exact match on the correlation id you supplied.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"ISO-8601 lower bound (inclusive) on created_at.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 upper bound (inclusive) on created_at.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","csv"],"default":"json"}}],"responses":{"200":{"description":"Paginated request log (or CSV when `format=csv`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogPage"}},"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Invalid filter value (`invalid_request`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled or trial expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error (`internal_error`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/watches":{"post":{"operationId":"createWatch","summary":"Create a monitor-and-notify watch","description":"Register a subject to be re-verified on a recurring schedule. When a match is found, a signed `verify.watch.matched` webhook is POSTed to `webhook_url`. The signing `secret` is returned ONLY in this response. Body is a normal verify request plus `webhook_url` (https, required) and optional `expires_in_days`.","tags":["Watches"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchCreate"}}}},"responses":{"201":{"description":"Watch created. Includes the one-time signing `secret`.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Watch"},{"type":"object","properties":{"secret":{"type":"string","description":"HMAC signing secret. Shown once — store it securely."}}}]}}}},"400":{"description":"Invalid body (`invalid_request`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled or trial expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error (`internal_error`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listWatches","summary":"List your watches","tags":["Watches"],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","matched","delivery_failed","expired","canceled"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Paginated list of watches (secrets omitted).","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Watch"}},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"},"has_more":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid API key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled or trial expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/watches/{id}":{"get":{"operationId":"getWatch","summary":"Retrieve a watch","tags":["Watches"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The watch (secret omitted).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Watch"}}}},"401":{"description":"Missing or invalid API key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Watch not found (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"cancelWatch","summary":"Cancel a watch","description":"Soft-cancels the watch; no further checks or deliveries occur.","tags":["Watches"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Watch canceled.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}}}}},"401":{"description":"Missing or invalid API key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Watch not found (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/county-feed/notices":{"get":{"operationId":"listCountyFeedNotices","summary":"Pull Daily County Intelligence notices","description":"Returns new obituary and death notices. A bare GET advances the server-managed feed cursor. Filter with state, county_slug, or q (`name` is an alias). since, cursor, from, to, and lookback select the window. Do not combine since with from, to, or lookback. Daily County Intelligence accounts receive the counties on the account. Daily National Intelligence accounts can read supported US geography. Metered GET responses never debit tokens (meta.family_extraction_tokens.debited_this_request is always 0).","tags":["Daily County Intelligence"],"parameters":[{"name":"state","in":"query","required":false,"schema":{"type":"string","minLength":2,"maxLength":2},"description":"2-letter US state code. Omit to include every county the account can access."},{"name":"county_slug","in":"query","required":false,"schema":{"type":"string"},"description":"County identifier, for example travis-county-tx or jefferson-county-al. Omit to return every county in the state filter, or every entitled county when state is also omitted."},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Name search within the pull. `name` is an accepted alias."},{"name":"name","in":"query","required":false,"schema":{"type":"string"},"description":"Alias of q."},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"ISO-8601 lower bound. Do not combine with from, to, or lookback. Use cursor to continue a date-range pull."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque pagination cursor from pagination.next_cursor. Preferred over since when both are sent."},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"ISO-8601 start of a historical window. Requires a valid range with to or lookback."},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"ISO-8601 end of a historical window. Defaults to now when from is set."},{"name":"lookback","in":"query","required":false,"schema":{"type":"string"},"description":"Relative window such as 24h, 7d, or 60m. Do not combine with since."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"default":500},"description":"1–1000, default 500, for Daily County Intelligence. Daily National Intelligence pulls are clamped to 1–500, default 50."},{"name":"include_survivors","in":"query","required":false,"schema":{"type":"boolean"},"description":"Pass true or 1 to request structured survivors. Requires the survivors entitlement. Does not debit tokens on GET."},{"name":"include_property","in":"query","required":false,"schema":{"type":"boolean"},"description":"Pass true or 1 to attach property intelligence when the account is entitled. Entitled accounts may also receive it without this flag."},{"name":"include_profile","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Attach biographical_profile to each notice (default). Pass false or 0 to omit it."}],"responses":{"200":{"description":"Notices page. Names appear only when already granted.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Notice"}},"pagination":{"type":"object"},"meta":{"type":"object","description":"Present when Family Insights is metered for the account","properties":{"family_extraction_tokens":{"type":"object","properties":{"balance":{"type":"integer"},"debited_this_request":{"type":"integer","description":"Always 0 on GET"}}}}}}}}}},"401":{"description":"Missing or invalid API key."},"403":{"description":"Daily County Intelligence not enabled."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key issued in the developer portal, sent as `Authorization: Bearer om_live_...`."}},"schemas":{"VerifyRequest":{"type":"object","required":["first_name","last_name"],"description":"At least one disambiguator is required: `address.state`, `address.city`+`state`, `address.county`+`state`, `dob.year`, or `dob.month`+`year`.","properties":{"first_name":{"type":"string","example":"Margaret"},"last_name":{"type":"string","example":"Henderson"},"middle_name":{"type":"string","description":"Identity anchor when provided — not a search hint. Candidates whose obituary states a different middle name are dropped. If the obituary omits the middle name, the result cannot reach found (stays possible_match). Initials that agree (e.g. \"M.\" ↔ Marie) count as a match."},"dob":{"type":"object","properties":{"month":{"type":"integer","minimum":1,"maximum":12},"year":{"type":"integer","minimum":1800,"maximum":2100},"day":{"type":"integer","minimum":1,"maximum":31,"description":"Requires month + year. Enables exact-date disambiguation."}}},"death_date":{"description":"Known/expected date of death. Accepts an ISO string (`YYYY-MM-DD`, `YYYY-MM`, `YYYY`) or `{year, month?, day?}`. A matching death date is a strong disambiguator and can confirm an otherwise-ambiguous common name.","oneOf":[{"type":"string","example":"2026-03-14"},{"type":"object","properties":{"year":{"type":"integer","minimum":1900,"maximum":2100},"month":{"type":"integer","minimum":1,"maximum":12},"day":{"type":"integer","minimum":1,"maximum":31}},"required":["year"]}]},"estimated_age":{"type":"integer","minimum":1,"maximum":130,"description":"Estimated age at death. Helps reject same-name matches with incompatible ages. Use with `estimated_age_tolerance` (default 5 years).","example":72},"estimated_age_tolerance":{"type":"integer","minimum":0,"maximum":20,"description":"Years of slack around `estimated_age`. Default 5 when omitted."},"death_year_from":{"type":"integer","minimum":1900,"maximum":2100,"description":"Inclusive lower bound for expected death year (e.g. 2012). Prefer a range when the exact death date is unknown. Auto-extends lookback when the range predates the standard web window.","example":2012},"death_year_to":{"type":"integer","minimum":1900,"maximum":2100,"description":"Inclusive upper bound for expected death year (e.g. 2015).","example":2015},"address":{"type":"object","properties":{"city":{"type":"string","description":"Identity anchor when provided with state. Candidates whose obituary city conflicts with this value are dropped (metro-area pairs such as Chicago/Evanston still match). Funeral-home proxy cities on listing inventory are treated as weaker signals."},"state":{"type":"string","description":"2-letter US state recommended (e.g. TX)."},"county":{"type":"string","description":"US county name (e.g. Travis or Travis County). With state, disambiguates via our funeral-home directory — city index, stored inventory county, and funeral-home domain on search results."},"line1":{"type":"string","description":"Street line. If it embeds a trailing \"City, ST [zip]\" and city/state are omitted, they are parsed from it."}}},"client_ref":{"type":"string","maxLength":255,"description":"Your correlation id; echoed back in the response."},"search_depth":{"type":"string","enum":["recent","standard","extended"],"description":"Omit for auto. `recent` = stored inventory only; `standard` adds ~3-year historical web search (stored inventory always checked); `extended` adds configurable multi-year lookback on stored + web sources."},"lookback_years":{"type":"integer","minimum":1,"maximum":20,"description":"Only valid when `search_depth` is `extended`; capped by your account. Sets the stored-inventory death-date window and the years used in web queries. Web results themselves are not date-filtered — see `lookback_check`."},"include_survivors":{"type":"boolean","description":"BETA. When true and family delivery is enabled on the account, attach structured survivors/family to the match (`match.survivors`) or offer an unlock URL. Uses stored obituary text when available; otherwise fetches the obit page to parse names, which can add about 10 seconds. If family is not on the account, extraction is skipped and `family.status` is `not_offered` with `family.reason` = `family_not_enabled`. Coverage and accuracy vary — treat as a research aid."},"require_match":{"type":"array","items":{"type":"string","enum":["dob_year","dob_month","middle_name","city","county","state"]},"description":"Strict matching — strongly recommended for batch probate/trust/creditor workflows. Each listed field must be explicitly corroborated by a candidate's obituary or that candidate is dropped. Suppresses same-name possible_match results when the obituary omits a birth year, middle name, or city you supplied. Values: dob_year, dob_month, middle_name, city, county, state — each must match a value sent in the same request. Obituaries that omit the field are also dropped (trades recall for precision). Echoed on the response."},"dob_policy":{"type":"string","enum":["strict","reject_conflicts"],"default":"strict","description":"How a required birth date (`require_match` with `dob_year` or `dob_month`) is enforced when the obituary can't confirm it. `strict` drops any candidate that doesn't confirm it. `reject_conflicts` drops only candidates whose stated birth year (or age at death) contradicts yours; obituaries that list no birth date or age, or miss by one year, are kept but returned at most as `possible_match` with `review_recommended` and a `dob_check` block explaining why."}}},"VerifyResponse":{"type":"object","required":["result","confidence","review_recommended","search_scope","checked_at"],"properties":{"result":{"type":"string","enum":["found","possible_match","not_found"]},"confidence":{"type":"number","format":"float","minimum":0,"maximum":1},"confidence_band":{"type":"string","enum":["high","moderate","low","none"],"description":"Calibrated band over confidence: high = safe for automated action, moderate = review recommended, low = verify before acting, none = not_found."},"review_recommended":{"type":"boolean"},"scoring_reasons":{"type":"array","items":{"type":"string"}},"client_ref":{"type":["string","null"]},"search_scope":{"$ref":"#/components/schemas/SearchScope"},"external_queries_count":{"type":"integer"},"checked_at":{"type":"string","format":"date-time"},"match":{"oneOf":[{"$ref":"#/components/schemas/VerifyMatch"},{"type":"null"}],"description":"Present for `found`/`possible_match`; null for `not_found`."},"candidates":{"type":"array","items":{"$ref":"#/components/schemas/VerifyCandidate"}},"dob_check":{"type":"object","description":"Present when `dob_policy` is `reject_conflicts` and a match was returned. `unverified` means the obituary could not confirm your birth date; the match is capped at `possible_match`.","properties":{"policy":{"type":"string","enum":["reject_conflicts"]},"status":{"type":"string","enum":["confirmed","unverified"]},"reason":{"type":"string","enum":["birth_date_confirmed","age_at_death_consistent","obituary_lists_no_birth_date_or_age","birth_year_near_miss","birth_month_not_stated","birth_month_differs"]},"conflict":{"type":"boolean","enum":[false]}}},"lookback_check":{"type":"object","description":"Present on extended depth when a match was returned and you did not supply a death date or range. Compares the obituary's death date with the `lookback_years` window. Web results are not date-filtered, so an `outside` death may still be real; it can only be `found` when the birth date confirms it (full date or month and year), otherwise it is capped at `possible_match`.","properties":{"window_start":{"type":"string","format":"date"},"death_date":{"type":["string","null"]},"status":{"type":"string","enum":["inside","outside","unknown"]},"capped_to_possible_match":{"type":"boolean"}}},"not_proof_of_life":{"type":"boolean","description":"Present and true only on `not_found`."},"interpretation":{"type":"string","description":"Present only on `not_found`."},"negative_result_strength":{"type":"string","enum":["weak","moderate","strong"],"description":"Present only on `not_found`; strength of the negative signal."},"family":{"$ref":"#/components/schemas/VerifyFamily"}}},"VerifyFamily":{"type":"object","description":"Family delivery block on every verification. Names are never present here unless the account is `legacy_inline`.","properties":{"status":{"type":["string","null"],"description":"`not_offered` when family is not on the account. Otherwise the extraction status (`ok`, `none_found`, `unavailable_realtime`, `error`) or null when the survivor step did not run."},"available":{"type":"boolean"},"count":{"type":"integer"},"reason":{"type":"string","enum":["unlock_required","not_available","no_named_family","family_not_enabled"],"description":"`family_not_enabled` = this plan does not include named family; live extraction is skipped. `unlock_required` = names available via `unlock_url`. `not_available` = no linkable listing notice."},"notice_id":{"type":"string"},"unlock_url":{"type":"string"}}},"SearchScope":{"type":"object","properties":{"stored_obituaries_checked":{"type":"boolean"},"listing_inventory_checked":{"type":"boolean"},"newspaper_inventory_checked":{"type":"boolean"},"historical_web_search_checked":{"type":"boolean"},"search_depth":{"type":"string","enum":["recent","standard","extended"]},"search_depth_requested":{"oneOf":[{"type":"string","enum":["recent","standard","extended"]},{"type":"null"}]},"search_depth_auto_reason":{"type":["string","null"]},"years_searched":{"type":"array","items":{"type":"integer"}},"lookback_years_requested":{"type":["integer","null"]},"lookback_years_applied":{"type":["integer","null"]},"web_search_status":{"type":"string","enum":["skipped","pending_phase2","completed"]}}},"VerifyMatch":{"type":"object","required":["matched_name","obituary_url","evidence","source_trust"],"properties":{"matched_name":{"type":"string"},"death_date":{"type":["string","null"]},"birth_date":{"type":["string","null"],"description":"Obituary-printed birth date when known (`YYYY-MM-DD`, or coarser `YYYY-MM` / `YYYY`). Null when unknown — never invented from age alone."},"location":{"type":["string","null"]},"obituary_url":{"type":"string"},"source":{"type":["string","null"]},"snippet":{"type":["string","null"],"deprecated":true,"description":"Deprecated. Always null. Obituary text is not delivered; read obituary_url."},"biography_summary":{"type":["string","null"],"description":"A short summary of the person's life written in our own words from the published obituary. Never quotes the obituary. Null when no summary is available yet."},"evidence":{"$ref":"#/components/schemas/Evidence"},"scoring_reasons":{"type":"array","items":{"type":"string"}},"source_trust":{"type":"string","enum":["stored","extended"]},"survivors":{"type":"array","description":"BETA. Structured survivors/family parsed from the obituary text. Present only when `include_survivors` was requested.","items":{"type":"object","properties":{"name":{"type":"string"},"relationship":{"type":"string"},"degree_of_kinship":{"type":"string","description":"Kinship degree label, e.g. \"1st Degree\", \"In-Law\"."},"location":{"type":["string","null"]}}}},"survivors_status":{"type":"string","enum":["ok","none_found","unavailable_realtime","error"],"description":"BETA. `unavailable_realtime` = no stored text for a synchronous lookup."},"survivors_source":{"type":["string","null"],"enum":["obituary_full_text","snippet","scraped",null],"description":"BETA. Which source the survivor list was read from."},"survivors_beta":{"type":"boolean","description":"Always true; survivors extraction is in beta."},"biographical_profile":{"$ref":"#/components/schemas/BiographicalProfile","description":"Profile of the matched obituary. An occupation citation supports that occupation only. Family facts are included only when family names are delivered inline for this request. Does not affect `result` or `confidence`."}}},"ProfileEvidence":{"type":"object","required":["status","quote","flags"],"properties":{"status":{"type":"string","enum":["supported","uncertain","explicit_negative","not_mentioned"]},"quote":{"type":["string","null"],"deprecated":true,"description":"Deprecated. Always null. The obituary sentence is not returned. `status` says whether a checked sentence supports the value. Flag `quote_withheld` still marks a sentence withheld for naming family."},"flags":{"type":"array","items":{"type":"string"}}}},"BiographicalProfile":{"description":"Captured work, military service, education and places from the obituary. An occupation citation supports that occupation only; it does not verify education, places, business_owner, or family counts. Military service carries its own evidence. A veteran, branch, or era is `uncertain` unless a checked sentence attributes that service to the deceased. That sentence is not returned (`quote` is deprecated and always null). A stored grade without that check stays uncertain. Never changes match scores. Poll again when `profile_status` is `pending`; there is no webhook. If the lookup fails the notice is still delivered with `{\"profile_status\": null, \"profile_error\": \"profile_lookup_failed\"}`.","oneOf":[{"type":"object","required":["profile_status","profile_version","last_refresh_error","family_access"],"properties":{"profile_status":{"type":"string","enum":["ready","pending","unavailable","skipped"]},"profile_version":{"type":["integer","null"]},"last_refresh_error":{"type":["object","null"],"description":"Most recent failed refresh; a ready profile may still carry one.","properties":{"status":{"type":"string"},"profile_version":{"type":["integer","null"]},"at":{"type":["string","null"],"format":"date-time"}}},"skip_reason":{"type":"string","enum":["no_biographical_cues"]},"family_access":{"type":"string","enum":["included","omitted"],"description":"`included` only when family names are already released for this notice under the account's existing family-access rules."},"occupations":{"type":"array","description":"Present when ready.","items":{"type":"object","properties":{"title":{"type":["string","null"],"description":"Job title. Only the first letter is uppercased for display; the rest of the text is unchanged."},"employer":{"type":["string","null"],"description":"Employer as stored. The first letter is uppercased only when the title is empty, because that is when the employer starts the entry."},"retired":{"type":"boolean"},"profession_ids":{"type":"array","items":{"type":"string"}},"profession_labels":{"type":"array","items":{"type":"string"}},"evidence":{"$ref":"#/components/schemas/ProfileEvidence"}}}},"business_owner":{"type":["boolean","null"]},"military":{"type":"object","properties":{"veteran":{"$ref":"#/components/schemas/ProfileEvidence"},"branches":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/ProfileEvidence"},{"type":"object","properties":{"value":{"type":"string"}}}]}},"eras":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/ProfileEvidence"},{"type":"object","properties":{"value":{"type":"string"}}}]}}}},"education":{"type":"array","items":{"type":"object","properties":{"school":{"type":["string","null"]},"level":{"type":["string","null"]},"year":{"type":["integer","null"]}}}},"places":{"type":"object","properties":{"birthplace":{"type":["object","null"],"properties":{"city":{"type":["string","null"]},"state":{"type":["string","null"]}}},"residence":{"type":["object","null"],"properties":{"city":{"type":["string","null"]},"state":{"type":["string","null"]}}}}},"family":{"type":"object","description":"Present only when `family_access` is `included`.","properties":{"marital_status":{"type":["string","null"]},"children_count":{"type":["integer","null"]},"grandchildren_count":{"type":["integer","null"]},"great_grandchildren_count":{"type":["integer","null"]},"siblings_count":{"type":["integer","null"]},"is_parent":{"type":"string","enum":["supported","uncertain","explicit_negative","not_mentioned"]},"is_grandparent":{"type":"string","enum":["supported","uncertain","explicit_negative","not_mentioned"]},"is_great_grandparent":{"type":"string","enum":["supported","uncertain","explicit_negative","not_mentioned"]},"has_siblings":{"type":"string","enum":["supported","uncertain","explicit_negative","not_mentioned"]},"is_widowed":{"type":"string","enum":["supported","uncertain","explicit_negative","not_mentioned"]}}}}},{"type":"object","required":["profile_status","profile_error"],"properties":{"profile_status":{"type":"null"},"profile_error":{"type":"string","enum":["profile_lookup_failed"]}}}]},"VerifyCandidate":{"type":"object","required":["matched_name","obituary_url","confidence"],"properties":{"matched_name":{"type":"string"},"location":{"type":["string","null"]},"obituary_url":{"type":"string"},"confidence":{"type":"number","format":"float"},"scoring_reasons":{"type":"array","items":{"type":"string"}},"source_trust":{"type":"string","enum":["stored","extended"]}}},"Evidence":{"type":"object","properties":{"name_match":{"type":"string","enum":["exact","near","partial","mismatch","unknown"]},"location_match":{"type":"string","enum":["address_city","city_state","county_state","state_only","nearby","mismatch","unknown"]},"dob_match":{"type":"string","enum":["exact_date","month_year","year_only","age_consistent","mismatch","unknown"]}}},"BatchRequest":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/VerifyRequest"}}}},"AsyncBatchRequest":{"type":"object","required":["items"],"description":"Async job body. Same item schema as sync batch, but up to 5,000 rows per job.","properties":{"items":{"type":"array","minItems":1,"maxItems":5000,"items":{"$ref":"#/components/schemas/VerifyRequest"}}}},"BatchResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/BatchResultItem"}},"batch_time_budget_exceeded":{"type":"object","description":"Present when the synchronous budget stopped the batch. `async_job` is set when the unfinished rows were queued for you.","properties":{"message":{"type":"string"},"unfinished_indexes":{"type":"array","items":{"type":"integer"}},"queued_indexes":{"type":"array","items":{"type":"integer"}},"async_job":{"type":"object","nullable":true,"properties":{"job_id":{"type":"string","format":"uuid"},"poll_url":{"type":"string"},"export_url":{"type":"string"}}}}}}},"BatchResultItem":{"type":"object","required":["index"],"description":"A verify response (with an added `index`) on success, or `{ index, client_ref, error }` on failure.","properties":{"index":{"type":"integer","description":"Zero-based position in the request `items`."},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}},"additionalProperties":true},"RequestLogPage":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RequestLogEntry"}},"pagination":{"type":"object","required":["limit","offset","total","has_more"],"properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"},"has_more":{"type":"boolean"}}}}},"RequestLogEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"client_ref":{"type":["string","null"]},"query":{"type":"object","properties":{"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]}}},"search_depth":{"type":"string","enum":["recent","standard","extended"]},"result":{"type":"string","enum":["found","possible_match","not_found","error"]},"confidence":{"type":["number","null"],"format":"float"},"negative_result_strength":{"type":["string","null"]},"review_recommended":{"type":"boolean"},"latency_ms":{"type":"integer"},"external_queries_count":{"type":"integer"},"error_code":{"type":["string","null"]}}},"WatchCreate":{"type":"object","required":["first_name","last_name","webhook_url"],"description":"A verify request body plus webhook fields. The verify portion must include at least one disambiguator, exactly like POST /api/v1/verify.","allOf":[{"$ref":"#/components/schemas/VerifyRequest"}],"properties":{"webhook_url":{"type":"string","format":"uri","description":"HTTPS URL that receives signed verify.watch.matched events."},"expires_in_days":{"type":"integer","minimum":1,"maximum":365,"default":180,"description":"Auto-expire the watch after this many days if never matched."}}},"Watch":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","matched","delivery_failed","expired","canceled"]},"subject":{"type":"object","description":"The stored verify request body."},"client_ref":{"type":["string","null"]},"webhook_url":{"type":"string"},"search_depth":{"type":"string","enum":["recent","standard","extended"]},"last_result":{"type":["string","null"]},"check_count":{"type":"integer"},"last_checked_at":{"type":["string","null"],"format":"date-time"},"matched_at":{"type":["string","null"],"format":"date-time"},"delivery_attempts":{"type":"integer"},"last_delivery_at":{"type":["string","null"],"format":"date-time"},"last_delivery_status":{"type":["integer","null"]},"expires_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}