Obscura

UK Payment Flows

Monthly totals of real UK inter-organisation payments - Bacs Direct Debit, Bacs Direct Credit and Faster Payments - by paying and receiving industry and UK region, with both the value transferred and the number of transactions.

ons_payment_flows - the dataset name to pass to the Obscura API.

Category Macro Columns 12 Refresh Monthly Point-in-time available_date

What one row means

One month's total Bacs/Faster Payments value and transaction count from one payer cell to one payee cell, where a cell is an industry and/or a UK region.

One row per (resolution, payer_sic, payer_region, payee_sic, payee_region, occurred_on).

Point-in-time availability

Every Obscura dataset carries available_date: the calendar day the publisher made the row available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the same thing on every dataset in the catalog.

For ons_payment_flows: published: available_date is a plain collector-written column carrying the release day of the FIRST ONS edition that contained this (resolution, month), taken from that edition's own metadata (`releaseDate`, converted to the Europe/London calendar day) and corroborated by the workbook Cover sheet's 'Released:' cell. It is PER EDITION and deliberately not a blanket floor: measured 2026-08-25, the SIC2/SIC5 editions release on 2026-05-21, the three by-region editions on 2026-06-18 and region-to-region on 2026-01-30, so one floor across the family would publish the by-region member about nineteen weeks early. occurred_on is the first day of the month the payments were made in, which is weeks earlier than available_date and must never be used as the point-in-time basis.

Refresh cadence

Obscura refreshes ons_payment_flows monthly - the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.

Schema - 12 columns

The full public column list for ons_payment_flows, with the meaning of every field. The same schema is served unauthenticated at https://api.obscura.trade/v1/catalog/ons_payment_flows.

ColumnTypeDescription
resolutiontext · not nullWHICH MARGIN OF THE PAYMENT CUBE this row is, and the first component of the key: `sic2`, `sic5`, `industry_region` or `region_region`. Every resolution restates the SAME underlying payments at a different breakdown, so **summing across this column double-counts the economy** - always filter to exactly one value before aggregating. It is redundant by construction (derivable from the SIC code width and whether the region columns are sentinels) and is in the key anyway, so the rule is a column a consumer can see rather than folklore.
payer_sictext · not nullIndustry of the PAYING organisation as the SIC code string exactly as ONS publishes it - 2-digit (`"46"`) at `sic2`, 5-digit (`"46110"`) at `sic5`. `"ALL"` is the explicit margin sentinel, used on resolutions that do not break the payer out by industry. Never NULL: a sentinel says "summed over this axis", a NULL would say "unknown", and they are different facts.
payer_regiontext · not nullITL1 region of the PAYING organisation (one of the twelve ONS ITL1 codes), or `"ALL"` where the resolution does not break the payer out by region.
payee_sictext · not nullIndustry of the RECEIVING organisation, on exactly the same code system and sentinel convention as `payer_sic`.
payee_regiontext · not nullITL1 region of the RECEIVING organisation, same convention as `payer_region`.
occurred_ondate · not nullTHE MONTH THE PAYMENTS WERE MADE IN, as that month's first calendar day. This is the event date and is weeks earlier than `available_date` - ONS publishes a month's flows well after the month ends. **Never filter or join point-in-time on this**; that is `available_date`.
value_gbpbigintTotal value in POUNDS STERLING of payments from the payer cell to the payee cell during `occurred_on`'s month. NULL when the cell is suppressed or genuinely absent - read `cell_status` to tell which, rather than treating a NULL as a zero. A suppressed cell is not an empty one.
transaction_countbigintNumber of individual Bacs Direct Debit, Bacs Direct Credit and Faster Payments transactions behind `value_gbp`. NULL under the same rules.
cell_statustext · not nullWHY the measures are or are not populated, so a NULL is never ambiguous: `published` (both measures present), `suppressed` (ONS withheld the cell for disclosure control - a real flow exists and its size is withheld), or `absent` (no payments observed between these cells that month). Collapsing suppressed and absent into one NULL would make "we may not tell you" and "it did not happen" indistinguishable, which for a disclosure-controlled series is the difference between a gap and a zero.
regimetext · not nullThe METHODOLOGY ERA these numbers were produced under - see [`REGIMES`]. ONS rebuilt the series between the experimental 2016-2023 publication and the current maintained editions, so a difference taken across 2024-01-01 measures the rebuild rather than the economy.
available_datedate · not nullPUBLIC-AVAILABILITY DATE - the day this `(resolution, month)` FIRST became readable, from the ONS edition's own `releaseDate` on the Europe/London calendar. **The point-in-time column: filter and join on this, never on `occurred_on`.** Per edition, not a family-wide floor - the four editions release on genuinely different days and a blanket value would publish the by-region member months before it existed.
source_release_datedateRelease day of the file this row's CURRENT values were last read from, when that is a later edition than the one that first published it. ONS revises: a restated cell keeps its original `available_date` (when the figure first became knowable) and updates this, so the two together say "known since X, last restated by the Y release".

