Hanzo
Hanzo Skills Reference

Hanzo Reconciliation

Hanzo Reconciliation is an automated transaction matching engine that compares ledger balances against payment provider data to verify financial consistency and identify discrepancies. It runs as a...

Overview

Hanzo Reconciliation is an automated transaction matching engine that compares ledger balances against payment provider data to verify financial consistency and identify discrepancies. It runs as a standalone HTTP service backed by PostgreSQL, with policies that define how and when to reconcile ledger and payment data. Part of the Hanzo treasury stack.

Why Hanzo Reconciliation?

  • Policy-based matching -- Define reconciliation rules per payment provider and ledger
  • Drift detection -- Computes driftBalances showing exact differences between ledger and payments
  • Multi-provider -- Reconcile across Stripe, Adyen, bank feeds, and 50+ payment connectors
  • OpenAPI spec -- Full OpenAPI 3.0.3 definition for all endpoints
  • OpenTelemetry -- Built-in tracing (OTLP) and metrics export
  • Auto-migration -- Database migrations with --auto-migrate flag or dedicated migrate command

Tech Stack

  • Language: Go 1.24
  • HTTP: go-chi/chi v5
  • ORM: uptrace/bun (PostgreSQL via pgdialect)
  • DI: uber/fx
  • CLI: spf13/cobra
  • Auth: OAuth2 client credentials (Formance SDK)
  • Observability: OpenTelemetry (traces + metrics)
  • Testing: testify + gomock + dockertest (PostgreSQL integration tests)
  • Build: goreleaser + Earthly

OSS Base

Repo: hanzoai/reconciliation (Formance reconciliation fork). Go module path is github.com/formancehq/reconciliation (upstream module name retained).

Architecture Context

hanzo/commerce    Storefront, catalog, orders
       |
hanzo/payments    Payment routing (50+ processors)
       |
hanzo/treasury    Ledger, reconciliation, wallets   <-- this service
       |
lux/treasury      On-chain treasury, MPC/KMS wallets

When to use

  • Verifying ledger balances match payment provider records
  • Detecting discrepancies between internal ledger and external payment data
  • Automating periodic reconciliation across multiple payment providers
  • Generating compliance-ready reconciliation audit reports
  • Matching transactions at specific points in time for both ledger and payments

Hard requirements

  1. PostgreSQL (v12+) for policy and reconciliation result storage
  2. Formance Stack (ledger + payments services) for data sources
  3. Go 1.24+ for building from source

Quick reference

ItemValue
Go modulegithub.com/formancehq/reconciliation
Default port:8080
API versionv1 (prefixed in OpenAPI)
Default branchmain
Binaryreconciliation
Imageghcr.io/formancehq/base:22.04 (base)
Repogithub.com/hanzoai/reconciliation

One-file quickstart

Build and run

# Build
go build -o ./bin/reconciliation .

# Run with auto-migrate
./bin/reconciliation serve \
  --postgres-uri "postgresql://user:pass@localhost:5432/reconciliation" \
  --stack-url "http://localhost:8080" \
  --stack-client-id "client-id" \
  --stack-client-secret "client-secret" \
  --auto-migrate \
  --listen ":8080"

Create a reconciliation policy

curl -X POST http://localhost:8080/policies \
  -H "Content-Type: application/json" \
  -d '{
    "name": "stripe-daily",
    "ledgerName": "default",
    "ledgerQuery": {"$match": {"metadata[provider]": "stripe"}},
    "paymentsPoolID": "stripe-pool"
  }'

Trigger reconciliation

curl -X POST http://localhost:8080/policies/{policyID}/reconciliation \
  -H "Content-Type: application/json" \
  -d '{
    "reconciledAtLedger": "2026-03-13T00:00:00.000Z",
    "reconciledAtPayments": "2026-03-13T00:00:00.000Z"
  }'

Check results

# List all reconciliation results
curl http://localhost:8080/reconciliations

# Get specific result
curl http://localhost:8080/reconciliations/{reconciliationID}

Core Concepts

Data Model

Policy
  |-- id, name, createdAt
  |-- ledgerName          (which ledger to query)
  |-- ledgerQuery         (filter for ledger transactions)
  |-- paymentsPoolID      (which payment pool to compare against)

