Developer documentation
Med Spa Radar API
Aesthetic-practice regulation as JSON: federal substance standing, per-state coverage posture, and the freshness of everything behind it. Contract v1.0.0 · OpenAPI 3.1
What this is, and what it is not
This is not a nationwide regulatory feed, and we would rather you learn that here than from an empty response. It is a statute-cited rules corpus for 12 states, a federal substance tracker, and a change feed — each carrying its own verification date and its own pipeline-health state.
States with a cited corpus today: AZ, CA, FL, GA, IL, IN, NJ, NY, NC, OH, PA, TX. Every other jurisdiction returns an explicit not_covered — see below, because that distinction is the most important thing on this page.
Not built yet, and why
- State × substance legality.No state-overlay events exist yet. An endpoint here would return “nothing on record” for every combination, which is a gap advertised as a feature.
- Enforcement events. Our verified case record is too small to be worth querying, and we will not ship a severity score invented to fill a column — that is legal-risk analysis, and it needs to be right before it is fast.
- A bill pipeline. We hold legislative change notifications, not bill records — no sponsor, chamber, or last-action fields exist. Calling it a bill tracker would misdescribe it. What we do have is served by
/v1/changes?source=legiscan, described as what it is. - Webhooks. Polling with a cursor serves the same need today. We will build them when consumers need them, not before.
Quickstart
The open-data endpoints answer without a key, at a shared limit. A free key gives you your own budget — 60 requests/minute, 5000 per day — and gives us a contact to reach before we would ever switch anything off.
curl https://medsparadar.com/v1/meta/freshness
curl -H "Authorization: Bearer msr_free_…" \
https://medsparadar.com/v1/states/TXGet a free key
Your key is created when you open the emailed link, and shown once on that page. We store only a hash and cannot re-send it.
Reading absence correctly
Every response carries a record block, and it is the field to read first. An empty result is never a bare empty array, because two very different things look identical as [].
| status | What it means |
|---|---|
on_record | We cover this scope and have data. |
not_on_record | We cover this scope, we looked, there is genuinely nothing. Absence here is evidence. |
not_covered | We have not written this scope. Our silence says nothing about the underlying law — do not rely on it. |
undetermined | Error responses only. The request was not fulfilled and nothing was determined. Never a finding. |
Freshness, and what degraded means
Every response carries freshness.pipeline, scoped to the sources that feed that endpoint. If one is behind its window we still return the data, set status: "degraded", name the source, and add a Warning header. An outage would be a worse answer than a flagged one. Where pipeline health cannot be read at all the status is "unknown", which is never an all-clear.
freshness.publication_latency is measured, not promised: across the last 30 days the median is 8 days end-to-end, with 48% live inside a week (n=106). That figure spans the time the source took to publish as well as the time we took to pick it up — it is not a pipeline latency, and the caveat travels in the payload. Live status.
Attribution is a condition of use
Every item is marked sourced or msr_analysis. Where an item comes from a source whose licence requires attribution, the response’s attribution block names the source, the licence, the exact statement, and the specific item ids it covers.
Legislative data is provided via LegiScan under CC BY 4.0. If you pass LegiScan-derived fields on — including inside a client deliverable — that attribution must travel with them. MSR-original analysis carries no such obligation and must not be attributed to a government body or to LegiScan.
Commercial access
The cited rules corpus — the statute references, the verification dates, the claims themselves — needs more than a free key. How you get there depends on one question, and it is not how much data you want: it is whether the data leaves your organisation.
Internal use
Included with a subscription
Reading your own plan’s data into your own systems needs no call. Any paid plan can mint a key from the dashboard, scoped to the states that plan covers. It takes a click, and the key is shown once.
Access follows the subscription: it starts when you subscribe and stops when you don’t, with no key to remember to revoke.
Mint one on your dashboard →Client deliverables
Quoted, not listed
Putting our corpus inside a document you hand a third party — a client report, a white-labelled deliverable, a product you sell — is a redistribution licence. The scope is the agreement, so it is settled on a call rather than bought from a page.
This is also the path for volume beyond a member key’s limits, and for scoping states you do not otherwise subscribe to.
What a commercial key reaches
GET /v1/rules/{state}— every cited claim for a licensed state: the statement, its statute reference, the URL it was verified against, and the date of that verification. Each claim carries its own verification status, because a consultancy citing one claim needs to know whether that claim is stale, and a corpus median cannot tell them.GET /v1/changes— what moved, paged by an opaque cursor. A quiet window returns an explicitnot_on_recordrather than an empty array: at two to three material items a month most windows are quiet, and being able to assert that nothing happened is the point.
A key is scoped to states we have actually written. We refuse to scope one to a state with no corpus — that would be selling access to a not_covered response.
Talk to us about commercial access
Use of this API is governed by the Terms of Service, including §8.5 (programmatic access) and §6.2 (attribution). Regulatory monitoring and reference only — not legal advice. Legislative data via LegiScan (CC BY 4.0).