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.

Hanzo Reconciliation - Transaction Auto-Matching Engine

Category: Hanzo Ecosystem Related Skills: hanzo/hanzo-numscript.md, hanzo/hanzo-billing.md

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?

Tech Stack

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

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

| Item | Value | |------|-------| | Go module | github.com/formancehq/reconciliation | | Default port | :8080 | | API version | v1 (prefixed in OpenAPI) | | Default branch | main | | Binary | reconciliation | | Image | ghcr.io/formancehq/base:22.04 (base) | | Repo | github.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)

| Method | Path | Purpose | Auth Scope | |--------|------|---------|------------| | GET | /_info | Server version info | reconciliation:read | | POST | /policies | Create a reconciliation policy | reconciliation:write | | GET | /policies | List policies (paginated) | reconciliation:read | | GET | /policies/{policyID} | Get a single policy | reconciliation:read | | DELETE | /policies/{policyID} | Delete a policy | reconciliation:write | | POST | /policies/{policyID}/reconciliation | Run reconciliation | reconciliation:write | | GET | /reconciliations | List reconciliation results | reconciliation:read | | GET | /reconciliations/{reconciliationID} | Get a single result | reconciliation: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

| Issue | Cause | Solution | |-------|-------|----------| | Connection refused on startup | PostgreSQL not reachable | Check --postgres-uri and network | | Migration fails | Schema conflicts | Run reconciliation migrate standalone first | | OAuth2 token error | Wrong stack credentials | Verify --stack-client-id and --stack-client-secret | | Empty drift balances | No matching transactions | Check ledgerQuery filter matches actual ledger data | | Module path confusion | Upstream module name | Import as github.com/formancehq/reconciliation |

Related Skills


Last Updated: 2026-03-13 Category: Hanzo Ecosystem Related: fintech, reconciliation, accounting, payments, ledger, go Prerequisites: PostgreSQL 12+, Go 1.24+, Formance stack (ledger + payments)