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

# Clearinghouse Integration

> Integration contract for PM clearinghouse adapters, transaction flow, tenant-safe credential handling, and Phase 2 production transport.

# Clearinghouse Integration — Integration

**Version:** 2.0.0\
**Status:** 📝 Planned\
**Last Updated:** 2026-03-27\
**Spec (Phase 1):** [PM-15 Clearinghouse Integration](../../../specs/pm/specs/PM-15-clearinghouse-integration.md)\
**Spec (Phase 2):** [PM-15-P2 Production Clearinghouse Transport](../../../specs/pm/contexts/PM-15-PHASE-2-EXPANSION.md)\
**Constitution Reference:** Section 1.3 (Integration Patterns), Section 2.1 (Integration points documented in `/docs/architecture/integrations/`)

***

## Quick Reference

| I need to…                          | Pattern                                       | Location                                                     |
| ----------------------------------- | --------------------------------------------- | ------------------------------------------------------------ |
| Submit a claim batch (SFTP)         | `ClearinghouseAdapter.submitBatchFile()`      | `supabase/functions/_shared/transport/` (Phase 2a)           |
| Submit a single claim (REST API)    | `ClearinghouseAdapter.submitClaim()`          | `src/cores/pm/types/clearinghouse.ts`                        |
| Retrieve ERA/835 from clearinghouse | `ClearinghouseAdapter.fetchRemittance()`      | Same adapter interface                                       |
| Check eligibility via 270/271       | `ClearinghouseAdapter.checkEligibility()`     | Same adapter interface                                       |
| Generate X12 837P from claims       | `generate837P(claims, config)`                | `supabase/functions/_shared/x12/generate-837p.ts` (Phase 2b) |
| Parse 835 ERA file                  | `parse835(x12Content)`                        | `supabase/functions/_shared/x12/parse-835.ts` (Phase 2b)     |
| Configure clearinghouse connection  | `pm_clearinghouse_config` table               | `PM-15-T1` migration                                         |
| Schedule batch submission           | `pm_clearinghouse_config.submission_schedule` | Phase 2a migration                                           |
| View connection health              | `pm_clearinghouse_config.health_status`       | Phase 2c; gated by `pm.clearinghouse.view`                   |
| View transaction audit log          | `pm_transaction_log` (append-only)            | RLS: SELECT only                                             |

***

## Decision Tree

* **Need to submit a claim electronically?**
  → Use PM-15 `ClearinghouseAdapter.submitClaim()` via PM-08 claim workflow.
  → Credentials resolved from vault refs at runtime; never stored in code.

* **Need to process an ERA/835?**
  → Use `ClearinghouseAdapter.fetchRemittance()` → parse → feed PM-09 payment posting.
  → 835 SVC segments map to `pm_claim_lines`.

* **Need to check eligibility in real-time?**
  → Use `ClearinghouseAdapter.checkEligibility()` for 270/271 (PM-02 integration).

***

## Common Mistakes

| Symptom                             | Fix                                                                                   |
| ----------------------------------- | ------------------------------------------------------------------------------------- |
| Credentials in code or migration    | Store as vault refs in `pm_clearinghouse_config`; resolve at runtime in edge function |
| Missing org filter on batch queries | Add `.eq('organization_id', orgId)` to all mutations                                  |
| Editing `pm_transaction_log` rows   | Table is append-only; RLS denies UPDATE/DELETE                                        |
| Direct import from PM-08 hooks      | Use adapter interface; PM-15 is invoked by PM-08, not the reverse                     |

***

## Pre-Flight Checklist

* [ ] PM-08 and PM-09 schemas exist (claims, claim\_lines, payments)
* [ ] Vault refs configured for clearinghouse credentials
* [ ] RLS enabled with FORCE on all four tables
* [ ] UPDATE policies include WITH CHECK
* [ ] No secrets in code, migrations, or docs

***

## Overview

PM-15 provides clearinghouse connectivity for ANSI X12 transactions (837P/I, 835, 270/271, 276/277, 278, 999/277CA). It defines the data model (`pm_clearinghouse_config` with clearinghouse\_provider, sender\_id, receiver\_id, connection\_type, vault refs, host/port/paths or api\_endpoint; `pm_transaction_batches`, `pm_transaction_log`, `pm_payer_enrollments`), RLS, and the generic `ClearinghouseAdapter` interface. Implementations (Waystar first, then Availity, Change Healthcare, etc.) are configured per organization; credentials are stored in vault only.

***

## Integration Points

