Wellward

← Guides

Changelog

Try it on a test key

curl -s "https://api.wellwardhealth.com/v1/health"

2026-10-28 — API Terms v3: standalone

The API Terms now stand on their own: the Wellward Terms of Service no longer apply to the API, and the terms they used to bring in (warranty disclaimer, limitation of liability, indemnification, dispute resolution, governing law, notices and general terms) are written out in §§11–19. Arbitration now distinguishes Individual and Business Users: Individual Users keep a 30-day opt-out; Business Users arbitrate in New York and cannot opt out. A signed agreement takes precedence over the API Terms where they conflict. You may now combine Wellward prices with your own data or other sources (§4); the earlier rule against blending them into one figure is gone. Nothing else changes: fees, notice periods, caching, withdrawn prices and logging are as before. An org admin is asked to accept the new version in the dashboard (Billing).

2026-10-26 — max_age_days re-calls a listed provider whose price is older

A provider you listed on a price request is now called again when the price we hold for them was quoted more than max_age_days ago. Before, any price we held for a listed provider was the answer, however old, and only prices within max_age_days counted toward your request, so an older one could never be refreshed.

  • Without max_age_days, nothing changes: a price we already hold for a listed provider is still the answer for them.
  • Billing is unchanged: a request is billed when it produces a price within max_age_days while it is open.

2026-10-22 — Required consults are prerequisites, not add-ons

A consult or office visit the patient must pay for before a service is now a prerequisite variant, not an add-on. It is never part of the service's price. Eight services had one listed as an add-on: colonoscopy and upper-endoscopy-egd (pre-procedure consult), lasik, wart-removal, mohs-surgery, hernia-repair-inguinal, vasectomy (consultation) and dental-extraction (exam and X-rays).

  • variants[].type can be prerequisite. Three services (colposcopy, lip-tie and tongue-tie release) already returned it, but it wasn't documented.
  • These consults are no longer in addons[], and addons= no longer accepts their keys.
  • A price request whose only result is a required consult completes as no_price_obtained and is not billed, as with an add-on on its own.

2026-10-21 — Prices: abutment and crown component names, for dental implants

coverage.includes, coverage.excludes and coverage.components[].component can now name two more core components: abutment and crown. They apply to dental implant prices, alongside the existing implant (the implant fixture). For example, a quote of "implant $2,840, abutment $1,138, crown $2,045" returns each as a component price of the implant-and-crown service.

  • Treat a component name you don't recognise as a valid component: new ones may be added.
  • No other field changes.

2026-10-21 — Prices: each stated part of a quote is also its own component price; all_in filled in from the call

When a provider quotes a price and says what each part costs, each part is now also its own component price. For example, an MRI quoted as "$490: the scan $380 and the radiologist's read $110" returns the $490 price and two component prices: the scan ($380, coverage.includes ["technical"]) and the read ($110, ["professional"]).

  • These component prices follow the existing rules: they're delivered by id (in a price request's price_ids when the quote came from your request) and never appear in search, sorting or benchmarks.
  • The $490 price is unchanged, and its coverage.components still lists the two amounts.
  • coverage.all_in was null for some prices whose coverage was recorded on the call but not yet confirmed by a second check. It now gives the call's answer (true or false). No other field changes.

2026-10-12 — Price requests: via, when a listed provider is priced through the group at their facility

Each entry in a price request's providers gains via. When you list an anesthesiologist, the price usually comes from the anesthesia group that covers the facility they work at, not from the doctor. That price now counts for the doctor you listed: it is in their price_ids, and via says how it was reached: { facility: { id, name }, group: { id, name } }. For example, Dr. Bentrem at Stony Point Surgery Center, priced through NorthStar Anesthesia.

  • practice_id on that entry is the group's.
  • The price's own facility names the same facility.
  • via is null when the price is the provider's own. No other field changes.

2026-10-12 — Prices: facility, for a price that applies at a facility

