Contextual Payments
A self-contained downloadable pack that demonstrates the contextual ontology layer over ISO 20022 payments — per-source binding context, per-property transforms, data contracts, standards anchors, and direction-scoped concept aliases. Ships its own demo data.
The Contextual Payments example is a downloadable, click-through demo of a contextual ontology — and unlike every other example pack, it ships its own demo data as declarative data sources, so a fully-running deployment needs no CSV upload. (A CSV fallback is provided below for local-dev setups where the data-source reconciler isn't running.)
New to this? Read Contextual ontologies first — what a contextual ontology is, when you actually need one, and the problem it solves. This page is the show-me; that page is the why.
The scenario
You run payments operations. Your canonical ontology has one Payment concept and a few party concepts (Counterparty, Beneficiary, Originator). But the data arrives from a core-banking system as an ISO 20022 pacs.008 statement, where:
- amounts are integer cents (
1234556), not euros, - timestamps are UTC, not your booking timezone,
- and the word "Counterparty" means a different party depending on whether a transfer is inbound or outbound.
A plain binding would flatten all of that and lose it. This pack instead records the source's context, normalizes the values with declared transforms, anchors the concepts to ISO 20022 / FIBO / LEI, and registers direction-scoped aliases — so every projected Payment is trustworthy and explainable. Then you install it and watch it work.
What it demonstrates
A canonical Payment concept fed by an ISO 20022 pacs.008 statement, modelled so every projected value carries its meaning. Each bullet maps to one building block:
bindingContext— the payments binding records that this feed is an ISO 20022pacs.008statement fromcore_banking_x, booked inBE, at 96 % mapping confidence, valid from2025-01-01.transformMap— per-property transforms layered over the flat column map: the integer-minor-unitamount_minoris divided by 100 into a major-unitamount; the UTCsettled_at_utcis normalized toEurope/Brussels. Both are flagged lossy so they surface in provenance.dataContract—paymentId,amount, andcurrencymust project;currencymust be ISO 4217;amountmust be positive — owned bypayments-platform-team.anchors— standards anchors on object types and properties (ISO 20022FIToFICstmrCdtTrf/IntrBkSttlmAmt/Ccy, FIBOLegalEntity, ISO 17442 LEI) so a concept is discoverable by its external identifier.aliases— the reconciliation showpiece: the same local term"Counterparty"resolves to a different canonical concept depending on context.
Reconciliation, not a forced winner. The alias resolver surfaces all matching candidates ranked by context-specificity then confidence — it never collapses divergent sources into a silent golden record. The same is true of bindings: divergence is recorded in the provenance envelope, not hidden.
Download
The pack is a downloadable .scrydon-pack.tar.gz bundle — it is not preshipped with the platform.
- contextual-payments.scrydon-pack.tar.gz — latest.
- scrydon-pack-contextual-payments-1.0.3.scrydon-pack.tar.gz — version-pinned.
The bundle contains three content kinds: the ontology, and two declarative data sources (iso20022_pacs008_payments, core_banking_counterparties) that land the demo rows. No external API, no credentials — the data sources emit inline static rows on a schedule.
Install
Upload the pack
Download the bundle above. In your Scrydon deployment open Settings → Platform → Packs, drag the .tar.gz onto the drop zone, tick the unsigned-pack acknowledgement, and click Upload. It appears in your org catalog as Contextual Payments v1.0.3 with three contributes: 1 ontology, 2 data sources.
Enable it for a workspace-environment
Open the Ontology marketplace and enable Contextual Payments for your active workspace-environment. The two data sources are scheduled per workspace-environment by the platform's data-source reconciler.
Wait for the first tick
The data sources emit their rows on the first scheduled tick (this can take up to a minute after install while the reconciler schedules them). When it runs, two managed tables appear under Analytics → Tables: iso20022_pacs008_payments (6 rows) and core_banking_counterparties (5 rows).
No tables after a minute or two? The bundled data sources only land rows when the platform's data-source reconciler + Dapr scheduler are running — which is often not the case in a local-only dev setup. If iso20022_pacs008_payments and core_banking_counterparties never show up under Analytics → Tables, fall back to uploading the same demo data by hand:
- Download the two CSVs:
- iso20022_pacs008_payments.csv (6 payments)
- core_banking_counterparties.csv (5 counterparties)
- Analytics → Tables → upload each one. Name each table exactly
iso20022_pacs008_payments/core_banking_counterparties— the bindings resolve by matching that logical name, so a different name leaves them not ready.
The CSV columns are the exact ones the bindings reference, so once the tables exist the bindings auto-resolve and the ISSUES on /graph clear.
Upgrading from an earlier copy? Re-uploading the pack is not enough — you must also re-enable it for the workspace-environment. Pack install is a two-stage model (ADR 2026-05-30-two-stage-packs-install-vs-instantiate):
- Stage 1 — uploading the
.tar.gzin Settings → Platform → Packs installs/updates the org-scoped ontology and its bindings. - Stage 2 — Marketplace → enable for this workspace-environment installs a separate workspace-scoped copy of the ontology + bindings. This is the copy the workbench and
/graphshow (it's labelled "… (Workspace · <env>)").
A re-upload only reconciles the Stage-1 (org) copy. To push the fix into the workspace copy you actually look at, adopt the new version in the workspace. After a re-upload makes a newer catalog version available, you'll see a "Newer version available → Update to v<x>" affordance in two places:
- the Ontology Designer (
/ontology) shows an Update banner above the workbench whenever the selected ontology is behind its pack's catalog version; - the Marketplace (
/marketplace) shows an Update to v<x> button on the pack row.
Clicking Update re-runs the workspace enable at the latest version, which reconciles the workspace binding's identityColumns / columnMap / transformMap / bindingContext / source in place — no manual unbind, no delete-first. (Updates are never applied silently: a workspace owner clicks Update to adopt, so a customised workspace ontology is never overwritten behind your back.)
silver_table instances are projected at read time straight from the data-source table — nothing is materialized — so the instant the workspace binding is reconciled, a refresh of /graph shows the corrected values. There is no stale promoted data to clean up.
If you previously installed an early build whose identityColumns were wrong, you may have seen every paymentId render as null and a "Table missing columns: paymentId" issue on /graph. That was a defect in the pack — identity columns must be the physical table column payment_id, not the property slug paymentId — fixed in v1.0.2, and v1.0.3 adds the link types that connect the graph. Upload the latest, re-enable for the workspace (or click Update on the ontology), and refresh. The version-pinned filename changes with every release, so a fresh download is never served from your browser cache.
Walk through it
The steps below assume the two tables exist (from the data-source tick or the CSV upload above). The binding work needs no CSV authoring — the pack ships the ontology, context, transforms, and aliases.
See the binding auto-resolve with context
Open Ontology → Bindings and click the Payment binding row (silver_table → iso20022_pacs008_payments) to expand it — click anywhere on the row's left side, next to the ▸ caret. (Object bindings are expandable even with no columns mapped.) Because the binding's source.table matches the data source's table name, it resolves automatically — the header shows a core_banking_x · 96% source-context badge and the binding is Ready, and it already projects with the transforms applied.
One click to unlock editing. A Pick table button appears on the row. The binding is Ready and projects correctly without it — but until you click it, the column map shows as a read-only listing (no transform pickers, no editing). Click Pick table and select iso20022_pacs008_payments (it's pre-highlighted as the match) to resolve the table id; the column-map block then switches to the editable editor used in the next two steps. This is a UI gate, not a data one — the shipped transforms run at projection either way.
Inside the expanded row, the first block is the Source context form (above the column-map editor — there's no separate button). What you should see: a set of labelled fields already filled in — because the pack shipped this binding's context. This is the metadata that says "this particular feed is an outgoing ISO 20022 credit-transfer statement from the BE core-banking system, and we're 96% sure of the mapping" — and it's what gets stamped onto every value this binding projects.
The fields, and what each one tells a downstream consumer:
| Field (in the form) | Value | What it means |
|---|---|---|
| Source system | core_banking_x | Which upstream system produced these rows |
| Standard | ISO20022 · message type pacs.008 | The message format the feed conforms to |
| Jurisdiction | BE | Where the payments are booked |
| Business process | credit_transfer | The business event the feed represents |
| Currency semantics | minor_units | Amounts arrive as integer cents (why the divide_by_100 transform exists) |
| Mapping confidence | 0.96 | How sure we are this source maps to the canonical Payment concept |
| Valid from | 2025-01-01 | When this mapping became effective |
Why it matters: the same canonical Payment could be fed by a second system using pacs.009, decimal amounts, a different jurisdiction. Recording this feed's context is what lets analytics and AI tell two amount values apart and explain where each came from — instead of silently flattening them into one ambiguous column. (You can edit any field and click Save to see it round-trip; the header badge updates to match.)
Inspect the per-property transforms
Once you've clicked Pick table (previous step), the column-map block becomes the editable editor: a row per mapped property, with a Transform dropdown beside each. Two of them come pre-selected — these are the transforms the pack shipped:
amount←amount_minor, transformdivide_by_100. The feed's1234556projects as12345.56.settlementTimestamp←settled_at_utc, transformtimezone_normalize(Europe/Brussels). The UTC instant is shifted to the booking jurisdiction.
The dropdown for every other property reads No transform (identity). You can change a transform and Save to author your own.
Both shipped transforms are flagged lossy, so a read's provenance.lossyProperties lists them — callers can see the projected value is a derived approximation, not the raw source byte.
Don't see the dropdowns? The editable editor only appears after the table is resolved (Pick table). Before that you get a read-only source → property listing, which doesn't render transforms.
Confirm the context travels with reads
The 96 % confidence and source context now travel with every projected instance instead of being stripped — each read carries a provenance envelope (confidence, bindingContext, lossyProperties). Where you can observe it:
- On the graph — click an instance node on
/graph(next step). The detail panel shows a Provenance section: mapping confidence, the source context, and which properties are lossy approximations. - In the Bindings workbench — the
core_banking_x · 96%source-context badge on the binding header (the earlier steps) is the per-binding proxy. - Via the API —
POST /api/ontology/instances/query(the ontology-SDKinstances.querysurface) returns each row with itsprovenanceenvelope. - Asserted in CI —
apps/api-ontology/src/services/pack-install-contextual.integration.test.tsproves the envelope persists and resolves end-to-end on a real database.
(Optional) Explore the graph
Open /graph (Analytics → Graph). What you see first is the schema, not data: one node per object type — Payment, Counterparty, Originator, Beneficiary — with the header reading 4 TYPES · 2 LINK TYPES.
- Edges. Two link types wire the payment network:
Payment —Initiated by→ OriginatorandPayment —Sent to→ Beneficiary(each pacs.008 row carries both endpoints, so one row = one edge).Counterpartyhas no hard edge — it is reconciled to Originator/Beneficiary through the contextual aliases below, which is the point: the relationship lives in the context layer, not a foreign key. - Instance counts. Each type node shows its instance count (
Payment 6,Counterparty 5,Originator 6,Beneficiary 6) once the tables exist; before that it reads—(unknown). ISSUESmeans a binding is not ready — it can't resolve its source table. Until the two tables exist (data-source tick or the CSV upload above), this is expected; once they exist the count drops to0.- To see instances: click a type node (e.g.
Payment) and press Expand instances in the side panel (or double-click the node). Its rows render as instance nodes. The top search bar jumps straight to a specific instance. - To see provenance: click an instance node. The detail panel shows a Provenance section — mapping confidence (
96%), the source context (core_banking_x,ISO20022,pacs.008,BE…), and a Lossy row listingamountandsettlementTimestamp(the transformed properties). Plain (non-contextual) bindings show no Provenance section.
Resolve a term contextually (the showpiece)
Open Ontology → Aliases. The pack's four aliases appear in the Registered aliases list (source imported). Scroll to the Test resolution panel at the bottom, type the local term Counterparty in the alias field, and fill the context inputs:
| Context you enter | Resolves to | Why |
|---|---|---|
standard = ISO20022, direction = outgoing | Beneficiary | On an outgoing transfer the party you transact with is the credited beneficiary. |
standard = ISO20022, direction = inbound | Originator | On an inbound transfer it's the ordering debtor. |
sourceSystem = kyc_system | Counterparty | In the KYC master it's the durable legal-entity record. |
The same term, three different canonical concepts — surfaced with their confidence, ranked by how specifically the context matches. This is the contextual-reconciliation behaviour made visible.
(Optional) Suggest a mapping with AI
If your org has an LLM integration configured, expand a binding, click Pick table to open the editable editor (the same gate as the transforms — the Suggest with AI button lives inside that editor), then click Suggest with AI. It profiles the bound table's columns, asks the platformized model to map them to the binding's object type, and shows a review list (property ← column [transform] confidence%). Apply N pre-fills the editor for you to review and Save. It's advisory — nothing publishes without a human.
What's interesting about it
- Meaning, not columns — a compliance query for "outgoing credit transfers over €10 000 booked in BE" can rely on the binding context to know which feed, direction, and amount semantics produced each value, and explain divergence between sources instead of hiding it.
- Standards-anchored — the ISO 20022 / FIBO / LEI anchors mean a concept is discoverable by its external identifier, without forcing the local language to match the standard.
- Self-contained — the bundled data sources make the whole pack a one-click demo: install, wait one tick, and the contextual projection is live.
Related
- Contextual ontologies — what a contextual ontology is and when you need one (the concept behind this example).
- Context-aware bindings — the authoring guide this pack accompanies (concepts, full field reference, the
provenanceenvelope). - Authoring ontologies — the base typed-ontology guide.
- Fraude Intelligence — the base typed ontology over financial-crime data.
- Ontology → Packs — how packs ship and install.