Skip to main content
The canonical field registry β€” defined in packages/core-model/src/canonical/field-registry.ts and exposed at GET /v1/canonical-fields β€” is the single source of truth for β€œwhat fields exist on each canonical model, and which evidence sources can populate them.” External files, webhooks, and APIs should map into these known fields. Unknown or long-tail data should stay in RawRecord.payload, metadata, or FlowLegReference β€” never invent ad-hoc canonical columns at runtime.

Purpose

The registry gives three parts of the product a shared contract:
  • Import profile builders know which fields can be mapped (fieldMappings on ImportProfile).
  • API and adapter code know which canonical shape to produce when normalizing a RawRecord into a FlowLeg or PaymentIntent.
  • Dashboard screens know which fields to show when users configure mappings.

The /v1/canonical-fields endpoint

GET /v1/canonical-fields?model=<CanonicalFieldModel>&sourceType=<CanonicalFieldSourceType>&importTargetsOnly=<boolean>
Query parameters (CanonicalFieldListQuery):
ParamTypeBehavior
modelPaymentIntent | RawRecord | FlowLeg | FlowLegReference | ReconciliationCaseFilter to fields on one model.
sourceTypeCanonicalFieldSourceTypeFilter to fields whose sourceTypes includes this value.
importTargetsOnlyboolean (default false)When true and sourceType is set, returns only fields valid as import mapping targets for that source type (see below). When true without a sourceType, returns an empty list.
Each item in the response (CanonicalFieldDefinitionResponse):
{
  path: string;            // e.g. "PaymentIntent.sourceAmount"
  model: string;
  label: string;
  description: string;
  requirement: 'required' | 'optional' | 'system';
  storage: 'first_class' | 'json' | 'reference';
  sourceTypes: string[];
  examples?: string[];
  notes?: string;
}

requirement values

  • required β€” must be present for the model to be valid (e.g. PaymentIntent.externalReference, RawRecord.payload, FlowLeg.type).
  • optional β€” may be present; enriches matching, reporting, or review.
  • system β€” written by the matcher/evaluator, not by import mappings. All ReconciliationCase.* fields are system.

storage values

  • first_class β€” a real column on the table (queryable, indexable).
  • json β€” stored inside a Json column (metadata, references, payload, validationErrors).
  • reference β€” stored as a row in FlowLegReference (typed key/value identifiers).

CanonicalFieldSourceType values

client_transfer_report   client_internal_ledger   bank_statement
onchain_report            psp_report                manual
api_expectation
api_expectation represents direct API intake (POST /v1/payment-intents, POST /v1/evidence/provider, POST /v1/evidence/onchain) β€” it is excluded from ReconciliationRule.sourceType (a rule can’t be scoped to β€œthe API itself” as an evidence source) but is a valid sourceTypes entry for PaymentIntent fields.

PaymentIntent fields

Populated by direct API intake (api_expectation) or client_internal_ledger file imports.
Field pathRequirementStorageDescriptionExamples / Notes
PaymentIntent.externalReferencerequiredfirst_classClient’s stable business reference for the expected paymentUsed for business idempotency within an organization
PaymentIntent.sourceAmountrequiredfirst_classExpected amount leaving the source side1000.00
PaymentIntent.sourceCurrencyrequiredfirst_classCurrency or token expected on the source sideUSD, USDC
PaymentIntent.destinationAmountrequiredfirst_classExpected amount at the beneficiary/destination side82500.00
PaymentIntent.destinationCurrencyrequiredfirst_classCurrency or token expected at the destination sideINR, MXN, USDC
PaymentIntent.paymentTypeoptionalfirst_classBroad payment categorystablecoin, bank, cross_border, other
PaymentIntent.paymentSubtypeoptionalfirst_classNarrow rail, corridor, or provider subtypewire, swift, usd_mxn, polygon_usdc
PaymentIntent.directionoptionalfirst_classDirection from the client’s perspectivedebit, credit
PaymentIntent.effectiveDateoptionalfirst_classBusiness effective date for the expected paymentNot the same as ingestion time
PaymentIntent.beneficiaryAccountoptionalfirst_classDestination account, wallet, or payout identifier
PaymentIntent.beneficiaryNameoptionalfirst_classBeneficiary display name
PaymentIntent.stablecoinoptionalfirst_classToken symbol when the expectation is stablecoin-specificUSDC
PaymentIntent.chainoptionalfirst_classChain or network label when knownpolygon
PaymentIntent.referencesoptionaljsonStructured references attached to the expected paymentNot an import mapping target β€” excluded from import mapping
PaymentIntent.metadataoptionaljsonClient-specific context not part of standard matchingcost_center, batch_id, corridor. Not an import mapping target
Both sourceTypes for every PaymentIntent field are ['client_internal_ledger', 'api_expectation'].

