# 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).