Every price gains facility. It is set when the price applies at a facility the practice works at rather than at its own office: an anesthesia group's total for a procedure at the surgery center or hospital it covers. For example, NorthStar Anesthesia's total for a deep facial tumor removal at Stony Point Surgery Center, Richmond VA.

  • facility has id, name, address_line1, city, state and zip. It is null for a price at the practice's own office.
  • When facility is set, practice.geo and distance_miles are the facility's: a group that works across many states is found near the facilities it covers.
  • Additive: no other field changes.

2026-10-09 — Prices: each component's own amount, when the provider stated it

Every price's coverage gains components: each core component of the service with its status and, when the provider stated it on the call, its own amount. For example, a delivery package quoted as "$19,126.77: the hospital's $14,756.77 and the physician's $4,370, anesthesia billed separately" returns facility and professional with their amounts (included) and anesthesia excluded.

  • An amount is only ever a figure the provider said. We never estimate, split or derive one, and a range gives no amount.
  • An included component's amount is part of the price's amount; when every included component has one, they add up to it. An excluded component's amount is quoted separately, on top.
  • Amounts are given only for services with two or more core components.
  • Additive: all_in, includes and excludes are unchanged. components is empty when a price's components weren't established.

2026-10-08 — Price requests: prices from calls we made for you count at any distance

A completed price request now includes a price from any provider we called for that request, whatever its distance. Where few providers are near your location, we sometimes look further than radius_miles; a price from one of those calls used to be left out, and is now sent.

  • Providers you list in providers still count at any distance.
  • Other nearby prices (ones we already held, not gathered for your request) still come only from within radius_miles by road.
  • distance_miles on each price tells you how far it is. No fields change.

2026-10-07 — Billing: charged daily

Card accounts are now charged daily: shortly after midnight US Eastern, one invoice for the previous day's (US Eastern) Reads and completed price requests. Days without billable usage aren't charged. Rates are unchanged. The first daily charges cover October 1 onward; nothing from October is billed again on November 1.

  • The dashboard's Billing tab lists each day's charge with its invoice.
  • billing.payment_failed keeps month (YYYY-MM) and adds day (YYYY-MM-DD) when the unpaid invoice is a daily charge.
  • Invoiced (net 30) accounts are unchanged: billed monthly.

2026-10-06 — Price requests: nearby means within driving distance

A price request's nearby prices now come from providers within radius_miles by road. Before, distance was a straight line, so a provider across water (for example 20 miles across Long Island Sound from Norwalk, CT, and 60+ miles by road) counted as nearby.

  • Providers you list in providers still count at any distance.
  • /v1/prices search and distance_miles on prices are unchanged; they stay straight-line.
  • No fields change.

2026-10-06 — Price requests: one price per practice

A practice's rate is one data point. When we reached the same practice on two lines (for example its main number and a doctor who works there) and both quoted the same amount for the same variant and coverage, a request's price_ids carried it twice. It now carries it once. If one of those lines was a provider you listed, the kept price is that one, so it still appears under that provider in providers. Different amounts, variants or coverage are still separate prices. No fields change.

2026-10-06 — Price requests: one listed provider's price isn't another's

If you list a hospital or practice and a clinician whose backup number turns out to be that same hospital's line, the hospital's price now counts only under the hospital's entry in providers, not under the clinician's too. Before, it appeared under both. The price is still in the request's price_ids. No fields change.

2026-10-06 — Price requests: service is null until a query is matched

A request sent with query (and no service) now shows service: null until our team matches your words to a catalog service, which happens before any calls. Before, service showed our automatic first guess straight away, and that guess was often wrong.

  • Affects the create response, GET /v1/price-requests/{id} and webhook payloads.
  • A request sent with service is unchanged.
  • No fields are added or removed.

2026-10-06 — Price requests: an add-on on its own is not a result

A provider whose only price for the service is an add-on (for example, allergy skin testing priced per antigen, with no consult price) is no longer in a request's price_ids. That matches what Request a price already said. An add-on still arrives alongside the same provider's core or component price.

  • A request whose only result was an add-on now completes as no_price_obtained and is not billed. Before, it could complete as price_obtained and be billed.
  • No fields change.

2026-10-06 — Practice names: never a different person's name