Reconciliation
  |-- id, policyID, createdAt
  |-- reconciledAtLedger      (point-in-time for ledger snapshot)
  |-- reconciledAtPayments    (point-in-time for payments snapshot)
  |-- status                  (COMPLETED, FAILED, etc.)
  |-- ledgerBalances          (map[asset]bigint from ledger)
  |-- paymentsBalances        (map[asset]bigint from payments)
  |-- driftBalances           (map[asset]bigint -- the difference)
  |-- error                   (if status is FAILED)

API Endpoints (OpenAPI 3.0.3)

MethodPathPurposeAuth Scope
GET/_infoServer version inforeconciliation:read
POST/policiesCreate a reconciliation policyreconciliation:write
GET/policiesList policies (paginated)reconciliation:read
GET/policies/{policyID}Get a single policyreconciliation:read
DELETE/policies/{policyID}Delete a policyreconciliation:write
POST/policies/{policyID}/reconciliationRun reconciliationreconciliation:write
GET/reconciliationsList reconciliation resultsreconciliation:read
GET/reconciliations/{reconciliationID}Get a single resultreconciliation:read

Pagination

Cursor-based pagination on list endpoints:

GET /policies?pageSize=15&cursor=base64EncodedCursor

Response includes cursor.hasMore, cursor.next, cursor.previous.

CLI Commands

reconciliation serve      # Start HTTP server
reconciliation migrate    # Run database migrations
reconciliation version    # Print version info

Serve Flags

--listen              HTTP listen address (default ":8080")
--stack-url           Formance stack URL (for ledger + payments API)
--stack-client-id     OAuth2 client ID for stack API
--stack-client-secret OAuth2 client secret for stack API
--auto-migrate        Auto-run database migrations on startup
--postgres-uri        PostgreSQL connection string

Directory structure

github.com/hanzoai/reconciliation/
    main.go                          # Entrypoint (calls cmd.Execute())
    openapi.yaml                     # OpenAPI 3.0.3 spec (full API definition)
    Justfile                         # Build commands (test, lint, build, release)
    build.Dockerfile                 # Production container image
    scratch.Dockerfile               # Minimal scratch-based image
    Earthfile                        # Earthly build definition
    .goreleaser.yml                  # Cross-platform release config
    cmd/
        root.go                      # CLI root command, service name, flags
        serve.go                     # HTTP server with fx DI, OAuth2 stack client
        migrate.go                   # Database migration command
        version.go                   # Version info command
    internal/
        api/
            router.go                # Chi router setup
            module.go                # fx HTTP module
            policy.go                # Policy CRUD handlers
            reconciliation.go        # Reconciliation run + query handlers
            query.go                 # Query builder helpers
            utils.go                 # HTTP response utilities
            backend/                 # Backend service interface + mock
            service/                 # Business logic layer
            policy_test.go           # Policy handler tests
            reconciliation_test.go   # Reconciliation handler tests
        models/
            policy.go                # Policy domain model
            reconciliation.go        # Reconciliation domain model
        storage/
            store.go                 # Store interface
            module.go                # fx storage module
            policy.go                # Policy DB queries (bun)
            reconciliations.go       # Reconciliation DB queries (bun)
            error.go                 # Storage error types
            ping.go                  # Database health check
            utils.go                 # Query utilities
            migrations/              # SQL migration files
            main_test.go             # Test harness (dockertest PostgreSQL)
            policy_test.go           # Policy storage tests
            reconciliations_test.go  # Reconciliation storage tests

Troubleshooting

IssueCauseSolution
Connection refused on startupPostgreSQL not reachableCheck --postgres-uri and network
Migration failsSchema conflictsRun reconciliation migrate standalone first
OAuth2 token errorWrong stack credentialsVerify --stack-client-id and --stack-client-secret
Empty drift balancesNo matching transactionsCheck ledgerQuery filter matches actual ledger data
Module path confusionUpstream module nameImport as github.com/formancehq/reconciliation
  • hanzo/hanzo-numscript.md - DSL for modeling the transactions being reconciled
  • hanzo/hanzo-billing.md - Billing and subscription management

How is this guide?

Last updated on

On this page