SectorTrace

The API

Everything on this portal is drawn from a read-only JSON API on this same server. It is documented here so that the audience most likely to want the numbers — people working in a notebook, a spreadsheet or R — does not have to reverse-engineer it from the pages.

Read this with the figures. Every response carries the caveats that govern the numbers in it, in a caveat or caveats key. They are not boilerplate: they lead with the things that must not be computed from this data — no arithmetic across evidence layers, no differencing of workforce census years, no defensible total contract value. A figure quoted without its caveat is a figure this project cannot defend, and it will be disputed by whoever it is quoted at.

Choose a route by task

How it behaves

The routes

/api/v1/summary

Headline counts across the corpus: providers, authorities, contract notices and their values, the latest workforce census metrics, and the pipeline's own collection state.

No parameters.

Returns providers, authorities, contracts (with value_is_concentrated, which is why this portal publishes no headline contract total), workforce, pipeline, funnel (the candidate-to-evidence verification funnel: discovered, undecided, promoted, rejected, evidence_rows).

/api/v1/summary

/api/v1/providers

One row per provider, with matched contract value, tribunal and CQC counts, latest charity income, and the register identifiers (company_number, charity_number) so a reader can verify at source.

No parameters.

Returns providers: an array.

/api/v1/providers

/api/v1/providers/{provider_key}/timeline

The deep dive on one provider: dated events from charity financials, tribunal decisions, NHS job adverts and contract awards, plus its CQC locations and the entity edges that link it to companies and charities. provider_key is the provider_key field from /api/v1/providers.

Returns provider, events, cqc_locations, entity_edges, tribunal_cases, charity_finance, cqc_inspections, disclosure (with gaps, disclosed and not_searched kept apart), filings, pfd_mentions, caveats.

/api/v1/providers/change_grow_live/timeline

/api/v1/authorities

Every commissioning authority: ons_code, name, type, region. The ONS code is the join key for the geography, contracts and NDTMS routes.

No parameters.

/api/v1/authorities

/api/v1/authorities/{ons_code}

Everything the warehouse holds about one authority: coverage ticks (W-12), grant allocation and budgeted spend as published, the budget lines behind the budget figure (W-27), treatment estimates with their paired confidence intervals, and the contracts it let. ons_code is the ons_code field from /api/v1/authorities.

Returns authority, coverage, grant, budget, budget_detail, treatment (fingertips and ndtms, with the same pairing rules the treatment page uses), contracts, caveats.

The grant and the budget are different figures from different documents and are never combined or divided — the payload keeps them separate and so must anything built on it. budget_detail carries amounts as published: no per-capita, no inflation adjustment, no ratio.

/api/v1/authorities/E08000025

/api/v1/compare

The existing series for two or more authorities or providers, drawn on shared axes — the campaign's "how does my authority compare?" answered in the only shape this pipeline may give it: the reader picks the peers. No new data: every series is the series an existing endpoint returns (grant and budget as the geography page draws them, treatment as the treatment page draws it, contracts by publication year as the contracts page counts them), composed for the chosen entities.

ParameterMeaning
ons_codeAn authority from /api/v1/authorities. Repeatable.
provider_keyA provider from /api/v1/providers. Repeatable.

Returns authorities, providers, series keyed by layer — grant, budget, treatment, contracts for authorities, charity and provider_contracts for providers — each carrying its own caveat, plus caveats.cross_layer.

The charts share axes with each other's authorities, never with each other's layers: nothing in the payload is combined, differenced or divided, and a gap between one chart and another is not a finding. At least one parameter is required; an unknown code is a 400.

/api/v1/compare?ons_code=E08000025&ons_code=E06000047&provider_key=change_grow_live

/api/v1/layers

The geography map's overlay layers: contracts aggregated to one point per commissioning authority, CQC-regulated locations, latest treatment rates per authority, and coverage — how many evidence kinds the warehouse holds per authority. Each layer carries its own caveats, read from the same source the export layers use, so the portal and the downloads cannot drift apart.

