API reference · v1.0.0

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

GET/v1/uk-council-spending/transactions

Published 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

NameInTypeDescription
councilquerystring

One or more ONS GSS codes, comma separated (at most 20).

Example: E08000035,E08000039
supplierquerystring

A supplier_key (exact normalised name), e.g. from GET /suppliers.

Example: a-and-a-electrical-distributors-ltd
supplier_namequerystring

Supplier name prefix, normalised like supplier.normalised_name (at least 3 letters or digits).

Example: Mears
supplier_company_numberquerystring

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_fromquerystring (date)

First payment date (YYYY-MM-DD, inclusive).

Example: 2026-04-01
date_toquerystring (date)

Last payment date (YYYY-MM-DD, inclusive).

Example: 2026-06-30
amount_minquerystring

Minimum amount in pounds (inclusive).

Example: 10000
amount_maxquerystring

Maximum amount in pounds (inclusive).

include_redactedqueryboolean

Include lines whose payee is redacted (default true).

limitqueryinteger

Page size.

cursorquerystring

meta.pagination.next_cursor of the previous page.

Responses

200

One page of transactions.

TransactionsResponse
400

Invalid parameter (VALIDATION_ERROR; details.fields maps each parameter to the reason).

Error
401

Missing or invalid API key (UNAUTHORIZED), or a disabled, expired or revoked one (API_KEY_DISABLED, API_KEY_EXPIRED, API_KEY_REVOKED).

Error
403

Organization suspended (ORGANIZATION_SUSPENDED), no live subscription (NO_ACTIVE_SUBSCRIPTION), uk-council-spending not on the plan (PRODUCT_NOT_ENABLED) or a key scoped to another product (API_KEY_PRODUCT_SCOPE).

Error
429

Per-minute rate limit exceeded (RATE_LIMIT_EXCEEDED) or monthly quota exhausted (QUOTA_EXCEEDED).

Error
503

The council spending dataset has no active publication yet (SERVICE_UNAVAILABLE, details.dataset_id).

Error
curl
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

GET/v1/uk-council-spending/suppliers

Suppliers (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

NameInTypeDescription
qquerystring

Name prefix, normalised like normalised_name (at least 3 letters or digits). q or company_number is required.

Example: mears
company_numberquerystring

Companies House number; lists the names that carry it on at least one line.

councilquerystring

Only payments by this council (ONS GSS code).

limitqueryinteger
cursorquerystring

meta.pagination.next_cursor of the previous page (a supplier_key).

Responses

200

One page of suppliers.

SuppliersResponse
400

Invalid parameter (VALIDATION_ERROR; details.fields maps each parameter to the reason).

Error
401

Missing or invalid API key (UNAUTHORIZED), or a disabled, expired or revoked one (API_KEY_DISABLED, API_KEY_EXPIRED, API_KEY_REVOKED).

Error
403

Organization suspended (ORGANIZATION_SUSPENDED), no live subscription (NO_ACTIVE_SUBSCRIPTION), uk-council-spending not on the plan (PRODUCT_NOT_ENABLED) or a key scoped to another product (API_KEY_PRODUCT_SCOPE).

Error
429

Per-minute rate limit exceeded (RATE_LIMIT_EXCEEDED) or monthly quota exhausted (QUOTA_EXCEEDED).

Error
503

The council spending dataset has no active publication yet (SERVICE_UNAVAILABLE, details.dataset_id).

Error
curl
curl -s "https://api.olympus.new-odyssey.com/v1/uk-council-spending/suppliers" \
  -H "X-API-Key: $OLYMPUS_API_KEY"

Supplier summary

GET/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

NameInTypeDescription
supplier_keyrequiredpathstring
Example: a-and-a-electrical-distributors-ltd
date_fromquerystring (date)

First payment date (YYYY-MM-DD, inclusive).

Example: 2026-04-01
date_toquerystring (date)

Last payment date (YYYY-MM-DD, inclusive).

Example: 2026-06-30

Responses

200

The supplier.

SupplierResponse
400

Invalid parameter (VALIDATION_ERROR; details.fields maps each parameter to the reason).

Error
401

Missing or invalid API key (UNAUTHORIZED), or a disabled, expired or revoked one (API_KEY_DISABLED, API_KEY_EXPIRED, API_KEY_REVOKED).

Error
403

Organization suspended (ORGANIZATION_SUSPENDED), no live subscription (NO_ACTIVE_SUBSCRIPTION), uk-council-spending not on the plan (PRODUCT_NOT_ENABLED) or a key scoped to another product (API_KEY_PRODUCT_SCOPE).

Error
404

The council is not in the published data, or the supplier has no published payments (NOT_FOUND).

Error
429

Per-minute rate limit exceeded (RATE_LIMIT_EXCEEDED) or monthly quota exhausted (QUOTA_EXCEEDED).

Error
503

The council spending dataset has no active publication yet (SERVICE_UNAVAILABLE, details.dataset_id).

Error
curl
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

GET/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

NameInTypeDescription
council_coderequiredpathstring

ONS GSS code of the council.

Example: E08000035
date_fromquerystring (date)

First payment date (YYYY-MM-DD, inclusive).

Example: 2026-04-01
date_toquerystring (date)

Last payment date (YYYY-MM-DD, inclusive).

Example: 2026-06-30

Responses

200

The council summary.

CouncilResponse
400

Invalid parameter (VALIDATION_ERROR; details.fields maps each parameter to the reason).

Error
401

Missing or invalid API key (UNAUTHORIZED), or a disabled, expired or revoked one (API_KEY_DISABLED, API_KEY_EXPIRED, API_KEY_REVOKED).

Error
403

Organization suspended (ORGANIZATION_SUSPENDED), no live subscription (NO_ACTIVE_SUBSCRIPTION), uk-council-spending not on the plan (PRODUCT_NOT_ENABLED) or a key scoped to another product (API_KEY_PRODUCT_SCOPE).

Error
404

The council is not in the published data, or the supplier has no published payments (NOT_FOUND).

Error
429

Per-minute rate limit exceeded (RATE_LIMIT_EXCEEDED) or monthly quota exhausted (QUOTA_EXCEEDED).

Error
503

The council spending dataset has no active publication yet (SERVICE_UNAVAILABLE, details.dataset_id).

Error
curl
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

GET/v1/uk-council-spending/coverage

Every 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 (UNAUTHORIZED), or a disabled, expired or revoked one (API_KEY_DISABLED, API_KEY_EXPIRED, API_KEY_REVOKED).

Error
403

Organization suspended (ORGANIZATION_SUSPENDED), no live subscription (NO_ACTIVE_SUBSCRIPTION), uk-council-spending not on the plan (PRODUCT_NOT_ENABLED) or a key scoped to another product (API_KEY_PRODUCT_SCOPE).

Error
429

Per-minute rate limit exceeded (RATE_LIMIT_EXCEEDED) or monthly quota exhausted (QUOTA_EXCEEDED).

Error
curl
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.

FieldTypeDescription
error *string

Human-readable message.

code *string

Stable machine-readable code.

productstring

Product that produced the error, when applicable.

detailsobject

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

FieldTypeDescription
from *Date
to *Date

Provenance object

Where this record came from and which publication introduced this version of it.

FieldTypeDescription
dataset_id *enum: ukspend.transactions
source_id *string

The council's source, <council>.supplier_payments (e.g. leeds.supplier_payments).

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. 2026-06 spending_2026_06.csv.

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. ukspend:<gss>:<period>:<hash>:<n>.

DatasetPublication object

FieldTypeDescription
dataset_id *string
publication_id *integer (int64)
published_at *string (date-time)
freshness *enum: fresh | stale

stale when the active publication is older than 45 days.

Notice object

FieldTypeDescription
code *enum: as_published | grouped_by_name | not_published | several_company_numbers | outside_coverage
message *string

Pagination object

FieldTypeDescription
limit *integer
has_more *boolean
next_cursor *string | null

Meta object

FieldTypeDescription
request_idstring
datasets *DatasetPublication []

Active publication of the dataset this response read (empty before the first publication).

notices *Notice []

Caveats about this response. Always includes as_published.

paginationPagination

Supplier object

FieldTypeDescription
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

FieldTypeDescription
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 column_map of its file for the header).

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

