# Relay Financial Integration

**Last updated:** 2026-03-19

## Overview

Relay (relayfi.com) is our business banking platform. We use a dedicated
Relay virtual debit card to pay state filing fees during automated business
formation. Relay does NOT have a public developer API, so integration is
via encrypted card storage + Playwright automation + Plaid for read-only
transaction data.

## Architecture

```
ERPNext (Sensitive ID)          Playwright                State Portal
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│ Relay card details│────►│ Formation worker  │────►│ Payment form     │
│ (AES encrypted)  │     │ enters card into  │     │ Card charged     │
│ card_number      │     │ state portal form │     │ Filing confirmed │
│ exp_month/year   │     └──────────────────┘     └──────────────────┘
│ cvv              │              │
│ billing_zip      │              ▼
└──────────────────┘     ┌──────────────────┐
                         │ filing_payments   │
                         │ table (PostgreSQL)│
                         │ card_last4, amount│
                         │ confirmation #    │
                         └──────────────────┘
                                  │
                                  ▼ (reconcile)
                         ┌──────────────────┐
                         │ Relay dashboard   │
                         │ or Plaid read-only│
                         │ transaction match │
                         └──────────────────┘
```

## Card Details Storage

Card details are stored in ERPNext's **Sensitive ID** DocType using the
Frappe Password fieldtype, which provides AES encryption at rest.

### Setup (One-time)

1. Log into ERPNext at crm.performancewest.net
2. Navigate to Sensitive ID → New
3. Set:
   - **Name:** `relay-filing-card`
   - **ID Type:** `DEBIT_CARD`
   - **Encrypted Value:** (paste JSON below)

```json
{
  "number": "4000123456789012",
  "exp_month": "12",
  "exp_year": "28",
  "cvv": "123",
  "name": "Performance West Inc",
  "zip": "82001"
}
```

4. Save — the value is encrypted by Frappe's Password field

### Runtime Flow

1. Job server receives a `file_entity` job
2. `relay_integration.populate_order_payment()` loads card from ERPNext
3. Card details are held in memory only (never logged, never written to disk)
4. Playwright enters card details into state portal payment form
5. After filing, card details are cleared from memory
6. `record_filing_payment()` logs the payment (card_last4 only) for reconciliation

## Payment Reconciliation

After each filing, a record is created in the `filing_payments` table:

| Field | Value |
|-------|-------|
| formation_order_id | Links to the order |
| state_code | Which state was paid |
| amount_cents | How much was charged |
| card_last4 | Last 4 digits for matching |
| portal_confirmation | State portal confirmation # |
| reconciled | FALSE until matched |

### Matching Relay Transactions

**Option A — Manual (current):**
Export Relay transactions as CSV, compare against `filing_payments` table.

**Option B — Plaid (future):**
Connect Relay to Plaid, then connect Plaid to ERPNext via the community
Plaid integration. This gives read-only access to Relay transactions for
automatic reconciliation.

**Option C — QuickBooks bridge (future):**
Relay → QuickBooks Online sync → ERPNext QBO integration. Transactions
flow: Relay → QBO → ERPNext → auto-match against filing_payments.

## Commission Payouts via ACH

Sales agent commissions are tracked in the `commission_ledger` table in
PostgreSQL and reconciled with ERPNext.

### Agent Setup

Sales agents are created via `POST /api/v1/admin/agents`, which:
1. Creates the agent record with an auto-generated `REF-XXXXX` referral code
2. Creates a linked discount code (5% off service fee) tied to the agent
3. Agent shares their referral link or discount code with prospects

### Commission Amounts

Commissions are configurable per service type:

| Service | Commission |
|---------|-----------|
| Canada CRTC registration | $300 |
| Business formations | $50 |
| Compliance services | 10% of service fee |
| Service bundles | $100 |

### Commission Lifecycle

```
pending → eligible → approved → processing → paid
```

1. **Pending:** Commission record created when referred order is placed
2. **Eligible:** 14-day holdback after order delivery has passed
3. **Approved:** Admin reviews and approves in ERPNext
4. **Processing:** ACH payment initiated via Relay dashboard
5. **Paid:** ACH confirmed, `commission_ledger` updated with `paid_at` and `relay_transaction_id`

### Automation

- `commission_worker.py` runs as a daily cron job
- Scans `commission_ledger` for commissions past the 14-day holdback
- Transitions qualifying records from `pending` → `eligible`
- Sends admin notification in ERPNext for batch approval
- After admin approval, payment is made via Relay ACH (manual — no Relay API)

### Future: ACH API

If Relay adds API support (or we switch to a banking-as-a-service provider
like Mercury, Brex, or Column), we can automate ACH payouts. The
`commission_ledger` table is designed for this — the `status` field
tracks the full lifecycle from pending through paid.

## Virtual Card Security

- Card only funded to the amount needed for the next filing
- Separate Relay checking account dedicated to filing fees
- Card number stored AES-encrypted in ERPNext (Frappe Password field)
- Card details only in memory during Playwright automation
- Never logged, never written to disk, never in screenshots
- `filing_payments` table stores only last4 digits
- If card is compromised, max exposure = current balance (minimal)

## Relay Account Structure

Recommended Relay account organization (Profit First method):

| Account | Purpose |
|---------|---------|
| **Operating** | Main revenue account |
| **Filing Fees** | Dedicated to state filing fee payments (virtual card attached) |
| **Profit** | Retained earnings |
| **Tax** | Tax reserves |
| **Commissions** | Referral partner payouts (ACH from here) |
| **Owner Pay** | Owner distributions |

## Environment Variables

```
RELAY_FILING_CARD_ID=relay-filing-card    # ERPNext Sensitive ID name
```

No Relay API credentials needed (there is no API).