RawRecord fields

Populated for every ingested record before normalization, from any evidence source type (client_transfer_report, client_internal_ledger, bank_statement, onchain_report, psp_report, manual).
Field pathRequirementStorageDescriptionExamples / Notes
RawRecord.sourcerequiredfirst_classIngestion channelfile, api, webhook, manual
RawRecord.sourceTypeoptionalfirst_classBusiness category of the sourcee.g. bank_statement, psp_report, onchain_report
RawRecord.provideroptionalfirst_classVendor or provider labelbridge, bvnk, icici, alchemy. Not valid for client_transfer_report/client_internal_ledger
RawRecord.integrationKeyoptionalfirst_classTechnical connector identitybridge:webhook, icici:daily-xlsx. Same source-type restriction as provider
RawRecord.sourceRefrequiredfirst_classStable source-side identifierprovider id, tx hash, file row id
RawRecord.payloadrequiredjsonUntouched source payloadNever edited; not an import mapping target
RawRecord.rowNumberoptionalfirst_classSource row number for filesUsed for row-level import feedback. Not valid for manual

FlowLeg fields

Populated when the source represents actual money movement: bank statement row, PSP/provider transfer event, on-chain transfer event, or payout confirmation.
Field pathRequirementStorageDescriptionExamples / Notes
FlowLeg.typerequiredfirst_classType of actual money movementprovider_transfer, onchain_transfer, bank_transfer
FlowLeg.phaseoptionalfirst_classRole of the leg inside a multi-step routesource, intermediary_in, transfer, intermediary_out, destination
FlowLeg.statusoptionalfirst_classStatus of this movement legpending, confirmed, failed, reversed, missing
FlowLeg.reconciliationScopeoptionalfirst_classWhether this leg is required, optional, or ignored for completenessrequired, optional, ignored
FlowLeg.routeGroupIdoptionalfirst_classGroups legs that belong to one route or retry path
FlowLeg.sequenceoptionalfirst_classOrder of this leg inside a route group
FlowLeg.providerTransferIdoptionalfirst_classHigh-value provider transfer identifierValid for client_transfer_report, psp_report, manual
FlowLeg.txHashoptionalfirst_classOn-chain transaction hashValid for onchain_report, psp_report, manual
FlowLeg.chainIdoptionalfirst_classNumeric chain identifier137. Valid for onchain_report, psp_report, manual
FlowLeg.fromAddressoptionalfirst_classOn-chain sender addressValid for onchain_report, manual
FlowLeg.toAddressoptionalfirst_classOn-chain receiver addressValid for onchain_report, manual
FlowLeg.tokenAddressoptionalfirst_classToken contract addressValid for onchain_report, manual
FlowLeg.provideroptionalfirst_classVendor or provider label for the normalized legNot valid for client_transfer_report
FlowLeg.integrationKeyoptionalfirst_classTechnical connector identity for the normalized legSame restriction as provider
FlowLeg.amountoptionalfirst_classAmount moved on this leg
FlowLeg.currencyoptionalfirst_classCurrency or token moved on this legUSD, USDC, INR
FlowLeg.occurredAtoptionalfirst_classWhen the movement happened
FlowLeg.metadataoptionaljsonExtra leg context not part of standard matchingNot an import mapping target
FlowLeg.type, .phase, .status, .reconciliationScope, .routeGroupId, .sequence, .amount, .currency, .occurredAt, and .metadata all share sourceTypes: ['client_transfer_report', 'bank_statement', 'onchain_report', 'psp_report', 'manual'].