Access ons_payment_flows

Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.

import obscura

client = obscura.Client("obs_live_…")

df = client.query(
    dataset="ons_payment_flows",
    start="2024-01-01",
)

Create a free account Browse all 122 datasets

Frequently asked questions

What is in the ons_payment_flows dataset?

Monthly totals of real UK inter-organisation payments - Bacs Direct Debit, Bacs Direct Credit and Faster Payments - by paying and receiving industry and UK region, with both the value transferred and the number of transactions. One month's total Bacs/Faster Payments value and transaction count from one payer cell to one payee cell, where a cell is an industry and/or a UK region.

How do I avoid look-ahead bias with ons_payment_flows?

Filter on ons_payment_flows.available_date, the day the publisher made the row public. For this dataset that date is derived as follows - published: available_date is a plain collector-written column carrying the release day of the FIRST ONS edition that contained this (resolution, month), taken from that edition's own metadata (`releaseDate`, converted to the Europe/London calendar day) and corroborated by the workbook Cover sheet's 'Released:' cell. It is PER EDITION and deliberately not a blanket floor: measured 2026-08-25, the SIC2/SIC5 editions release on 2026-05-21, the three by-region editions on 2026-06-18 and region-to-region on 2026-01-30, so one floor across the family would publish the by-region member about nineteen weeks early. occurred_on is the first day of the month the payments were made in, which is weeks earlier than available_date and must never be used as the point-in-time basis. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.

In what formats can I get ons_payment_flows?

As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="ons_payment_flows". The column schema is public at https://api.obscura.trade/v1/catalog/ons_payment_flows.

How often is ons_payment_flows updated?

Obscura refreshes ons_payment_flows on a monthly schedule - that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.

Related datasets

US Employment, Inflation and Wage Series (BLS)Economic series from the U.S. Bureau of Labor Statistics, fetched by series ID: employment, unemployment, CPI, PPI, wage… US Retail Sales by NAICSMonthly US retail and food-services sales by NAICS industry category, both seasonally adjusted and not adjusted, in mill… Bilateral Goods Trade Flows (UN Comtrade)Annual bilateral goods-trade totals between countries, from UN Comtrade: one row per reporter, partner and year, with tr… European Central Bank (ECB) Data SeriesEuropean Central Bank Data Portal series, retrieved by series key: euro-area policy rates, money supply, bank lending, y… Federal Reserve Economic Data (FRED) SeriesSeries from the Federal Reserve's FRED database by series ID - rates, prices, output, employment and more - as a point-i… IMF Country Macro IndicatorsCountry-level macro indicators from the IMF's DataMapper: growth, inflation, fiscal balance, debt and current account, o… UK Payment Flow CodesIndustry (SIC) and UK region (ITL1) code lists used by the UK payment-flow matrix, with published descriptions and paren… UK Macroeconomic Series (ONS)UK macroeconomic series from the Office for National Statistics: GDP, inflation, labour market, trade and output, retrie…