Returns layers, each with label, features and caveats. PFD reports are deliberately absent: they have no geometry, and coroner areas must not be mapped as if they were authorities.

No parameters.

/api/v1/layers

/api/v1/contracts

Contract notices, with aggregates computed over the whole filtered corpus and a window of individual notices. The aggregates are complete; the notices array is not, and total says how many rows the filters actually match. For every row, use the export route below.

ParameterMeaning
provider_keyOnly notices whose supplier name matches a known alias of this provider.
buyer_ons_codeOnly notices let by this authority.
year_from, year_toPublication year bounds, inclusive.
psr_only1 for notices let under the Provider Selection Regime only.
limitRows in the notices window. Default 500, maximum 5,000. Ignored by the export, which reads every row.

Returns total, total_value_gbp, value_concentration, matched_to_provider, date_range, by_year, by_provider, by_procedure_type, by_quarter, value_bands (in fixed bands that never move with the filters), ending_soon (notices whose published end date falls within two years, with the caveat saying what that does and does not mean), top_buyers, notices, caveats.

Each notice carries three link fields and they are three different claims: source_url is the API page the bytes came from — a paginated cursor, which is provenance and not a destination; notice_web_url is the address the release itself published, or null; notice_link is the one to put in front of a reader, with notice_link_basis saying whether it was published or constructed.

/api/v1/contracts?psr_only=1&year_from=2025

/api/v1/pay

The pay evidence, and the most caveat-heavy payload here: indicative wage per employee from charity accounts, NHS job adverts by band, repeatedly advertised roles, and the workforce census metrics with their verification flags.

ParameterMeaning
provider_keyOne provider's series only.
year_from, year_toFinancial year bounds, inclusive.

Returns charity_wage_series, nhs_job_adverts, nhs_job_by_band, repeat_advertised_roles, workforce_census, census_verified_count, census_total, statutory_pay_rates, living_wage_accreditations, gender_pay_gap_reports, provider_published_pay, ons_ashe_observations, skills_for_care_estimates, caveats.

The wage figure is wages and salaries divided by an average employee count. It is not a pay scale, a median salary or anyone's earnings, and the caveat saying so travels in the payload.

/api/v1/pay

/api/v1/council_spend

Payment lines from council spend-transparency files. This is actual published payment evidence, kept separate from procurement notices and authority budgets. The response does not calculate a payment total.

ParameterMeaning
authority_ons_codeOne authority from /api/v1/authorities.
provider_keyOne tracked provider, linked only by exact normalised payee-name match.
limitMaximum payment lines returned; defaults to 500.

Returns total (the number of matching lines, not an amount), payments, files (including unreadable files), and caveats.

/api/v1/council_spend

/api/v1/geography

One value per authority for a chosen metric — the choropleth's data, without the geometry. Geometry is 14 MB and does not change between metrics, so it is fetched once from /api/v1/boundaries and joined on ons_code.

ParameterMeaning
metricOne of grant_total (the default), grant_drug_alcohol, grant_per_head, budget_public_health, treatment_numbers, contract_value.
yearFinancial year. Omit for the latest available.

Returns metric, metric_label, year, unit, allocation_status, features, authority_mean, min, max, available_years, caveat.

authority_mean is the mean across authorities and is labelled as such. It is not "the England figure", which is a different number published separately. A grant allocation and a budgeted spend are different figures from different documents: do not substitute one for the other, and do not compute a ratio between them.

/api/v1/geography?metric=grant_per_head

/api/v1/boundaries

Authority boundary geometry as a GeoJSON FeatureCollection, keyed by ons_code. Large, and cached: fetch it once.

No parameters.

Returns type, features, meta (source_url, retrieved_at, count).

/api/v1/boundaries

/api/v1/fingertips