FieldTypeDescription
data *Transaction []
meta *Meta

MonthTotal object

FieldTypeDescription
month *Month
transactions *integer (int64)
amount_total *Money

ExpenseTypeTotal object

FieldTypeDescription
expense_type *string | null
transactions *integer (int64)
amount_total *Money

SupplierTotal object

FieldTypeDescription
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

FieldTypeDescription
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

FieldTypeDescription
data *SupplierSummary []
meta *Meta

SupplierDetail object

FieldTypeDescription
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

FieldTypeDescription
data *SupplierDetail
meta *Meta

CouncilCoverage object

FieldTypeDescription
council_code *CouncilCode
council_name *string
ons_name *string | null

The ONS names-and-codes list's name for the code (e.g. Leeds); null when not loaded.

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. over £500. Rows are kept as published.

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

FieldTypeDescription
period_start *Date
period_end *Date
period_label *enum: month | quarter | financial_year | calendar_year | range
status *enum: loaded | unmapped | unreadable

unmapped: no header row maps a date, amount and supplier. unreadable: not a CSV or XLSX file (e.g. an HTML page) or not decodable.

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 (amount_invalid, amount_missing, date_invalid, date_missing).

rows_redacted *integer
rows_outside_period *integer
column_map *object

Canonical field -> the header it was read from.

provenance *Provenance

CouncilSummary object

FieldTypeDescription
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

FieldTypeDescription
data *CouncilSummary
meta *Meta

CoverageResponse object

FieldTypeDescription
data *object
meta *Meta

Identifier object

One identifier of an entity, with how and where it was linked.

FieldTypeDescription
scheme *string

Scheme code (org-id.guide prefix, or an Olympus OLY- scheme).

value *string

Normalised value.

method *enum: published | exact | derived

published: the source publishes this identifier for the record. exact: the same normalised value in another dataset. derived: computed from published values.

confidence *number

1 for published and exact links.

source *IdentifierSource

IdentifierSource object

Provenance of the link.

FieldTypeDescription
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)

RelatedVia object

The identifier the link goes through.

FieldTypeDescription
scheme *string
value *string

* required field