| Dependency                 | Pattern    | Purpose                                                                                                                                   |
| -------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **PM-08**                  | Data / API | Claim submission: PM-08 builds claim and invokes adapter `submitClaim()`; 999/277CA and line-level rejections feed PM-08 denial workflow. |
| **PM-09**                  | Data / API | ERA retrieval: adapter `fetchRemittance()` returns 835; SVC segments map to `pm_claim_lines`; line-level posting.                         |
| **PM-02**                  | API        | Eligibility: adapter `checkEligibility()` for 270/271 (when supported by clearinghouse).                                                  |
| **PM-10**                  | API        | Prior auth: adapter `submitPriorAuth()` for 278 (when supported).                                                                         |
| **External clearinghouse** | API / SFTP | Waystar (and future adapters): REST or sFTP per `pm_clearinghouse_config.connection_type`; credentials via vault refs.                    |

***

## API / Adapter Contract

Clearinghouse adapter interface is defined in [X12 EDI Technical Design](../../../docs/architecture/standards/X12-EDI-TECHNICAL-DESIGN.md).

### Phase 1 methods (adapter interface)

| Method                              | Description                                                    |
| ----------------------------------- | -------------------------------------------------------------- |
| `submitClaim(claimId, payload)`     | 837P/I REST per-claim submission; returns trace/reference      |
| `fetchRemittance(config)`           | Retrieve 835 file; returns raw X12 content for Phase 2b parser |
| `checkEligibility(config, request)` | 270/271 eligibility inquiry/response (PM-02)                   |
| `checkClaimStatus(config, traceId)` | 276/277 claim status inquiry/response                          |
| `submitPriorAuth(config, request)`  | 278 prior auth (PM-10; Phase 3)                                |
| `validateCredentials(config)`       | SFTP handshake or API ping for health check                    |
| `getSubmissionWindow()`             | Submission window per clearinghouse                            |

### Phase 2a additions (transport layer)

| Method                                          | Description                                                                                      | Location                                                         |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| `submitBatchFile(config, x12Content, fileName)` | SFTP batch file upload; returns remote file path                                                 | `supabase/functions/_shared/transport/sftp-transport.ts`         |
| `downloadFile(config, remoteFileName)`          | SFTP file download; returns raw file content                                                     | Same                                                             |
| Waystar OAuth2 token                            | Acquired and cached per invocation via `waystar-rest-transport.ts`                               | `supabase/functions/_shared/transport/waystar-rest-transport.ts` |
| Retry logic                                     | Exponential backoff (2s, 4s, 8s); max 3 retries; dead-letter → `clearinghouse_batch_error` event | `supabase/functions/_shared/transport/retry.ts`                  |

### Phase 2b additions (X12 utilities — shared, pure TypeScript)

| Utility                        | Input                                        | Output                                         | Location                       |
| ------------------------------ | -------------------------------------------- | ---------------------------------------------- | ------------------------------ |
| `generate837P(claims, config)` | `pm_claims` + `pm_claim_lines` + COB (PM-30) | X12 837P string                                | `_shared/x12/generate-837p.ts` |
| `parse835(x12Content)`         | Raw 835 X12 string                           | `pm_era_files` metadata + CLP/SVC payment data | `_shared/x12/parse-835.ts`     |
| `generate270(config, request)` | Eligibility inquiry params                   | X12 270 string                                 | `_shared/x12/generate-270.ts`  |
| `parse271(x12Content)`         | Raw 271 X12 string                           | Structured eligibility response                | `_shared/x12/parse-271.ts`     |
| `parse999(x12Content)`         | Raw 999 X12 string                           | Functional ack status + error codes            | `_shared/x12/parse-999.ts`     |
| `parse277CA(x12Content)`       | Raw 277CA X12 string                         | Line-level rejection statuses                  | `_shared/x12/parse-277ca.ts`   |
| `buildEnvelope(params)`        | ISA/GS/ST params                             | X12 envelope segments                          | `_shared/x12/envelope.ts`      |

### 835 parser → PM-09 interface

The Phase 2b 835 parser writes to PM-09-owned tables:

1. Creates `pm_era_files` record: `file_name`, `received_date`, `payer_id` (from GS/TRN), `check_eft_number`, `total_paid`, `claim_count`, `status = 'received'`
2. Emits `clearinghouse_era_received` event (payload below) for PM-09 to pick up
3. PM-09 payment posting pipeline consumes the event and creates `pm_payments` + `pm_payment_applications`

```typescript theme={null}
// clearinghouse_era_received event payload
interface ClearinghouseEraReceivedPayload {
  era_file_id: string;        // pm_era_files.id just created
  organization_id: string;
  batch_id: string;           // pm_transaction_batches.id
  claim_count: number;
  total_paid: number;
}
```