Treatment demand indicators from OHID Fingertips: the indicator catalogue, the per-authority series, and the England series alongside it.

ParameterMeaning
indicator_idOne Fingertips indicator.
topicIndicators under one topic.
substanceIndicators about one substance.
ons_codeOne authority's values.

Returns indicators, series, england_series, caveat.

/api/v1/fingertips

/api/v1/ndtms

Local-authority NDTMS figures. Called without an authority it returns the catalogue — which sheets exist, how many authorities and publications each covers — rather than 17,231 rows.

ParameterMeaning
ons_codeOne authority's rows. Without it, only the catalogue is returned.
table_refOne published sheet.

Returns datasets, authority, estimates, other_rows.

These are modelled estimates published with 95% confidence intervals, and the interval is part of the figure. An estimate in estimates carries lower, upper and has_interval; where the publication printed bounds that cannot be attached to one estimate unambiguously, they are left unattached and has_interval is false. A confidence interval on the wrong estimate is invented, which is worse than an absent one. other_rows holds the rows with no number in them — suppression markers kept verbatim. A marker is not a zero.

/api/v1/ndtms

/api/v1/pfd

Coroners' Prevention of Future Deaths reports: reports by year (with the metadata stubs counted on the chart, not in a footnote), by coroner area, the concern-term finding aid, and the two mention facts kept apart — being sent a report and being named in one are different mention_types and are never summed.

No parameters.

Returns totals, by_year, by_coroner_area, concern_terms, mentions (sent_to_providers, naming_providers, recipient_organisations), recent, caveats. The names of the deceased are in restricted tables this route cannot read, and no restricted table is listed anywhere in the payload.

/api/v1/pfd

/api/v1/claims

The campaign's claims, each linked to the evidence that supports it and approved by a named reviewer. Nothing in this response is computed: the claim text is what a person wrote, the citations are rows a person picked, and the caveats are lines a person wrote about what may not be computed from it.

No parameters.

Returns claims: an array of id, claim_text, caveats (one line each), citations (each with a resolved object of label, url, source_url and retrieved_at — or null when the row it named is no longer in the warehouse), published_by, published_at and note. Only published claims are served; a claim is published only by a recorded decision.

/api/v1/claims

/api/v1/freshness

When each source table was last written by a pipeline run — the newest retrieved_at per table. Served on its own route rather than inside /api/v1/summary because it is seconds of full table scans; the overview loads it lazily after first paint.

No parameters.

Returns tables: an array of label, table and retrieved_at (or no date at all — never collected is "never", not a zero), plus caveat.

/api/v1/freshness

/api/v1/export

The same figures as a file, with the provenance written into it. A CSV gets separated from any accompanying note within about a day of leaving this server, so the endpoint it came from, the filters that produced it, the number of rows it holds and the licence terms are all comment lines at the top of the file — and the same object is in the X-Provenance response header.

ParameterMeaning
endpointOne of summary, providers, authorities, contracts, pay, geography, fingertips, ndtms.
formatcsv (the default) or json.
any filterEvery parameter the underlying route accepts is forwarded, and is recorded in the file's filters_applied line.

An export is complete for its filters. It is not the page's window: a contracts export reads every notice the filters match, streamed, however many that is, and the # rows: line says how many so the file can be checked against itself. A limit in the query is ignored here.

/api/v1/export?endpoint=contracts&format=csv&psr_only=1

Provenance, in every row

Most rows carry source_url, retrieved_at and payload_sha256: the document the value came from, when it was fetched, and the SHA-256 of the exact bytes, which are archived. That is what makes a figure from here checkable by someone who does not trust it — which is the only kind of checking that matters.

Licence terms are per source and not uniform. Most of this material is under the Open Government Licence v3.0, which requires attribution; the workforce census is NHS Benchmarking Network content with its own terms, and council documents vary by council. Every CSV export names the licences its rows can be under, in # licence: lines.