A practice is now named after the organisation that quoted the price, never after a clinician who isn't that practice. Previously a practice could be named after any clinician whose NPI it carried, for example a hospital's price-estimation desk published under one surgeon's name.

  • practice.name follows these rules, in order:
    1. the practice's own registry organisation;
    2. a registry organisation matched by both the business name and the street address (practice.npi and entity_type: "organization" then describe that organisation);
    3. the clinician's own name, when the business is evidently theirs (their surname is in its name);
    4. otherwise the practice's business name from its Google listing (identity_source: "google", with entity_type and npi null).
  • identity_source gains a value, google. Most practices without a registry organisation now have a name. Before this, more than half of all prices had none.
  • No fields are removed.

2026-10-06 — Price requests: listed-provider results follow the call

A listed provider's price_ids now hold the prices from the numbers we called for that provider, and any recent price we already held for it. They used to hold any price at the practice the provider was grouped under. Only that matching changes; no fields change.

  • A price can't drop out of a listed provider's results when its practice is regrouped.
  • A price from a different provider at the same practice no longer counts as yours. It can still arrive as a nearby price.

2026-10-05 — coverage on every price, and component prices

Every price now says which core components it includes. Price requests also deliver component prices, such as a surgeon's fee alone. Nothing existing changes.

  • coverage is a new field on every price: all_in (true, false or null), plus includes and excludes, which list core components: professional, facility, anesthesia, standard_lens and technical. No existing field changes.
  • Component prices: a quote for part of a service, such as a listed surgeon's professional fee with the facility and anesthesia billed separately. They're now delivered with price requests and fetchable with GET /v1/prices/{id}. coverage.all_in is false on them. They never appear in search, sorting or benchmarks.
  • Billing: a price request that obtains only component prices is billed as a completed request, the same as one that obtains an all-in price.

2026-10-05 — Prices aim for the all-in total

Our calls now ask every provider for the all-in price, everything the patient would pay, and how it splits between facility, professional and anesthesia fees. No fields change.

  • amount on prices gathered from today is the all-in total whenever the provider could give it. Older prices are unchanged. Many were already all-in, and conditions.note says when one isn't.
  • conditions.note gives the breakdown when the provider gave one: All-in $T = facility $A + professional (surgeon) $B + anesthesia $C. A line starting Elsewhere: is a price at a different location, such as another facility the same surgeon operates at. It is never this practice's price.
  • Imaging prices aim for the global price, meaning the scan plus the radiologist's read.
  • Price requests that list clinicians at a facility: we ask for each clinician's professional fee at that facility, the all-in there, and whether they do it for less anywhere else they practice.

2026-10-01 — Price requests: two business days when we can't match the service

A request whose query matches no catalog service now gets an expected_by two business days out, not one: our team adds the service before any calls are made. Requests for a catalog service are unchanged.

2026-10-01 — Price requests: a blank service or query counts as not sent

"service": "" or null alongside a query is now accepted, as is a blank query alongside a service. Nothing that worked before changes.

  • Either field may be blank or null as long as the other has something; a request with neither is still 400 ("Give service or query").
  • The request-a-price guide now covers asking for a procedure that isn't in the catalog: describe it in query (CPT codes welcome) and leave service out.

2026-09-29 — Fixes from a first-customer walkthrough

Practice names, benchmark defaults, coverage by market, MCP radii, and clearer docs. No fields removed.

  • Practice names: about 320 practices were named <UNAVAIL> — a placeholder in the federal registry's "other name" field. They now show the practice's legal name.
  • /v1/benchmarks with no variant now uses the service's default variant — the one /v1/prices shows — and falls back to the variant with the most practices only when the default has no distribution there. (It used to take the largest sample, so colonoscopy benchmarked a different procedure from the prices beside it.)
  • /v1/coverage accepts market=, as /v1/prices does.
  • MCP find_cash_prices accepts every REST radius (75 and 100 were refused).
  • Docs: guide tables render as tables; placeid_only practices, add-ons a practice hasn't quoted, summary.count vs service_coverage.price_count, idempotent replays, and MCP's observation_id are explained.

