Skip to main content
ReconLayer’s persistence layer (packages/db/prisma/schema.prisma) is PostgreSQL via Prisma. packages/db owns the schema exclusively — HTTP handlers (apps/api) and the pure matching logic (packages/reconciliation-engine) never execute SQL directly. This page documents the actual tables, enums, and relations as defined in schema.prisma.
Five design rules are baked into this schema (from the schema header comments):
  1. raw_records.payload is jsonb, never edited, never deleted.
  2. match_links.match_reason is human-readable text, not a code.
  3. reconciliation_cases keeps expected, actual, fee, FX, rounding, and unexplained_delta as separate columns — nothing is collapsed into one number.
  4. Every state change is logged in audit_events. Append-only.
  5. Amounts use Decimal(38, 18) — wide enough for 18-decimal stablecoin values without losing fractional cents.

Entity relationship overview

payment_intents (PaymentIntent)

What the customer asks ReconLayer to reconcile. Constraints & indexes: @@unique([organizationId, externalReference]) — the idempotency key for the intake endpoint (nullable externalReference values don’t conflict with each other). Indexed on organizationId, (organizationId, status), externalReference, and createdAt. Relations: legs: FlowLeg[], reconciliationCase: ReconciliationCase? (1:1), rawRecords: RawRecord[], auditEvents: AuditEvent[], intentReferences: PaymentIntentReference[].

payment_intent_references (PaymentIntentReference)

Typed identifiers attached to an expectation, used by the matcher to find candidates by provider_transfer_id or tx_hash. Unique on (organizationId, type, value) and (paymentIntentId, type, value). Indexed on organizationId, paymentIntentId, and (organizationId, type, value).

raw_records (RawRecord)

Every payload ingested, untouched, forever. Constraints & indexes: @@unique([organizationId, source, sourceRef]) — tenant-scoped idempotent ingestion. Indexed on organizationId, paymentIntentId, importBatchId, receivedAt, (source, receivedAt), sourceType, (organizationId, provider), (organizationId, integrationKey). A GIN index on payload is added via migration SQL for ad-hoc JSONB querying. Relations: paymentIntent: PaymentIntent?, importBatch: ImportBatch?, flowLegs: FlowLeg[] (relation name LegFromRawRecord), matchLinks: MatchLink[], auditEvents: AuditEvent[].

flow_legs (FlowLeg)

Normalized legs where value actually moved. Indexes: organizationId, paymentIntentId, routeGroupId, providerTransferId, txHash, (paymentIntentId, sequence), (organizationId, provider), (organizationId, integrationKey), (type, status), receivedAt. Relations: paymentIntent: PaymentIntent?, rawRecord: RawRecord? (relation LegFromRawRecord), matchLinks: MatchLink[], legReferences: FlowLegReference[].

flow_leg_references (FlowLegReference)

Unique on (flowLegId, type, value). Indexed on organizationId, flowLegId, and (organizationId, type, value).

reconciliation_cases (ReconciliationCase)

One per PaymentIntent — the truth row. Indexes: organizationId, (organizationId, status), (organizationId, reconciliationStatus), (organizationId, exceptionType), unexplainedDelta. Relations: paymentIntent: PaymentIntent?, matchLinks: MatchLink[], auditEvents: AuditEvent[].

ExceptionType enum

Explainable links between raw records, flow legs, and cases. Constraints: @@unique([caseId, legId, rawRecordId]) — idempotent linking (the matcher upserts on this key). Indexed on organizationId, caseId, legId.

reconciliation_rules (ReconciliationRule)

Per-organization matching tolerances and behavior — see Reconciliation Rules for how each field is used. Indexed on organizationId, (organizationId, isActive), (organizationId, paymentType), (organizationId, sourceType).

audit_events (AuditEvent)

Append-only log of everything the system did. Indexed on organizationId, paymentIntentId, caseId, rawRecordId, importBatchId, eventType, occurredAt. Relations to PaymentIntent?, ReconciliationCase?, RawRecord?, ImportBatch?.

Import pipeline tables

import_profiles (ImportProfile)

Saved mapping/parsing rule sets for file onboarding. Indexed on organizationId, (organizationId, sourceType), (organizationId, provider), (organizationId, integrationKey). Relation: importBatches: ImportBatch[].

import_batches (ImportBatch)

One uploaded file or import job. @@unique([organizationId, fileHash]). Indexed on organizationId, (organizationId, status), importProfileId, createdByUserId, (organizationId, provider), (organizationId, integrationKey). Relations: importProfile: ImportProfile?, rawRecords: RawRecord[], auditEvents: AuditEvent[]. ImportBatchStatus: uploaded, mapping_required, parsing, validating, processing, completed, failed. ImportSourceType (also used as RawRecord.sourceType and ReconciliationRule.sourceType): client_transfer_report, client_internal_ledger, bank_statement, onchain_report, psp_report, manual.

Operational and platform tables

These tables support API access, integrations, outbound webhooks, org settings, and UI preferences. They are not part of the reconciliation data model but share the same database.

Schema migrations

Because core-model (canonical shape types and Zod schemas) is separate from db (Prisma persistence types), the reconciliation engine and most service-layer logic can be tested without a database.

Core Concepts

What each table represents in the reconciliation lifecycle.

Canonical Field Registry

Field-by-field mapping targets for import profiles and adapters.