Downstream consumers must resolve the Supabase storage object path from `era_file_id`.

## Pattern Library

* **Adapter abstraction pattern:** PM workflows call `ClearinghouseAdapter` methods, not vendor SDKs directly.
* **Vault reference pattern:** runtime credential resolution from `pm_clearinghouse_config`, never plaintext secrets in code.
* **Append-only ledger pattern:** `pm_transaction_log` is immutable and used for traceability.

```typescript theme={null}
// Example: PM workflow invocation using tenant-scoped config + adapter
const { data: config } = await supabase
  .from('pm_clearinghouse_config')
  .select('*')
  .eq('organization_id', orgId)
  .single();

const credentials = await resolveVaultCredentials(config); // resolves vault refs at runtime

await clearinghouseAdapter.submitClaim(claimId, payload, { credentials });
await clearinghouseAdapter.fetchRemittance({ organizationId: orgId, credentials });
await clearinghouseAdapter.checkEligibility({ organizationId: orgId, credentials }, eligibilityRequest);
```

***

## Event Contracts

Events are defined in [EVENT\_CONTRACTS.md](./EVENT_CONTRACTS.md). Phase 2 adds the following:

| Event                           | Emitter                                                | Consumers                                                        | Payload                                                                       |
| ------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `clearinghouse_batch_submitted` | `clearinghouse-submit` edge fn                         | PM-08 (batch status tracking)                                    | `{ batch_id, organization_id, claim_count, transport_type: 'sftp' \| 'api' }` |
| `clearinghouse_batch_error`     | `clearinghouse-submit` (dead-letter after 3 retries)   | PM-08 (denial routing), PF-10 (billing admin alert)              | `{ batch_id, organization_id, transport_error: string, retry_count: number }` |
| `clearinghouse_era_received`    | `clearinghouse-retrieve` after creating `pm_era_files` | PM-09 (payment posting)                                          | `{ era_file_id, organization_id, batch_id, claim_count, total_paid }`         |
| `clearinghouse_health_changed`  | `clearinghouse-health-check` on status transition      | PF-10 (alert on down/degraded; throttled recovery on 2× healthy) | `{ config_id, organization_id, old_status, new_status, checked_at }`          |

> **Note:** `clearinghouse_batch_submitted` and `clearinghouse_batch_error` were defined in Phase 1 (PM-15 Errata F-5). `clearinghouse_era_received` and `clearinghouse_health_changed` are new in Phase 2.

### Phase 2c: Connection Health Monitoring

The `clearinghouse-health-check` edge function runs every 30 minutes (Supabase cron) and performs a connection test (SFTP handshake via `validateCredentials()` or Waystar API ping):

* On status change → updates `pm_clearinghouse_config.health_status` and `last_health_check_at`
* On `down` or `degraded` → emits `clearinghouse_health_changed` immediately; PF-10 alert fired
* On recovery to `healthy` → requires 2 consecutive healthy checks before emitting recovery event (anti-flap throttle)
* Health badge in UI is gated by `pm.clearinghouse.view`

***

## Security & Tenant Isolation

* All clearinghouse tables are scoped by `organization_id`; RLS and SECURITY DEFINER helpers enforce isolation.
* Credentials stored in vault only; config holds vault refs; resolution at runtime in edge function or backend.
* PHI in 837/835: encrypt in transit (TLS); audit access to batch and transaction log.

***

## References

* [PM-15: Clearinghouse Integration](../../../specs/pm/specs/PM-15-clearinghouse-integration.md) — Phase 1 (tables, RLS, adapter interface, UI stubs)
* [PM-15-P2: Production Clearinghouse Transport](../../../specs/pm/contexts/PM-15-PHASE-2-EXPANSION.md) — Phase 2 (transport, X12, health monitoring)
* [PM-15: Clearinghouse Vendor Selection & Waystar-First Integration](../../../specs/pm/decisions/PM-15-clearinghouse-vendor-selection-waystar-integration.md)
* [PM-09: Payment Posting & ERA Processing](../../../specs/pm/specs/PM-09-payment-posting-era-processing.md) — `pm_era_files`, `pm_payments`, `pm_payment_applications` schema
* [X12 EDI Technical Design](../../../docs/architecture/standards/X12-EDI-TECHNICAL-DESIGN.md)
* [REGULATORY\_COMPLIANCE\_TRACKER.md](../../../docs/compliance/REGULATORY_COMPLIANCE_TRACKER.md) — PM-15-P2 HIPAA EDI Transport row