2026-09-29 — Price requests: what counts, and the service we gather

A price we already hold at a provider you listed now counts for your request, and a query's service is checked by our team. No fields change.

  • A listed provider's existing price counts. We don't re-call a provider we already have a recent price for; that price is the answer for them, and the request is billed as a price obtained (within max_age_days if you sent it). Prices near your location still have to be quoted on or after the day you asked.
  • service from a query is checked by our team before any calls are made, and may be corrected or assigned — so it can change while the request is queued. A request sent with service is never changed.

2026-09-29 — Price requests: list the providers to call first

A price request can now name up to 25 providers to call first, and reports a result for each. Additive.

  • providers on POST /v1/price-requests: up to 25 { npi, facility_name }. We call those first, then nearby providers. A location is still required. An invalid NPI (check digit) or a repeated one is 400.
  • On completion each listed provider carries result, price_ids and practice_id; the request's price_ids still holds every price. Billing is unchanged: once per request that obtains a price.
  • Every price request now includes providers (empty when none were listed).

2026-09-28 — Price requests: one name for each thing

These remove fields from /v1. No live price requests have been made yet, so they ship without the 90-day notice.

  • id only. request_id is gone from the price request — it repeated id, and request_id already names the HTTP call in error responses and meta.
  • state only. status is gone from the price request, and the list filter is ?state= (queued, in_progress, completed, expired, cancelled); ?status= is 400 invalid_request.
  • expected_by and resolved_at only. estimated_completion (the same date as a datetime) and completed_at are gone; resolved_at is set when a request is completed, expired or cancelled.
  • joined_existing is gone (it was always false).
  • callback_url is refused with 400 invalid_request. It was accepted but never called; results come by the request.completed webhook or by polling.
  • Webhooks: request.completed and request.expired carry exactly the price request object. observation_ids and reason are gone (use price_ids and note), and the old event name price_request.completed can no longer be subscribed to.

2026-09-25 — Status page measured from outside

The status page now reports the API, webhook delivery and the developer portal as measured by external checks every few minutes, plus incidents our team posts — nothing else.

2026-09-25 — Sorting, page size, summary, per-page Reads

One billing change: each page of /v1/prices results is now a Read. The rest is additive.

  • sort on GET /v1/prices: price (the default: ascending amount, ties by distance) or distance (ascending distance, ties by amount). The original price_asc still works as price; any other value is 400 invalid_sort.
  • Page size is 20 (default and maximum). A larger limit is 400 limit_too_large rather than being quietly reduced. Cursors last 60 minutes and keep the first page's sort and radius. The 100-result depth limit is gone.
  • summary on every /v1/prices response: count, min_price, median_price, max_price and nearest_distance_miles, over all results before paging, identical on every page.
  • /v1/health is liveness only. rows and data_as_of are gone from it, and meta.data_as_of is gone from every response — data freshness is an internal signal; our promise is that every price was quoted within 364 days.
  • Reference and guides reorganized into eight groups and four sections. Bulk data is no longer in the public reference; it is available under an enterprise agreement.
  • Every page is a Read. A follow-up page used to be free within an hour; now each page that returns prices is one Read. summary.count tells you how many pages a full pull takes. An identical call within 60 seconds still counts once.

2026-09-24 — API Terms v2.1

The API Terms were updated; an org admin is asked to accept them again in the dashboard (Billing). What changed: 30 days' notice (was 60) before a new or higher fee; don't blend Wellward prices with other sources' prices into one figure (aggregates of Wellward prices alone are fine); stop showing a withdrawn price within 24 hours; the price-request band is "that market or comparable markets"; and §9 now describes exactly what we log.

2026-09-24 — Limits per organization, catalog-only search

