UK Council Spending API
Download OpenAPI (uk-council-spending.yaml) · Base URL https://api.olympus.new-odyssey.com
The payments English councils publish under the Local Government Transparency Code 2015, in one schema: search transactions by council, supplier, date and amount; totals by supplier, council, month and expense type; and exactly which councils, files and months are loaded. Served by the Olympus Go gateway.
As published. Councils publish each item of spending over £500 (some publish over £250, some all spend) as CSV or XLSX files. Amounts, dates and names here are as each council publishes them, mapped onto one schema: no VAT adjustment, no reconciliation to accounts, no categorisation beyond the council's own (department, service, expense_type, description). Councils differ in which date they publish (payment, posting or certification date; the header used is in each file's column_map). Every response repeats this in meta.notices (as_published).
Coverage. Only the councils listed as published by GET /v1/uk-council-spending/coverage, for the files and months listed there (months_with_payments, and months_missing for gaps). Councils are identified by their ONS GSS code (e.g. E08000035, Leeds), checked against the ONS names-and-codes lists at every load.
Sources. Files are discovered only through catalogue APIs: the data.gov.uk CKAN API or the council's own CKAN-compatible open data portal (package_show / package_search); web pages are never read. Each file is kept under its SHA-256 and listed with its catalogue entry, licence as the catalogue states it, column mapping and row counts (GET /v1/uk-council-spending/councils/{council_code}, files).
Suppliers. Each line keeps the supplier name as published (supplier.name) and a normalised form for grouping (supplier.normalised_name: upper case, & as AND, punctuation removed, a leading THE dropped, LIMITED as LTD, PUBLIC LIMITED COMPANY as PLC, LIMITED LIABILITY PARTNERSHIP as LLP, COMPANY as CO, CORPORATION as CORP). supplier_key is the URL form of the normalised name. Grouping is not identity (grouped_by_name notice): a supplier is linked to a company only through a Companies House number a council file publishes (supplier.company_number), never by name.
Redactions. Payees councils redact, usually individuals ("Redacted Personal Data", "*Redact - Personal Information", a blank name), are returned with supplier.redacted: true, no normalised name and no numbers. They count in totals but never in supplier groupings. No payee name is inferred.
Money. Amounts are decimal strings in pounds with two places ("1234.50"); negative amounts are credits as published.
Pagination. GET /transactions returns the newest payments first with a cursor (meta.pagination.next_cursor; pass it back unchanged with the same filters). A cursor is tied to the publication it was issued under: after the data is republished, start again. GET /suppliers pages by supplier_key.
Identifiers. Council and supplier summaries carry entity_id, identifiers and related from the shared identifier registry (GET /v1/entities/{entity_id}, GET /v1/resolve): council areas by GSS code (OLY-GB-GSS) and suppliers by the Companies House number (GB-COH) their files publish. People are never registered.
Provenance. Every transaction, file and council coverage row carries a provenance block: the file it came from (source_url, source_version = file period and name), the file's date, when this version was published and the validation status of the publication. Responses list the active publication in meta.datasets.
Authenticate with an API key in X-API-Key or Authorization: Bearer. The organization's plan must include uk-council-spending; requests count against its monthly quota. Every response carries X-Request-Id. Errors share the Error body.
Transactions
Search payments
/v1/uk-council-spending/transactionsPublished payment lines, newest payment date first, filtered by any combination of council, supplier, payment date and amount. Without filters every published line is searched.
Authentication: API key (X-API-Key or Bearer)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| council | query | string | One or more ONS GSS codes, comma separated (at most 20). Example: E08000035,E08000039 |
| supplier | query | string | A Example: a-and-a-electrical-distributors-ltd |
| supplier_name | query | string | Supplier name prefix, normalised like Example: Mears |
| supplier_company_number | query | string | Companies House number a council file publishes for the supplier (8 digits, or 2 letters and 6 digits; shorter numbers are zero padded). Example: 03232863 |
| date_from | query | string (date) | First payment date ( Example: 2026-04-01 |
| date_to | query | string (date) | Last payment date ( Example: 2026-06-30 |
| amount_min | query | string | Minimum amount in pounds (inclusive). Example: 10000 |
| amount_max | query | string | Maximum amount in pounds (inclusive). |
| include_redacted | query | boolean | Include lines whose payee is redacted (default true). |
| limit | query | integer | Page size. |
| cursor | query | string |
|
Responses
| 200 | One page of transactions. | TransactionsResponse |
| 400 | Invalid parameter ( | Error |
| 401 | Missing or invalid API key ( | Error |
| 403 | Organization suspended ( | Error |
| 429 | Per-minute rate limit exceeded ( | Error |
| 503 | The council spending dataset has no active publication yet ( | Error |
curl -s "https://api.olympus.new-odyssey.com/v1/uk-council-spending/transactions" \
-H "X-API-Key: $OLYMPUS_API_KEY"Suppliers
Find suppliers and their totals
/v1/uk-council-spending/suppliersSuppliers (normalised names) whose name starts with q, or that carry company_number on at least one line, in supplier_key order, with totals across the councils they were paid by (or one council with council). Redacted payees are never listed.
Authentication: API key (X-API-Key or Bearer)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| q | query | string | Name prefix, normalised like Example: mears |
| company_number | query | string | Companies House number; lists the names that carry it on at least one line. |
| council | query | string | Only payments by this council (ONS GSS code). |
| limit | query | integer | |
| cursor | query | string |
|
Responses
| 200 | One page of suppliers. | SuppliersResponse |
| 400 | Invalid parameter ( | Error |
| 401 | Missing or invalid API key ( | Error |
| 403 | Organization suspended ( | Error |
| 429 | Per-minute rate limit exceeded ( | Error |
| 503 | The council spending dataset has no active publication yet ( | Error |
curl -s "https://api.olympus.new-odyssey.com/v1/uk-council-spending/suppliers" \
-H "X-API-Key: $OLYMPUS_API_KEY"Supplier summary
/v1/uk-council-spending/suppliers/{supplier_key}One supplier (normalised name): the spellings councils publish, the Companies House and charity numbers on its lines, totals, totals by council and by month, and its top expense types, for the payment dates given (default all). When its lines carry exactly one Companies House number, the shared identifier blocks of that company are added.
Authentication: API key (X-API-Key or Bearer)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| supplier_keyrequired | path | string | Example: a-and-a-electrical-distributors-ltd |
| date_from | query | string (date) | First payment date ( Example: 2026-04-01 |
| date_to | query | string (date) | Last payment date ( Example: 2026-06-30 |
Responses
| 200 | The supplier. | SupplierResponse |
| 400 | Invalid parameter ( | Error |
| 401 | Missing or invalid API key ( | Error |
| 403 | Organization suspended ( | Error |
| 404 | The council is not in the published data, or the supplier has no published payments ( | Error |
| 429 | Per-minute rate limit exceeded ( | Error |
| 503 | The council spending dataset has no active publication yet ( | Error |
curl -s "https://api.olympus.new-odyssey.com/v1/uk-council-spending/suppliers/a-and-a-electrical-distributors-ltd" \
-H "X-API-Key: $OLYMPUS_API_KEY"Councils
Council summary
/v1/uk-council-spending/councils/{council_code}A published council: its coverage, totals, totals by month, top suppliers and expense types for the payment dates given (default every loaded payment), and every catalogue file considered with its period, status, licence, checksum, column mapping and row counts. Councils not in the publication answer 404; see /coverage.
Authentication: API key (X-API-Key or Bearer)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| council_coderequired | path | string | ONS GSS code of the council. Example: E08000035 |
| date_from | query | string (date) | First payment date ( Example: 2026-04-01 |
| date_to | query | string (date) | Last payment date ( Example: 2026-06-30 |
Responses
| 200 | The council summary. | CouncilResponse |
| 400 | Invalid parameter ( | Error |
| 401 | Missing or invalid API key ( | Error |
| 403 | Organization suspended ( | Error |
| 404 | The council is not in the published data, or the supplier has no published payments ( | Error |
| 429 | Per-minute rate limit exceeded ( | Error |
| 503 | The council spending dataset has no active publication yet ( | Error |
curl -s "https://api.olympus.new-odyssey.com/v1/uk-council-spending/councils/E08000035" \
-H "X-API-Key: $OLYMPUS_API_KEY"Coverage
Councils served, their files and months
/v1/uk-council-spending/coverageEvery configured council with its status: published (with the file periods and payment dates loaded, the months with payments and the missing ones, file counts, totals, catalogue and licence) or not_loaded (reason not_yet_published or not_enabled). Answers 200 even before anything is published; every council is then not_loaded.
Authentication: API key (X-API-Key or Bearer)
Responses
| 200 | Coverage. | CoverageResponse |
| 401 | Missing or invalid API key ( | Error |
| 403 | Organization suspended ( | Error |
| 429 | Per-minute rate limit exceeded ( | Error |
curl -s "https://api.olympus.new-odyssey.com/v1/uk-council-spending/coverage" \
-H "X-API-Key: $OLYMPUS_API_KEY"Schemas
Error object
The error body shared by every Olympus service.
| Field | Type | Description |
|---|---|---|
| error * | string | Human-readable message. |
| code * | string | Stable machine-readable code. |
| product | string | Product that produced the error, when applicable. |
| details | object |
Money string
Pounds as a decimal string with two places.
Date string (date)
CouncilCode string
ONS GSS code of the council (its area).
Month string
DateRange object
Provenance object
Where this record came from and which publication introduced this version of it.
| Field | Type | Description |
|---|---|---|
| dataset_id * | enum: ukspend.transactions | |
| source_id * | string | The council's source, |
| source_url * | string (uri) | The file the record was read from (for a council coverage row, the catalogue entry). |
| source_version * | string | The file's period and name, e.g. |
| source_date * | string (date) | null | Date of the file as served (Last-Modified), when the server gives one. |
| published_at * | string (date-time) | When this version of the record was first published. Unchanged records keep their original time. |
| schema_version * | string | |
| validation_status * | enum: passed | passed_with_warnings | |
| record_id * | string | Stable record key within the dataset, e.g. |
DatasetPublication object
| Field | Type | Description |
|---|---|---|
| dataset_id * | string | |
| publication_id * | integer (int64) | |
| published_at * | string (date-time) | |
| freshness * | enum: fresh | stale |
|
Notice object
| Field | Type | Description |
|---|---|---|
| code * | enum: as_published | grouped_by_name | not_published | several_company_numbers | outside_coverage | |
| message * | string |
Pagination object
| Field | Type | Description |
|---|---|---|
| limit * | integer | |
| has_more * | boolean | |
| next_cursor * | string | null |
Meta object
| Field | Type | Description |
|---|---|---|
| request_id | string | |
| datasets * | DatasetPublication [] | Active publication of the dataset this response read (empty before the first publication). |
| notices * | Notice [] | Caveats about this response. Always includes |
| pagination | Pagination |
Supplier object
| Field | Type | Description |
|---|---|---|
| name * | string | null | As published (a redaction placeholder for redacted payees; null when the field is blank). |
| normalised_name * | string | null | Grouping form of the name; null when redacted. |
| supplier_key * | string | null | |
| redacted * | boolean | The council redacted the payee (usually an individual). No name, key or number is given. |
| company_number * | string | null | Companies House number the file publishes for this line (validated; invalid values are dropped). |
| charity_number * | string | null | Charity Commission (England and Wales) or OSCR number the file publishes (validated). |
| council_reference * | string | null | The council's own supplier reference, as published. |
Transaction object
| Field | Type | Description |
|---|---|---|
| transaction_id * | string | Stable id of the line (the record id). |
| council_code * | CouncilCode | |
| payment_date * | Date | The date the council publishes for the line (see |
| amount * | Money | |
| irrecoverable_vat * | string | null | Irrecoverable VAT, where published. |
| supplier * | Supplier | |
| transaction_ref * | string | null | Transaction, invoice or document number, as published. |
| department * | string | null | Directorate or department, as published. |
| service * | string | null | Service area or cost centre, as published. |
| expense_type * | string | null | Expense type or category, as published. |
| description * | string | null | Purpose or description, as published. |
| capital_revenue * | string | null | |
| file_period * | object | |
| provenance * | Provenance |
TransactionsResponse object
| Field | Type | Description |
|---|---|---|
| data * | Transaction [] | |
| meta * | Meta |
MonthTotal object
ExpenseTypeTotal object
| Field | Type | Description |
|---|---|---|
| expense_type * | string | null | |
| transactions * | integer (int64) | |
| amount_total * | Money |
SupplierTotal object
| Field | Type | Description |
|---|---|---|
| supplier_key * | string | |
| supplier_name * | string | The most common published spelling. |
| company_number * | string | null | Set when the lines carry exactly one Companies House number. |
| transactions * | integer (int64) | |
| amount_total * | Money |
SupplierSummary object
| Field | Type | Description |
|---|---|---|
| supplier_key * | string | |
| supplier_name * | string | The most common published spelling. |
| normalised_name * | string | |
| company_numbers * | array of string | |
| councils * | CouncilCode [] | |
| transactions * | integer (int64) | |
| amount_total * | Money | |
| first_payment * | Date | |
| last_payment * | Date |
SuppliersResponse object
| Field | Type | Description |
|---|---|---|
| data * | SupplierSummary [] | |
| meta * | Meta |
SupplierDetail object
| Field | Type | Description |
|---|---|---|
| supplier_key * | string | |
| normalised_name * | string | |
| names_as_published * | array of object | The ten most frequent published spellings. |
| company_numbers * | array of string | |
| charity_numbers * | array of string | |
| payment_dates * | DateRange | null | First and last payment in the dates asked; null when there is none. |
| totals * | object | |
| by_council * | array of object | |
| by_month * | MonthTotal [] | |
| top_expense_types * | ExpenseTypeTotal [] | |
| entity_id * | string | null | Olympus entity ID of the company when the lines carry exactly one Companies House number and it is registered; else null. |
| identifiers * | Identifier [] | |
| related * | RelatedLink [] |
SupplierResponse object
| Field | Type | Description |
|---|---|---|
| data * | SupplierDetail | |
| meta * | Meta |
CouncilCoverage object
| Field | Type | Description |
|---|---|---|
| council_code * | CouncilCode | |
| council_name * | string | |
| ons_name * | string | null | The ONS names-and-codes list's name for the code (e.g. |
| tier * | enum: county | unitary | metropolitan_district | london_borough | non_metropolitan_district | |
| status * | enum: published | not_loaded | |
| reason * | enum: not_yet_published | not_enabled | null | |
| catalogue * | object | |
| licence * | string | null | The licence as the catalogue states it (or that none is stated). |
| threshold_label * | string | null | What the catalogue entry says is published, e.g. |
| file_periods * | DateRange | null | Earliest start and latest end of the loaded files' stated periods. |
| payment_dates * | DateRange | null | Earliest and latest payment date loaded. |
| months_with_payments * | Month [] | |
| months_missing * | Month [] | Months between the first and last with payments that have none (a gap in what the council published or what loaded). |
| files_loaded * | integer | |
| files_skipped * | integer | Catalogue resources not loaded (PDF, XLS, before the load window, duplicate period, ...). |
| transactions * | integer (int64) | |
| amount_total * | Money | |
| suppliers * | integer (int64) | Distinct normalised supplier names. |
| redacted_transactions * | integer (int64) | |
| transactions_with_company_number * | integer (int64) | |
| provenance * | Provenance | null |
File object
| Field | Type | Description |
|---|---|---|
| period_start * | Date | |
| period_end * | Date | |
| period_label * | enum: month | quarter | financial_year | calendar_year | range | |
| status * | enum: loaded | unmapped | unreadable |
|
| status_detail * | string | null | |
| resource_name * | string | null | The catalogue resource name. |
| file_url * | string (uri) | |
| format * | enum: csv | xlsx | unknown | |
| catalogue_url * | string (uri) | The package_show call that listed the file. |
| licence * | string | null | The catalogue record's licence |
| sha256 * | string | null | Checksum of the file as retained. |
| rows_read * | integer | |
| rows_loaded * | integer | |
| rows_rejected * | object | Lines not loaded, by reason ( |
| rows_redacted * | integer | |
| rows_outside_period * | integer | |
| column_map * | object | Canonical field -> the header it was read from. |
| provenance * | Provenance |
CouncilSummary object
| Field | Type | Description |
|---|---|---|
| council * | CouncilCoverage | |
| payment_dates * | DateRange | |
| totals * | object | |
| by_month * | MonthTotal [] | |
| top_suppliers * | SupplierTotal [] | The ten largest suppliers by amount (redacted payees excluded). |
| top_expense_types * | ExpenseTypeTotal [] | |
| files * | File [] | |
| entity_id * | string | null | Olympus entity ID of the council area (OLY-GB-GSS); null until it is registered. |
| identifiers * | Identifier [] | |
| related * | RelatedLink [] |
CouncilResponse object
| Field | Type | Description |
|---|---|---|
| data * | CouncilSummary | |
| meta * | Meta |
CoverageResponse object
| Field | Type | Description |
|---|---|---|
| data * | object | |
| meta * | Meta |
Identifier object
One identifier of an entity, with how and where it was linked.
| Field | Type | Description |
|---|---|---|
| scheme * | string | Scheme code (org-id.guide prefix, or an Olympus OLY- scheme). |
| value * | string | Normalised value. |
| method * | enum: published | exact | derived |
|
| confidence * | number | 1 for published and exact links. |
| source * | IdentifierSource |
IdentifierSource object
Provenance of the link.
| Field | Type | Description |
|---|---|---|
| dataset_id * | string | Registry dataset that published the link. |
| source_id * | string | |
| source_url * | string | |
| source_version * | string | |
| source_date * | string (date) | null | |
| published_at * | string (date-time) |
RelatedLink object
The record a product serves for the same entity.
| Field | Type | Description |
|---|---|---|
| product * | string | Public product ID. |
| resource * | string | |
| path * | string | Public path of the record. |
| via * | RelatedVia |
RelatedVia object
The identifier the link goes through.
| Field | Type | Description |
|---|---|---|
| scheme * | string | |
| value * | string |
* required field