FlowLegReference fields β€” typed long-tail identifiers

Use FlowLegReference for identifiers that should be searchable but shouldn’t become new nullable columns on FlowLeg.
Field pathRequirementStorageDescriptionExamples
FlowLegReference.typerequiredreferenceIdentifier type for long-tail leg referencesbank_reference, ach_trace_number, uetr, sepa_reference
FlowLegReference.valuerequiredreferenceIdentifier value for long-tail leg references

Typed reference mapping target: FlowLegReference.<referenceType>

Import profiles can target FlowLegReference.<referenceType> (e.g. FlowLegReference.bank_reference, FlowLegReference.uetr) directly. This is a synthetic mapping target β€” getSupportedImportMappingTargetsForSourceType() adds it for every source type that supports FlowLegReference.
Legacy normalization: mapping targets of the form references.<type> (e.g. references.bank_reference) are automatically normalized to FlowLegReference.<type> by normalizeImportMappingTargetPath(). New mappings should use the FlowLegReference.<type> form directly.

ReconciliationCase fields β€” system-written, not import targets

These fields are written by the matcher/evaluator (apps/api/src/services/matcher.ts), never by import mappings. All have requirement: 'system' and are excluded from getSupportedImportMappingTargetsForSourceType().
Field pathDescriptionWritten from
ReconciliationCase.expectedAmountExpected case amount, usually copied from PaymentIntent.sourceAmountSet when the case is created
ReconciliationCase.actualAmountObserved reconciled amountThe selected leg’s amount (selectCaseEvaluationLeg)
ReconciliationCase.providerFeeProvider fee component for delta breakdownpayload.event_object.receipt.developer_fee, or prior value
ReconciliationCase.networkFeeNetwork/chain fee component for delta breakdownpayload.event_object.receipt.gas_fee, or prior value
ReconciliationCase.developerFeePlatform/developer fee component for delta breakdownPrior value (not refreshed by the matcher today)
ReconciliationCase.fxSpreadFX variance/spread component for delta breakdownpayload.event_object.receipt.exchange_fee, or prior value
ReconciliationCase.roundingDeltaRounding component for delta breakdownPrior value (not refreshed by the matcher today)
ReconciliationCase.unexplainedDeltaRemaining unexplained amount after known deltasreconcile() output β€” the key ops review field
sourceTypes for these fields reflects which evidence kinds can plausibly produce the underlying fee data: providerFee/developerFee ← psp_report/manual; networkFee ← onchain_report/manual; fxSpread/roundingDelta ← client_transfer_report/psp_report/manual; expectedAmount ← client_internal_ledger/api_expectation; actualAmount/unexplainedDelta ← any evidence source type.

Import mapping target rules

isSupportedImportMappingTarget(sourceType, path) decides whether a path is a valid value in ImportProfile.fieldMappings for a given sourceType. A path is valid if:
  1. It’s a canonical field whose sourceTypes includes the requested sourceType, and it is not in the import-mapping-excluded set (PaymentIntent.references, PaymentIntent.metadata, RawRecord.source, RawRecord.payload, RawRecord.rowNumber, FlowLeg.metadata, FlowLegReference.type, FlowLegReference.value, and every ReconciliationCase.* field), or
  2. It normalizes (via normalizeImportMappingTargetPath) to FlowLegReference.<referenceType> with a non-empty referenceType, and that source type supports FlowLegReference as a mapping target.

ImportSourceType β†’ primary downstream model

ImportSourceTypePrimary downstream target
client_internal_ledgerPaymentIntent and ReconciliationCase (expectation-first)
client_transfer_reportUsually FlowLeg, sometimes supporting evidence
bank_statementFlowLeg (evidence-first)
psp_reportFlowLeg (evidence-first)
onchain_reportFlowLeg (evidence-first)
manualDepends on manual entry type

List canonical fields

GET /v1/canonical-fields API reference.

Core Concepts

What each model represents in the reconciliation lifecycle.