Some of these remove things from /v1. There are no live customers yet, so they ship without the 90-day notice.

  • Limits are now per organization, not per key, and test and live are counted separately. Prices and benchmarks: 5/second, 5,000/day. Search: 2/second, 1,000/day. Price requests: 2/second, 500/day. Everything else: 20/second, 100,000/day. 1,200 calls a minute overall.
  • Price records per day: an org is served at most 10,000 price records in any 24 hours (2,500 for a new account until its first invoice is paid), counting follow-up pages. One query pages through at most 100 results.
  • Monthly quotas and tiers are retired. quota_exceeded is no longer returned; /v1/account shows the new limits.
  • /v1/search is catalog-only. It returns services, never prices, and is never billed. The near parameter is gone; take the slug to /v1/prices.
  • /v1/providers/{id} lists what we price at a practice, not the prices.
  • Price requests are never joined. Each request has its own expected_by and is billed on its own; joined_existing is always false.
  • The spending cap now also stops new live price requests. New accounts have a lower monthly cap until the first invoice is paid.
  • Updates (POST /v1/prices/{id}/updates and /disputes) now require a key with the contribute scope. A reported price joins your changes feed and webhooks, so you hear when it changes.

2026-09-24 — API Terms v2 and flat pricing

Nothing existing was removed. One change adds a charge: GET /v1/benchmarks is now billed when it returns a distribution.

  • Pricing is flat and per usage: one rate per Read and one per completed price request (see the pricing page). GET /v1/benchmarks now counts as a Read when it returns a distribution. Test keys are still free. See Billing.
  • Updates: POST /v1/prices/{id}/updates is the new name for reporting that a provider quoted something different. POST /v1/prices/{id}/disputes still works, and price records carry links.update alongside links.dispute.
  • Display: the disclaimer is the only required display element. Attribution is optional, so attribution.required is now false, and disclosure now returns the disclaimer text. See Displaying prices.
  • Versioning: 90 days' notice before a field or endpoint is removed or renamed within a version. A version may be retired six months after its successor is announced.

Fixes

  • GET /v1/search without prices in the answer is no longer billed as a Read.
  • GET /v1/prices/changes no longer skips events that share a timestamp at a page boundary.
  • Webhook retries now run the full schedule (about 24 hours); they stopped after about 9.
  • With addons=, amount now includes the requested add-ons for every service, matching included_in_amount.
  • market= now searches the market's own radius when you don't pass radius_miles.
  • GET /v1/price-requests?to=<date> now includes that whole day.
  • Error responses now carry Cache-Control: private, no-store, and Wellward-Mode for test keys.
  • At the spend cap, MCP now pauses only the billed tools.

2026-09-23 — Self-serve launch

All additive; nothing existing was renamed or removed.

  • Self-serve accounts. Sign up and get a test key immediately. Orgs, team members and roles (admin, developer, billing).
  • Test mode. wl_test_ keys read a fixed fictional dataset and never create work; test_scenario exercises every error.
  • Keys are now wl_test_… / wl_live_…, named, and can be rotated with overlap. Existing wwk_ keys keep working. Keys may also be sent as X-Api-Key.
  • Only valid prices. Every price is inside a 364-day freshness window and currently valid. Withdrawn prices answer 410 with withdrawn_at.
  • Prices: as_of, nested addons[], service_coverage, attribution and disclosure; zip as an alias of near; radius_miles 75 and 100. service is now required (a market without one used to return every service's prices together).
  • Coverage: services[] with per-service counts and full / partial / none.
  • New endpoints: /v1/meta/attribution, /v1/prices/changes, /v1/usage, /v1/account, GET /v1/price-requests, POST /v1/price-requests/{id}/cancel, POST /v1/webhooks/{id}/test, GET /v1/webhooks/{id}/deliveries.
  • Price requests: state, outcome, billable, price_ids; Idempotency-Key; provider_id, variant_key, max_age_days, metadata; 402 / 409 / 422 refusals.
  • Webhooks: request.completed, request.expired, price.withdrawn, price.updated, billing.payment_failed, usage.threshold_reached; Wellward-Signature: t=,v1=; retries for about a day.
  • Rate limits per endpoint class, with X-RateLimit-* and Retry-After on every 429.
  • Billing: per-Read pricing for live keys; usage, statements, spending caps.

API reference · Dashboard · Questions: hello@wellwardhealth.com