new-site/docs/relay-integration.md
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

181 lines
6.6 KiB
Markdown

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