> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Midaz integration

> Connect Matcher to Midaz Ledger to query transactions directly and reconcile them against external sources without file exports.

<Info>
  **This integration is optional.** Matcher is a stand-alone product that works independently. Use this guide only if you want to integrate Matcher with Midaz Ledger.
</Info>

Matcher can integrate natively with Midaz Ledger, enabling seamless reconciliation of ledger transactions against external sources like bank statements and payment gateways.

## Overview

***

The Midaz integration provides:

* **Direct ledger access**: Query transactions directly from Midaz without file exports
* **Real-time sync**: Automatic transaction synchronization as entries are posted
* **Unified authentication**: Single auth system via lib-auth
* **Tenant isolation**: Schema-per-tenant architecture ensures data separation

## Prerequisites

***

Before configuring the Midaz integration:

* Midaz Ledger instance running and accessible
* API credentials with transaction read permissions
* Network connectivity between Matcher and Midaz
* Matching tenant configuration in both systems

## Configuration

***

### Environment variables

Configure Matcher to connect to your Midaz instance:

```bash theme={null}
# Midaz connection
MIDAZ_BASE_URL=https://api.midaz.example.com
MIDAZ_GRPC_ADDRESS=midaz-grpc.example.com:50051

# Authentication (shared with midaz)
AUTH_SERVICE_URL=https://auth.example.com
AUTH_CLIENT_ID=matcher-service
AUTH_CLIENT_SECRET=your-secret

# Connection settings
MIDAZ_CONNECTION_TIMEOUT=30s
MIDAZ_REQUEST_TIMEOUT=60s
MIDAZ_MAX_RETRIES=3
```

### Creating a Midaz source

Create a source with type `LEDGER` to connect to your Midaz ledger:

```json theme={null}
{
  "name": "Midaz Main Ledger",
  "type": "LEDGER",
  "config": {
    "ledger_id": "ldg_001",
    "account_filter": {
      "type": "ASSET",
      "path_prefix": "assets:cash"
    },
    "sync_mode": "realtime",
    "lookback_days": 30
  }
}
```

<Tip>API Reference: [Create source](/en/reference/matcher/create-source)</Tip>

### Source settings

| Setting                      | Type    | Description                                  |
| ---------------------------- | ------- | -------------------------------------------- |
| `ledger_id`                  | String  | Target ledger ID in Midaz                    |
| `account_filter.type`        | String  | Account type filter (ASSET, LIABILITY, etc.) |
| `account_filter.path_prefix` | String  | Account path prefix to include               |
| `account_filter.accounts`    | Array   | Specific account IDs to include              |
| `sync_mode`                  | String  | `realtime` or `batch`                        |
| `lookback_days`              | Integer | Days of historical data to include           |
| `exclude_pending`            | Boolean | Exclude pending entries                      |

## Authentication

***

Matcher uses the same authentication system as Midaz via the shared `lib-auth` library.

### Service-to-service auth

Matcher authenticates to Midaz using OAuth 2.0 client credentials:

```bash theme={null}
# Token exchange happens automatically
# Matcher requests: POST /oauth/token
{
 "grant_type": "client_credentials",
 "client_id": "matcher-service",
 "client_secret": "your-secret",
 "scope": "ledger:read transactions:read"
}
```

### Required scopes

| Scope               | Permission               |
| ------------------- | ------------------------ |
| `ledger:read`       | Read ledger metadata     |
| `transactions:read` | Read transaction entries |
| `accounts:read`     | Read account information |

### Tenant context

All requests include the tenant context header:

```
X-Tenant-ID: tenant_001
```

This ensures transactions are queried from the correct tenant schema.

## Querying transactions

***

### Automatic sync

With `sync_mode: realtime`, Matcher subscribes to Midaz events and receives transactions as they're posted. When a transaction is created in Midaz, it publishes an event to the message queue. Matcher consumes the event, stores the transaction locally, and queues it for matching—all without manual intervention.

<Frame caption="Event-driven ingestion for scalable reconciliation.">
  <img src="https://mintcdn.com/lerian-49cb71fc/UsUgoha8b-OkDZPH/images/en/docs/matcher-midaz-integration.jpg?fit=max&auto=format&n=UsUgoha8b-OkDZPH&q=85&s=02e7ac211fcfdaac0804520d43b27cb6" alt="Event-driven ingestion" width="1510" height="1034" data-path="images/en/docs/matcher-midaz-integration.jpg" />
</Frame>

### Query filters

Filter transactions when syncing:

```json theme={null}
{
  "date_from": "2024-01-01",
  "date_to": "2024-01-31",
  "filters": {
    "operation_types": [
      "CREDIT",
      "DEBIT"
    ],
    "min_amount": 100.0,
    "currencies": [
      "USD",
      "EUR"
    ],
    "metadata": {
      "source_system": "treasury"
    }
  }
}
```

## Transaction mapping

***

Midaz transactions are automatically mapped to Matcher's schema:

| Midaz Field             | Matcher Field    | Notes                         |
| ----------------------- | ---------------- | ----------------------------- |
| `id`                    | `transaction_id` | Unique entry ID               |
| `amount`                | `amount`         | Decimal amount                |
| `asset_code`            | `currency`       | ISO currency code             |
| `created_at`            | `date`           | Entry date                    |
| `description`           | `reference`      | Entry description             |
| `metadata.external_ref` | `external_id`    | External reference if present |
| `operation`             | `type`           | CREDIT or DEBIT               |

### Custom field mapping

Override default mapping for specific use cases:

```json theme={null}
{
  "settings": {
    "field_mapping": {
      "reference": "metadata.invoice_number",
      "counterparty": "metadata.vendor_name",
      "external_id": "metadata.bank_reference"
    }
  }
}
```

## Tenant isolation

***

Matcher inherits Midaz's schema-per-tenant isolation model.

### How it works

1. Each tenant has a dedicated PostgreSQL schema
2. All queries are scoped to the tenant's schema
3. Connection pooling maintains schema context
4. No cross-tenant data access is possible

```
Database: matcher_db
├── tenant_001 (schema)
│ ├── transactions
│ ├── matches
│ └── exceptions
├── tenant_002 (schema)
│ ├── transactions
│ ├── matches
│ └── exceptions
└── shared (schema)
 ├── field_maps
 └── rules_templates
```

### Tenant resolution

Tenant is determined from the authentication token:

```json theme={null}
{
  "sub": "user_123",
  "tenant_id": "tenant_001",
  "roles": [
    "reconciliation_admin"
  ]
}
```

## Error handling

***

### Connection errors

```json theme={null}
{
  "error": "MIDAZ_CONNECTION_ERROR",
  "message": "Failed to connect to Midaz at midaz-grpc.example.com:50051",
  "details": {
    "retry_count": 3,
    "last_error": "connection refused"
  },
  "suggestion": "Check network connectivity and Midaz service status"
}
```

### Authentication errors

```json theme={null}
{
  "error": "MIDAZ_AUTH_ERROR",
  "message": "Failed to authenticate with Midaz",
  "details": {
    "status_code": 401,
    "reason": "invalid_client"
  },
  "suggestion": "Verify client credentials and required scopes"
}
```

### Sync errors

```json theme={null}
{
  "error": "MIDAZ_SYNC_ERROR",
  "message": "Partial sync failure",
  "details": {
    "total_expected": 5000,
    "fetched": 4500,
    "failed_batches": [
      {
        "batch": 10,
        "error": "timeout"
      }
    ]
  },
  "suggestion": "Retry failed batches or increase timeout"
}
```

## Best practices

***

<AccordionGroup>
  <Accordion title="Use realtime sync for active reconciliation">
    Enable `sync_mode: realtime` for contexts with daily reconciliation. This ensures transactions are available for matching immediately after posting.
  </Accordion>

  <Accordion title="Filter by account path">
    Use `account_filter.path_prefix` to limit transactions to relevant accounts. This reduces data volume and improves matching performance.
  </Accordion>

  <Accordion title="Set appropriate lookback period">
    Configure `lookback_days` based on your reconciliation cycle. Daily reconciliation typically needs 7-14 days; monthly needs 45-60 days.
  </Accordion>

  <Accordion title="Monitor sync lag">
    Track the delay between Midaz posts and Matcher availability. High lag may indicate queue backup or processing issues.
  </Accordion>

  <Accordion title="Use metadata for matching">
    Store matching-relevant data in Midaz metadata fields (invoice numbers, bank references) and map them to Matcher fields for better match rates.
  </Accordion>
</AccordionGroup>

## Next steps

***

<CardGroup cols={2}>
  <Card title="External Sources" icon="building-columns" href="/en/matcher/integrations/matcher-external-sources">
    Connect to banks and payment processors.
  </Card>

  <Card title="Field Mapping" icon="arrows-left-right" href="/en/matcher/configuration/matcher-field-mapping">
    Configure how Midaz fields map to Matcher.
  </Card>
</CardGroup>
