SRS: Stage 3 KYC & Live Onboarding — UC_5.5: Flows 3D–3G Contracts & Market Data Initiation
| Field | Value |
|---|---|
| BA in Charge | linh.nguyen34 |
| Date Created | 2026-08-07 |
| Version | v2.3 |
| Last Updated | 2026-08-22 — CHR tag standardization: STAGE3-037 → STAGE3-037 [CHR-46] (3 occurrences), CR-20260813-001 → [CHR-46] (3 occurrences). |
| Document References | Zapier Integration V7.pdf (Flow 3D lines 1177–1208; Flow 3E lines 1210–1227; Flow 3F lines 1229–1249; Flow 3G lines 1251–1262) · RFQ_ Stack Trading Prop Tech V7.pdf (§Contract Routing, §Market Data) · CR-20260720-001 (TradeSea replaces NinjaTrader — affects Flow 3H/UC_5.8, not this UC) · CR-20260720-004 (Freshdesk replaces Zendesk — not applicable to this UC) |
UC Index
| UC_ID | Use Case Name | Business Description |
|---|---|---|
| UC_5.5 | Flows 3D–3G — Contracts & Market Data Initiation | When all three KYC/payout statuses are Approved, the aggregation gate fires. Flow 3D sends the correct Independent Contractor Agreement via Rippling (country-routed) and initiates the Market Data setup path for Futures traders. Flow 3E handles the Rippling contract-signed webhook and evaluates whether live provisioning (Flow 3H) can proceed. Flows 3F and 3G handle the Futures-only Market Data Setup form and optional premium payment. |
Changelog
| Date | Version | Updated item | Before | After | Notes |
|---|---|---|---|---|---|
| 2026-08-07 | v1 | Initial creation | — | Created SRS for UC_5.5 (Flows 3D–3G) | First authoring pass |
| 2026-08-11 | v1.2 | §5 Flow 3E/3F/3G + §11 AC-5.5-06/08/10 — inter-flow trigger terminology | "fire internal webhook to trigger Flow 3H" / "triggered in same Zap execution" | "dispatch internal Webhook to trigger Flow 3H in a separate process; source Zap terminates" — Flow 3E/3F/3G and Flow 3H are independent Zaps | STAGE3-029 confirmed 2026-08-11 |
| 2026-08-11 | v1.2 | §7 Exceptional Flow — NULL Billing_Country (new, GAP-03) | Not present | Confirmed design gap: source does NOT define fallback when Billing_Country = NULL at Flow 3D routing branch. Added as GAP-03. | STAGE3-028 confirmed 2026-08-11 |
| 2026-08-11 | v1.2 | §11 Acceptance Criteria (new section) | Not present | AC-5.5-01 to AC-5.5-11 added — all confirmed ĐẠT by client 2026-08-11 | STAGE3-028 confirmed 2026-08-11 |
| 2026-08-12 | v1.3 | §7 Flow 3E stagnation — trader never signs ICA; BR_5.5.10 added | [MISSING] — no reminder or expiry behavior defined | ICA validity = indefinite (no expiry on contract itself). Signing link TTL = 7 days; Rippling native or internal DB invalidation. Reminders: Day 3 + Day 7 (Rippling native or webhook-triggered). Day 7: contract_status → 'Expired'; trader re-initiates via Dashboard button. BR_5.5.10 added. | QnA STAGE3-034 confirmed 2026-08-12 |
| 2026-08-12 | v1.4 | §1 3rd Party — removed Typeform/Zapier form assumption; §2 Trigger Flow 3F — webhook source changed from third-party form to internal frontend endpoint; §5 Flow 3D — "Level 1 Setup Form email" changed to login link email; §5 Flow 3F — rewritten as native dashboard screen with new internal Option A endpoint; §9 Wireframe — Level 1 Setup Form owned by Stack Trading frontend (not third-party) | As documented in v1.3 | Level 1 Setup Form is hosted on Stack Trading frontend dashboard. Flow 3D email = login link. Flow 3F trigger = frontend call to new internal endpoint (Option A) or existing checkout (Option B). BR_5.5.6 updated. | QnA STAGE3-042 confirmed 2026-08-12 |
| 2026-08-12 | v1.5 | §7 Flow 3F stagnation — [MISSING] replaced with confirmed cron logic; BR_5.5.11 added | [MISSING] — no stagnation handling for setup_status | Daily backend cron scans setup_status = 'Pending' + contract_status = 'Signed'; fires reminder at D+3 and D+7; no Ops Slack escalation; 90-day stagnation_deadline from Flow 3E handles termination. BR_5.5.11 added. | QnA STAGE3-043 confirmed 2026-08-12 |
| 2026-08-14 | v1.9 | §9 Wireframe — added re-entry trigger (load/refresh while setup_status=Pending); §10 Screen Description — full spec from screenshot (step pill, asset label, headline, 4 toggle cards, cost bar, lifecycle info box, Next CTA, on-click logic) | §9 one-liner; §10 "N/A" | Market Data selection screen fully documented. Step indicator = "Step 1". CME Level 2 ON by default (cannot be toggled off). CBOT/NYMEX/COMEX OFF by default. Cost bar dynamic. Lifecycle copy confirmed. | Screenshot confirmed 2026-08-14. |
| 2026-08-14 | v1.8 | §5 Flow 3F Option B — removed "payment link emailed to trader"; §3 3rd Party — removed "Option B payment link" from SES scope; §9 Wireframe — Option B payment widget on dashboard; AC-5.5-09 — corrected | Flow 3F Option B: middleware "sends payment link to trader via email" | Option B payment is completed entirely on the Stack Trading dashboard. Frontend calls Calculate Cart + Execute Checkout inline — no email sent. SES-26 (Market Data Payment Link) does not exist. | Correction: STAGE3-042 applies to both options — all payment UI is native to the dashboard. |
| 2026-08-12 | v1.7 | §5 Flow 3G Step 2 — market_data_flags write | Only setup_status = 'Complete' and market_data_billable = True documented | Node.js middleware at Process Payment Webhook also parses addon_ids from gateway metadata and writes per-feed Active/Inactive flags to market_data_flags JSON column in Users table, in the same atomic DB transaction. GET /market-data-status reads these flags. BR_5.5.12 added. | QnA STAGE3-047 confirmed 2026-08-12 |
| 2026-08-12 | v1.7 | §1 Overview / §6 Alt-1 added (dashboard lockout context) | UC_5.1 not previously referenced here | Added scope note: during Flows 3A–3E (all pending), dashboard is hard-locked. Only when contract is signed (Flow 3E complete) does the trader enter Flow 3F forced Market Data screen. Lockout BRs live in UC_5.1.md (BR_5.1.8/BR_5.1.9); referenced here for completeness. | QnA STAGE3-048 confirmed 2026-08-12 |
| 2026-08-18 | v2.2 | §7 Flow 3E stagnation + BR_5.5.10 — Rippling native confirmed | Day 3 reminder: "Rippling native or internal webhook-triggered"; Day 7: "If Rippling supports TTL / if not, PostgreSQL invalidation"; "Dev investigation required (STAGE3-034)" block present | Rippling handles TTL + reminders natively — confirmed by client 2026-08-18. All conditional if/else implementation language removed. "Dev investigation required" note removed. Implementation: pass ttl=7 days at signature request; configure Day 3 in Rippling scheduler; no internal fallback. | Client confirmed 2026-08-18 |
| 2026-08-18 | v2.1 | §2 Trigger Flow 3F — Returnee Trader Branch B trigger added | Flow 3F trigger: "Frontend call from Market Data selection screen (Futures traders only)" | Added second trigger source: internal webhook from Flow 3A Step 0B (Branch B Returnee Trader — identity_status='Approved' AND dots_payee_id IS NOT NULL AND contract_status='Signed'). Bypasses Flows 3B/3C/3D/3E; payout_status='Approved' + setup_status='Pending' already set. Flow 3F onward identical for both paths. | BR_5.1.11 / STAGE3-055/H-07 extended — 2026-08-18 |
| 2026-08-15 | v1.9 → v2.0 | §7 Flow 3D Rippling fail, §7 new Flow 3E webhook auth, §7 Flow 3G payment fail, §8 BR_5.5.13, §8 BR_5.5.14 | Flow 3D Rippling fail [MISSING]; Flow 3E webhook auth not documented; Flow 3G payment fail [MISSING]; market_data_billable reset on reactivation not documented | H-08: Rippling halt/freeze confirmed (no skip). H-09: Rippling dual-layer auth (Signed Webhook + IP Allowlist). M-13: payment fail → keep Pending_Payment, no rollback. BR_5.5.13: market_data_billable must reset True on reactivation. BR_5.5.14: Rippling webhook dual-layer auth. | STAGE3-056/057/058/072 confirmed 2026-08-15 |
| 2026-08-12 | v1.6 | §3 Pre-conditions Flow 3D — Billing_Country replaced with kyc_country; §5 Flow 3D Step 2 — routing source field changed; §7 GAP-03 — closed (NULL country structurally impossible); BR_5.5.2 updated; AC-5.5-01/02 updated | Flow 3D evaluated Billing_Country from payment gateway | Flow 3D now evaluates kyc_country extracted from Veriff government ID and written to Users table at APPROVED. kyc_country is never NULL at Flow 3D time — if Veriff fails to extract country, KYC fails and aggregation gate never fires. Billing_Country removed from ICA routing logic entirely. GAP-03 permanently closed. | QnA STAGE3-045 confirmed 2026-08-12 |
| 2026-08-10 | v1.1 | Q4: Payment processor webhook authentication confirmed — three-layer global security mandate documented; BR_5.5.8 (security layers) and BR_5.5.9 (integration patterns) added | [MISSING] — assumption was Zapier filter only | Confirmed: HMAC/JWS signature + IP allowlist + rate limiting; two integration patterns (Baseline Zapier Code Step vs Hardened WAF+Middleware) | QnA STAGE3-016 confirmed 2026-08-10 |
| 2026-08-22 | v2.2 → v2.3 | All sections — CHR tag standardization | Bare STAGE3 codes without CHR tags; date-based CR refs | A37: CR-20260813-001 → [CHR-46] (3 occurrences). B11: STAGE3-037 → STAGE3-037 [CHR-46] (3 occurrences). | CHR_Tag_Change_Plan_20260822_v4.md |
Glossary
For all shared project terminology, refer to: Project Glossary.
UC_5.5 — Flows 3D–3G: Contracts & Market Data Initiation
1. Overview
| Field | Content |
|---|---|
| ID | UC_5.5 |
| Use Case | Flows 3D–3G — Contracts & Market Data Initiation |
| Description | This UC covers four sequential Zapier flows that bridge the KYC/payout approval stage and the live account provisioning stage. Flow 3D fires when the three-way aggregation gate is met (all statuses Approved). It country-routes the Independent Contractor Agreement (ICA) via Rippling and simultaneously initiates the Market Data setup path by sending a login link email to Futures traders. Flow 3E receives the Rippling contract-signed webhook, updates contract_status = 'Signed', sets stagnation_deadline, and evaluates whether Market Data Setup is already complete before triggering Flow 3H. Flow 3F handles the Futures-only Market Data selection screen (native Stack Trading dashboard — confirmed STAGE3-042): Option A (firm-paid standard) calls a new internal endpoint to set setup_status = 'Complete'; Option B (trader-paid premium) initiates the existing checkout flow. Flow 3G handles the payment confirmation for Option B, setting setup_status = 'Complete' and re-evaluating the gate to Flow 3H. |
| Zapier Flows | Flow 3D · Flow 3E · Flow 3F (Futures only) · Flow 3G (Futures Option B only) |
| Zapier Table | Users table (contract_status — 'Pending' / 'Signed' / 'Expired', setup_status, stagnation_deadline, is_professional, market_data_billable, kyc_country — written at Veriff APPROVED, used by Flow 3D ICA routing) |
| 3rd Party | Rippling (ICA e-signature) · Payment processor (Option B market data payment — active processor per ACTIVE_PAYMENT_PROCESSOR config) · AWS SES (emails — login link for Market Data Setup only) |
Scope note — Forex traders: Forex traders skip Flows 3F and 3G entirely. Their
setup_statusis set to'N/A'by Flow 3D. Flow 3E therefore gates onsetup_status == 'N/A'(already satisfied) and proceeds directly to Flow 3H after contract signing.
Scope note — contract type: The WBS description references "US W-2 or Dots International contractor." Per source (
zapier_v7_full.txtline 1190): "Tax forms are excluded from this Rippling flow as Dots handles W-8BEN/W-9." Rippling is used strictly for ICA e-signature, not for tax forms. All four ICA variants are Independent Contractor Agreements, not W-2 employment forms. There is no W-2 (employee tax form) in this flow.
2. Trigger
Flow 3D: Internal webhook fired by the aggregation gate in Flow 3B (UC_5.2) or Flow 3C (UC_5.4) — whichever sets the last of the three required status fields to 'Approved'. Flow 3B.2 (UC_5.3) deprecated (STAGE3-037 [CHR-46]/039 — [CHR-46]) — Flow 3B now covers all traders (Futures and Forex).
Flow 3E: Inbound webhook from Rippling confirming the trader has e-signed the Independent Contractor Agreement.
Flow 3F: Frontend call from the Market Data selection screen in the Stack Trading dashboard (Futures traders only). Option A: frontend calls a new internal endpoint to update setup_status and trigger Flow 3H. Option B: frontend calls Calculate Cart and Execute Checkout endpoints; Flow 3G handles the subsequent payment confirmation webhook. (Confirmed STAGE3-042: not a third-party form webhook.)
Returnee Trader (Branch B) trigger (BR_5.1.11 / 2026-08-18): For Returnee Traders, Flow 3F is also triggered by an internal webhook from Flow 3A Step 0B — the Branch B execution block that bypasses Flows 3B/3C/3D/3E entirely and routes directly here. The
payout_status = 'Approved'andsetup_status = 'Pending'are already set by Flow 3A middleware before this trigger fires. From Flow 3F onward, the Returnee path is identical to the New Trader path: trader selects market data (Option A or B) and Flow 3H provisions the new account.
Flow 3G: Inbound webhook from payment processor confirming payment_success for the Option B premium market data upgrade (Futures Option B traders only).
3. Pre-conditions
Flow 3D:
identity_status = 'Approved'ANDinstitution_approval_status = 'Approved'ANDpayout_status = 'Approved'foruser_id.- Internal aggregation gate webhook received.
🔄 CR — STAGE3-045: ICA routing now uses kyc_country (from Veriff government ID) instead of Billing_Country. kyc_country is written to Users table at Veriff APPROVED and guaranteed non-NULL at Flow 3D trigger time.
kyc_countryIS NOT NULL in Users table — guaranteed by the Veriff APPROVED gate: if Veriff cannot extract a country from the government ID, KYC fails and Flow 3D never triggers. (Confirmed STAGE3-045 — replacesBilling_Countryas the ICA routing source field.)
Flow 3E:
- Flow 3D has executed: Rippling ICA e-signature request sent;
contract_status = 'Pending'. - Trader has received the Rippling contract email and completed the e-signature.
- Rippling has fired the signed-confirmation webhook.
Flow 3F:
Asset_Class = 'Futures'for the trader.- Flow 3D has sent the Market Data Setup login link email;
setup_status = 'Pending'. - Trader has logged in to dashboard and is presented with the Market Data selection screen.
Flow 3G:
- Flow 3F Option B path was triggered: trader selected premium add-ons; checkout initiated on dashboard.
setup_status = 'Pending_Payment'.- Payment processor has confirmed
payment_successand fired the webhook.
4. Post-conditions
Flow 3D:
- Rippling ICA e-signature request sent to trader (one of four country-routed agreements).
contract_status = 'Pending'in Users table.- Futures traders:
setup_status = 'Pending'; "Action Required: Complete Market Data Setup" login link email sent to trader. - Forex traders:
setup_status = 'N/A'. - Zap terminates.
Flow 3E — contract signed:
contract_status = 'Signed'in Users table.stagnation_deadline = Today + 90 daysset.is_professional = Trueset.- Gate evaluated: if
setup_status == 'Complete'ORsetup_status == 'N/A'→ Flow 3H triggered. - Else: Zap terminates, waits for Market Data Setup.
Flow 3F — Option A (firm-paid):
setup_status = 'Complete'andmarket_data_billable = False.- Gate evaluated: if
contract_status == 'Signed'→ Flow 3H triggered. Else: Zap terminates.
Flow 3F — Option B (trader-paid):
- Trader completes checkout on the dashboard (no payment link emailed).
setup_status = 'Pending_Payment'.- Zap terminates.
Flow 3G — payment confirmed:
setup_status = 'Complete'andmarket_data_billable = True.- Gate evaluated: if
contract_status == 'Signed'→ Flow 3H triggered. Else: Zap terminates.
5. Basic Flow
Flow 3D — Contract Execution & Market Data Initiation
- Internal webhook received:
identity_status,institution_approval_status,payout_statusall'Approved'foruser_id. - Zapier evaluates
kyc_country(verified country from Veriff government ID — confirmed STAGE3-045; replacesBilling_Country) to route the correct ICA via Rippling API:kyc_country = 'US'→ US Contractkyc_country = 'GB'or EU member state → UK/EU Contractkyc_country IN ('CA', 'AU', 'NZ')→ Common Law Contract- All other countries → Rest of World Contract
- Rippling API call sends the selected ICA for e-signature to the trader.
- UPDATE Users table:
contract_status = 'Pending'. - Market Data branching by Asset_Class:
- IF
Asset_Class == 'Futures': send "Action Required: Complete Market Data Setup" email to trader (contains login link to dashboard — no form link); UPDATEsetup_status = 'Pending'. - IF
Asset_Class == 'Forex': UPDATEsetup_status = 'N/A'.
- IF
- Zap terminates.
Flow 3E — Contract Execution Handler
- Rippling webhook received: contract signed, containing
user_id. - UPDATE Users table:
contract_status = 'Signed'stagnation_deadline = Today + 90 daysis_professional = True
- Aggregation gate check: query
setup_statusforuser_id:- IF
setup_status == 'Complete'ORsetup_status == 'N/A'→ dispatch internal Webhook to trigger Flow 3H (UC_5.8); Flow 3E Zap terminates. - ELSE → Zap terminates; waits for Market Data Setup (Flows 3F or 3G).
- IF
Flow 3F — Market Data Setup Handler (Futures only)
Platform confirmed (STAGE3-042 2026-08-12): The Market Data selection screen is hosted natively on the Stack Trading frontend dashboard. This is NOT a standalone form hosted on Typeform or Zapier. When the trader logs in after receiving the Flow 3D email, the dashboard forces them to the Market Data selection screen.
- Trader logs into dashboard; dashboard forces navigation to Market Data selection screen.
- Trader selects market data option:
- Option A — Standard (firm-paid, includes 1 Level 2 CME Feed):
- Frontend calls new internal endpoint:
POST /market-data/setup-complete(or equivalent) withuser_id,option = 'A'. - Backend: UPDATE Users table:
setup_status = 'Complete',market_data_billable = False. - Backend: dispatch internal webhook to trigger Flow 3H (UC_5.8); Flow 3F process terminates.
- Gate check: if
contract_status != 'Signed'→ dispatch to Flow 3H is deferred; Zap terminates and waits for contract.
- Frontend calls new internal endpoint:
- Option B — Premium add-ons (trader-paid, beyond firm-covered feed):
- Frontend calls
POST /calculate-cartthenPOST /execute-checkoutwithproduct_id = 'LIVE_DATA_UPGRADE',addon_ids = [selection]— all on the dashboard (no payment link emailed). - Middleware checks
ACTIVE_PAYMENT_PROCESSOR; payment flow completes within the dashboard session. - UPDATE Users table:
setup_status = 'Pending_Payment'. - Zap/process terminates; awaits payment confirmation via Flow 3G.
- Frontend calls
- Option A — Standard (firm-paid, includes 1 Level 2 CME Feed):
Flow 3G — Market Data Payment Handler (Futures Option B only)
- Webhook received from payment processor:
payment_success, containinguser_id,product_id,addon_ids. - Node.js Middleware (
Process Payment Webhook) performs an atomic DB transaction (STAGE3-047 2026-08-12):- Parse
addon_idsfrom gateway payment metadata. - Write per-feed flags to
market_data_flagsJSON column in Users table (one flag per exchange/feed inaddon_ids— e.g.,NYMEX: Active,CBOT: Active). - SET
setup_status = 'Complete' - SET
market_data_billable = True - All three writes are atomic — partial write must not occur.
Why:
GET /market-data-statusreadsmarket_data_flagsto render the Active/Inactive status per feed on the dashboard. Ifmarket_data_flagsis not written here, the feed status display will show incorrect state regardless of payment confirmation. (Source: STAGE3-047 confirmed 2026-08-12) - Parse
- Gate check: if
contract_status == 'Signed'→ dispatch internal Webhook to trigger Flow 3H (UC_5.8); Flow 3G Zap terminates. ELSE: Zap terminates, waits for contract.
6. Alternative Flow
-
[Flow 3E — setup_status already Complete or N/A at time of contract signing]
- Forex trader or Futures Option A trader already completed Market Data Setup before signing.
- Aggregation gate immediately satisfied → Flow 3H triggered in the same Zap execution.
-
[Flow 3E — contract signed before Market Data Setup complete (Futures)]
setup_status = 'Pending'or'Pending_Payment'when contract signed.- Flow 3E terminates; gate re-evaluated by Flow 3F or 3G when Market Data Setup completes.
-
[Flow 3F — trader selects Option B (premium add-ons)]
- Follows the Option B path in §5 Flow 3F. Zap terminates; waits for payment confirmation via Flow 3G.
-
[Flow 3G — contract already signed when payment confirmed]
contract_status = 'Signed'at time of payment confirmation → Flow 3H triggered immediately in Flow 3G.
7. Exceptional Flow
-
[Flow 3D — Rippling API call fails (H-08/STAGE3-056)]
Confirmed — HALT/FREEZE. If the Rippling API returns non-200 or times out at Flow 3D Step 3:
- Do NOT skip.
contract_statusstays'Pending'(or NULL if not yet written). - Fire Slack alert (urgent) to Ops channel for manual vendor issue resolution.
- Trader cannot proceed to live trading without signing ICA. No bypass allowed. (Source: STAGE3-056 / H-08 confirmed 2026-08-15)
- Do NOT skip.
-
[Flow 3D — trader's country not matched by any routing rule]
- Source defines four routing rules: US, GB/EU, CA/AU/NZ, Rest of World. "Rest of World" is a catch-all, so technically all countries are covered. However, the EU member state list is not explicitly enumerated in the source — it is assumed to be the standard ISO EU member list.
[MISSING]— is there an explicit allowlist of EU member states, or does the system rely on a country-code lookup table?
-
[Flow 3D — Billing_Country is NULL (GAP-03)]
(Confirmed design gap — STAGE3-028 2026-08-11)⛔ GAP-03 CLOSED — STAGE3-045 2026-08-12. Flow 3D no longer evaluatesBilling_Country. ICA routing now useskyc_country— the country extracted from the trader's government ID by the Veriff payload and written to the Users table atidentity_status = 'Approved'(UC_5.2 Step 3 / BR_5.2.10). NULL is structurally impossible: If Veriff cannot extract a country from the government ID document, the trader fails KYC (identity_statusstays'Pending'), the aggregation gate never fires, and Flow 3D is never triggered. No fallback or default routing logic is needed. Legal liability note: Client explicitly rejected defaulting to "Rest of World" for unknown country (Billing_Country-based Options 1–3 were rejected). Using verified KYC country eliminates the legal risk entirely. -
[Flow 3E — Rippling webhook received but user_id not found in Users table]
[MISSING]— no handling documented for orphaned Rippling webhooks.
-
[Flow 3E — contract_status already 'Signed' (duplicate webhook)]
- If Rippling re-delivers the webhook, the DB UPDATE re-sets the same values (idempotent for
contract_statusandis_professional).stagnation_deadline = Today + 90 dayswould be re-calculated from the re-delivery date — potentially extending the deadline unintentionally. [MISSING]— is there an idempotency guard to preventstagnation_deadlinefrom being reset on duplicate webhook delivery?
- If Rippling re-delivers the webhook, the DB UPDATE re-sets the same values (idempotent for
-
[Flow 3E — trader never signs the contract (stagnation)] (Confirmed — STAGE3-034 2026-08-12; Rippling native confirmed by client 2026-08-18)
- ICA validity period: The ICA document itself is valid indefinitely — there is no annual renewal or expiration date on the contract.
- Signing link TTL (7 days): The Rippling-generated signing link expires after 7 days. Rippling handles this natively — pass TTL at signature request generation; no internal PostgreSQL invalidation required.
- Automated reminders:
- Day 3: Rippling native automated reminder sent to trader.
- Day 7: Rippling native expiry fires. UPDATE Users table:
contract_status = 'Pending' → 'Expired'. Trader required to click a button on Dashboard to generate a fresh Rippling signature request and restart the signing process.
- No dev investigation required. Rippling natively handles both TTL enforcement (Day 7 expiry) and automated reminder scheduling (Day 3). No internal fallback webhook or PostgreSQL-level invalidation needed. (Client confirmed 2026-08-18.)
-
[Flow 3F — Market Data selection never completed (stagnation)] (Confirmed — STAGE3-043 2026-08-12)
- Automated reminders via backend cron: A daily cron job scans for users where
setup_status = 'Pending'ANDcontract_status = 'Signed'. Reminder emails fire at:- Day 3: Standard reminder email sent to trader.
- Day 7: Second reminder email sent to trader.
- No Ops Slack escalation. Operations team does not chase traders who fail to complete Market Data setup.
- No new automated closure process. Flow 3E already sets
stagnation_deadline = Today + 90 daysat contract signing. If the trader never sets up market data, they sit dormant until the Flow 19 Stagnation Monitor sweeps them up at the 90-day mark and terminates the account automatically. - See BR_5.5.11.
- Automated reminders via backend cron: A daily cron job scans for users where
-
[Flow 3E — Rippling inbound webhook authentication (H-09/STAGE3-057)]
Confirmed — dual-layer auth required. Middleware Hub MUST validate inbound Rippling signed webhooks using both:
- Signed Webhook Verification — verify Rippling's cryptographic signature in the webhook header.
- IP Allowlisting — only accept requests from Rippling's published IP range. Both layers are mandatory and simultaneous. Invalid signature or unlisted IP → reject + log security event. (Source: STAGE3-057 / H-09 confirmed 2026-08-15)
-
[Flow 3F/3G — payment fails or is declined (H-13/STAGE3-072)]
setup_statusstays'Pending_Payment'. Trader receives error from payment gateway directly on dashboard UI. Trader clicks the payment button again — no new link generation needed. (Source: STAGE3-072 / M-13 confirmed 2026-08-15) -
[Flow 3F/3G — Option B checkout initiated but Rippling contract already signed before payment]
- Covered in Alternative Flow (§6) — Flow 3G triggers Flow 3H immediately when payment is confirmed.
- No exception; standard path.
8. Business Rules
BR_5.5.1: Aggregation Gate Trigger — All Three Statuses Required
Flow 3D fires only when ALL three of the following are simultaneously 'Approved' for the same user_id:
| Field | Set by |
|---|---|
identity_status | |
institution_approval_status | identity_status (STAGE3-037 [CHR-46] / [CHR-46]) |
payout_status | Flow 3C (Dots) |
The gate is checked by whichever of the three upstream flows fires last. This UC is the downstream target — it does not re-check the gate itself.
(Source: Zapier Integration V7.pdf Flow 3D lines 1179–1181)
🔄 CR — STAGE3-045: ICA routing source changed from Billing_Country to kyc_country. Four ICA variants now routed on verified government ID country. Billing_Country removed from routing logic. GAP-03 permanently closed.
BR_5.5.2: ICA Country Routing — Four Variants via Rippling, routed on kyc_country (STAGE3-045)
Rippling sends one of four Independent Contractor Agreements based on kyc_country (the country extracted from the trader's Veriff government ID document — written to Users table at Veriff APPROVED per BR_5.2.10).
⛔
Billing_Countryis NOT used for ICA routing. It cannot be relied on for legal jurisdiction determination (confirmed STAGE3-045 2026-08-12 — legal liability concern).
| kyc_country value | Contract Type |
|---|---|
'US' | US Contract |
'GB' or EU member state | UK/EU Contract |
'CA', 'AU', 'NZ' | Common Law Contract |
| All other countries | Rest of World Contract |
kyc_country is guaranteed non-NULL at Flow 3D trigger time: if Veriff fails to extract a country from the government ID, the trader fails KYC and the aggregation gate never fires. No NULL fallback logic is required. (This permanently closes GAP-03.)
Tax forms (W-9, W-8BEN) are excluded from Rippling. Dots handles all tax form collection (UC_5.4).
(Source: Zapier Integration V7.pdf Flow 3D lines 1184–1190; QnA STAGE3-045 confirmed 2026-08-12)
BR_5.5.3: Stagnation Deadline Set at Contract Signing
stagnation_deadline = Today + 90 days is set when the trader signs the ICA (Flow 3E). This is the deadline by which the trader must complete live trading milestones before the account is flagged for stagnation review. The clock does not start until the ICA is signed — not when it is sent.
(Source: Zapier Integration V7.pdf Flow 3E lines 1217–1218)
BR_5.5.4: is_professional = True Set at Contract Signing
is_professional = True is set in the same DB write as contract_status = 'Signed'. This flag affects market data entitlement levels in Flow 3H (professional vs. non-professional data fees).
(Source: Zapier Integration V7.pdf Flow 3E line 1219)
BR_5.5.5: Forex Traders Skip Market Data Setup
For Forex traders, setup_status = 'N/A' is set by Flow 3D. Flow 3E's aggregation gate treats 'N/A' as equivalent to 'Complete' for triggering Flow 3H. Flows 3F and 3G are never executed for Forex traders.
(Source: Zapier Integration V7.pdf Flow 3D lines 1202–1205; Flow 3E lines 1223–1224)
BR_5.5.6: Market Data — Two-Tier Model for Futures Traders (Native Dashboard — STAGE3-042)
The Market Data selection is performed natively on the Stack Trading frontend dashboard (not via a Typeform or Zapier form). The dashboard forces the trader to the Market Data selection screen upon login while setup_status = 'Pending'.
Futures traders select their market data tier:
- Option A (Standard — firm-paid): 1 Level 2 CME Feed included. Frontend calls a new internal endpoint to set
setup_status = 'Complete'andmarket_data_billable = False. Backend then triggers the internal webhook to Flow 3H. - Option B (Premium — trader-paid): Additional data feeds beyond the firm-covered standard. Frontend calls
Calculate CartandExecute Checkoutendpoints. Payment processor is determined dynamically fromACTIVE_PAYMENT_PROCESSORconfiguration.market_data_billable = Trueupon payment confirmation (Flow 3G).
The Flow 3D email for Futures traders contains a standard dashboard login link (subject: "Action Required: Complete Market Data Setup") — not a direct form link.
(Source: Zapier Integration V7.pdf Flow 3F lines 1235–1249; QnA STAGE3-042 confirmed 2026-08-12)
BR_5.5.7: Dual Aggregation Gates — Contract and Market Data Must Both Complete
Flow 3H can only be triggered when BOTH of the following are true simultaneously:
contract_status = 'Signed'(set by Flow 3E)setup_status IN ('Complete', 'N/A')(set by Flow 3D for Forex, Flow 3F for Futures Option A, Flow 3G for Futures Option B)
Both Flow 3E and Flow 3F/3G independently evaluate this two-field gate. Whichever completes last triggers Flow 3H.
(Source: Zapier Integration V7.pdf Flow 3E lines 1223–1227; Flow 3F lines 1238–1239; Flow 3G lines 1260–1262)
BR_5.5.8: Global Webhook Security Mandate — Three Layers Apply to All Payment Webhooks
All inbound webhooks from external payment providers (NMI, Triple-A, Nomupay, EBANX, Dusupay, Skrill) are subject to a mandatory three-layer security control before any processing occurs:
| Layer | Control | Description |
|---|---|---|
| 1 | Signed Webhook Verification (HMAC/JWS) | Webhook receiver MUST verify the cryptographic hash of the payload against the stored gateway secret. Delivered via provider_signature header/parameter on POST /provisioning/live-trader (Process Payment Webhook). |
| 2 | IP Allowlisting | System MUST explicitly whitelist inbound IP ranges for each payment gateway. Requests from non-whitelisted IPs are rejected before payload inspection. |
| 3 | Layer-7 Rate Limiting | Enforced on all webhook catcher endpoints to prevent bot or brute-force traffic from exhausting automated task quotas or compute resources. |
The Process Payment Webhook endpoint (POST — ingests NMI/T365/etc. webhook) requires:
provider_signature— cryptographic hash to validate against gateway secret.- Payload with custom metadata:
addon_ids,product_id,user_id— ensures transaction consistency and correct routing.
(Source: QnA STAGE3-016 confirmed 2026-08-10; RFQ_ Stack Trading Prop Tech V7.pdf §Process Payment Webhook lines 1335–1373)
BR_5.5.9: Two Integration Patterns — How Signature Verification Executes
The physical execution of the signature check depends on the deployed integration pattern:
Option A — Baseline (Direct to Zapier):
- Payment provider webhook routes directly to a Zapier Catch Hook.
- Signature verification is executed via a Zapier Code Step (Python or JavaScript) or a synchronous API call back to the Middleware Hub for validation.
- Lower infrastructure overhead; requires Zapier Code step to be correctly maintained per gateway.
Option B — Hardened (Direct to Middleware, recommended):
- Webhook is sent directly to an internet-facing endpoint on the Middleware Hub behind a Web Application Firewall (WAF).
- Middleware Hub handles: cryptographic signature check → IP allowlist verification → payload normalisation → DB write-back → push of a clean, normalised event to Zapier.
- Zapier receives only the validated, normalised event — never the raw payment webhook.
- Higher security posture; WAF provides additional Layer-7 protection and shields Zapier from raw provider payload format changes.
Which pattern is deployed is an infrastructure/implementation decision. Both must satisfy all three controls in BR_5.5.8.
(Source: QnA STAGE3-016 confirmed 2026-08-10)
🔄 CR — STAGE3-034: ICA signing link TTL = 7 days. contract_status = 'Expired' state added. Day 3 reminder + Day 7 expiry with dashboard re-initiation button. Client confirmed 2026-08-18: Rippling handles both natively — no internal fallback needed.
BR_5.5.10: ICA Signing Link TTL — 7-Day Expiry and contract_status = 'Expired' Transition
The Rippling-generated ICA signing link has a 7-day Time-To-Live (TTL). Rippling handles TTL enforcement and reminder scheduling natively — no internal PostgreSQL invalidation or webhook fallback is needed. (Client confirmed 2026-08-18.)
| Phase | Behavior |
|---|---|
| Contract itself | Valid indefinitely — no renewal or expiry date on the ICA document |
| Day 3 | Rippling native automated reminder sent to trader |
| Day 7 | Rippling natively expires the signing link. contract_status transitions from 'Pending' → 'Expired'. Trader must click a Dashboard button to generate a fresh Rippling signature request and restart the signing process. |
Implementation: Pass TTL parameter (ttl = 7 days) at Rippling signature request generation. Configure Day 3 reminder in Rippling scheduler. No internal cron or webhook required for this flow.
(Source: QnA STAGE3-034 confirmed 2026-08-12; Rippling native confirmed by client 2026-08-18)
BR_5.5.11: Market Data Setup Stagnation — Cron Reminders at D+3 and D+7
If a Futures trader does not complete the Market Data selection screen after receiving the Flow 3D login link email, setup_status remains 'Pending' indefinitely. The following stagnation handling applies:
| Day | Action |
|---|---|
| Day 3 | Backend daily cron fires a webhook to dispatch a standard reminder email to the trader |
| Day 7 | Backend daily cron fires a second reminder email |
| Day 90 | stagnation_deadline (set by Flow 3E at contract signing) expires — Flow 19 Stagnation Monitor sweeps the account and terminates it |
Cron query: Scan for users where setup_status = 'Pending' AND contract_status = 'Signed'.
No Ops Slack escalation. Operations does not manually intervene for traders who fail to complete Market Data setup.
No new automated closure process. The existing 90-day stagnation_deadline from Flow 3E handles termination — no separate closure path is required.
(Source: QnA STAGE3-043 confirmed 2026-08-12)
BR_5.5.12: market_data_flags must be written atomically by middleware at payment confirmation (STAGE3-047 2026-08-12)
When Flow 3G (Process Payment Webhook) processes a successful payment with product_id = 'LIVE_DATA_UPGRADE' (or 'MARKET_DATA'), the Node.js middleware MUST parse addon_ids from the gateway payload metadata and write the per-feed Active flags to the market_data_flags JSON column in the Users table in the same atomic DB transaction as setup_status = 'Complete' and market_data_billable = True.
Zapier does not write market_data_flags. This write is handled entirely by the Node.js middleware at the Process Payment Webhook endpoint.
Downstream dependency: GET /market-data-status reads market_data_flags to render the Active/Inactive status for each subscribed exchange feed (NYMEX, CBOT, COMEX, etc.) in the dashboard. If market_data_flags is not written, the dashboard feed status display will be incorrect regardless of payment status.
(Source: QnA STAGE3-047 confirmed 2026-08-12)
BR_5.5.13: market_data_billable MUST be reset to True on reactivation (H-10/STAGE3-058 2026-08-15)
When a trader is reactivated after a Zombie/Inactive Hold (Flow 19 stagnation sweep), the backend MUST:
- Re-enable market data feeds (re-activate the exchange data subscription).
- Set
market_data_billable = Truein the Users table.
Both steps are mandatory and must occur together. Setting feeds active without resetting market_data_billable = True would result in the trader receiving live market data without being billed in the next EOM billing cycle (Flow 22), causing revenue leakage.
(Source: STAGE3-058 / H-10 confirmed 2026-08-15)
BR_5.5.14: Rippling inbound webhook MUST use dual-layer authentication (H-09/STAGE3-057 2026-08-15)
Inbound webhooks from Rippling (Flow 3E — contract signed confirmation) require both authentication layers simultaneously:
- Signed Webhook Verification — validate Rippling's cryptographic signature embedded in the webhook request header.
- IP Allowlisting — only accept requests originating from Rippling's published IP address range.
Both layers are mandatory. A request that passes only one layer MUST be rejected. Invalid → HTTP 400, security event logged.
Rationale: a spoofed Rippling webhook could falsely set contract_status = 'Signed' and trigger live account provisioning (Flow 3H) without a genuine signed ICA — a critical compliance and legal risk.
(Source: STAGE3-057 / H-09 confirmed 2026-08-15)
The only Stack Trading-owned UI screen in this UC is the Market Data selection screen (Flow 3F):
- Market Data selection screen (Stack Trading dashboard — confirmed STAGE3-042 2026-08-12): Displayed when the trader logs in after receiving the Flow 3D login link email, OR when trader loads/refreshes the dashboard while
setup_status = 'Pending'. The dashboard forces navigation to this screen — trader cannot navigate away. Trader selects Option A (standard, firm-paid CME feed) or Option B (premium add-ons, trader-paid). Frontend-owned screen — owned by Agency B (Stack Trading frontend).
Other trader-facing touchpoints in this UC are:
- Rippling-hosted ICA e-signature page (Rippling UI — not owned by Stack Trading)
- "Action Required: Complete Market Data Setup" login link email sent in Flow 3D (AWS SES — no embedded form link)
- Option B payment widget embedded in dashboard Market Data selection screen (no email payment link)
10. Screen Description and Business Rules
Market Data Selection Screen (Flow 3F — Futures only, confirmed from screenshot 2026-08-14):
Entry condition: setup_status = 'Pending' AND contract_status = 'Signed' AND asset_class = 'Futures'. Dashboard forces this screen on login or page refresh — no sidebar or settings access until setup_status transitions out of 'Pending'.
Step indicator: "Step 1" pill at top of screen. Progress bar shows 1 of 3 segments filled (this is the first step of the live account setup flow presented to the trader after contract signing).
Asset class label: "Futures" displayed below the step pill.
Headline: "Market Data" — display typography, "Data" in a distinct gold/italic style.
Exchange toggle cards (4 cards in a row):
| Card | Default state | Badge | Description |
|---|---|---|---|
| CME Level 2 | ON (gold toggle) | "Most Popular" badge (top-right corner) | Firm-paid — 1 Level 2 CME feed. Included for all Futures traders at no cost. |
| CBOT | OFF (grey toggle) | — | Trader-paid premium add-on |
| NYMEX | OFF (grey toggle) | — | Trader-paid premium add-on |
| COMEX | OFF (grey toggle) | — | Trader-paid premium add-on |
- CME Level 2 toggle is ON by default and cannot be turned off — it is the firm-covered mandatory feed.
- CBOT, NYMEX, COMEX toggles are OFF by default. Trader can toggle any combination to add premium feeds (Option B).
- Enabling any premium toggle transitions from Option A to Option B.
Cost summary bar:
| State | Display |
|---|---|
| No premium add-ons selected (Option A) | Cost: $0.00 |
| One or more premium add-ons enabled (Option B) | Cost: $[calculated amount] — updates dynamically as toggles change |
Market Data Lifecycle info box:
Static informational section displayed below the cost bar. Confirmed copy from screenshot:
- Associate Track Evaluation: The Firm pays 100% of data costs.
- Level 1 and 2: The Trader pays (Standard Exchange Professional Data rates apply).
- Level 3: The Trader is fully reimbursed for Level 1 and 2 market data costs incurred.
- Level 3 to Level 24: The Firm pays 100% of data costs.
CTA: "Next" button — gold/amber pill button, bottom-right corner. Enabled once a selection is made (CME Level 2 ON by default, so "Next" is always enabled from initial load).
On "Next" click:
- Option A (only CME Level 2 ON): Frontend calls internal endpoint →
setup_status = 'Complete',market_data_billable = False. Ifcontract_status = 'Signed'→ internal webhook to Flow 3H. - Option B (any premium add-on ON): Frontend calls
POST /calculate-cart+POST /execute-checkoutwith selectedaddon_ids→ payment flow on dashboard →setup_status = 'Pending_Payment'.
(Source: screenshot confirmed 2026-08-14; STAGE3-042 confirmed 2026-08-12; STAGE3-030 confirmed 2026-08-11)
11. Acceptance Criteria
(All ACs confirmed ĐẠT / CHÍNH XÁC by client 2026-08-11 — Source: STAGE3-028)
| AC ID | Flow | Scenario | Expected Result |
|---|---|---|---|
| AC-5.5-01 | Flow 3D | Three-way aggregation gate fires; kyc_country = 'US' (formerly Billing_Country = 'US' — STAGE3-045) | Rippling API sends US ICA; contract_status = 'Pending'; Futures: setup_status = 'Pending' + Market Data Setup login link email sent; Forex: setup_status = 'N/A' |
| AC-5.5-02 | Flow 3D | All four ICA routing rules evaluated on kyc_country (STAGE3-045) | kyc_country = 'US' → US Contract; kyc_country = 'GB' or EU member state → UK/EU Contract; kyc_country IN ('CA','AU','NZ') → Common Law Contract; all other countries → Rest of World Contract |
| AC-5.5-03 | Flow 3D | Asset_Class = 'Forex' | setup_status = 'N/A'; no Level 1 Setup Form email sent |
| AC-5.5-04 | Flow 3D | Asset_Class = 'Futures' | setup_status = 'Pending'; Level 1 Setup Form emailed to trader to collect CME data subscription before account provisioning |
| AC-5.5-05 | Flow 3E | Rippling signed webhook received | Single atomic DB write: contract_status = 'Signed', stagnation_deadline = Today + 90 days, is_professional = True |
| AC-5.5-06 | Flow 3E | Contract signed; setup_status already 'Complete' (Option A) or 'N/A' (Forex) | Aggregation gate satisfied → internal Webhook dispatched to trigger Flow 3H in a separate process; Flow 3E Zap terminates |
| AC-5.5-07 | Flow 3E | Contract signed; setup_status = 'Pending' (Futures, form not yet submitted) | Flow 3E Zap terminates; waits for trader to complete market data setup; Flow 3H webhook NOT dispatched |
| AC-5.5-08 | Flow 3F | addon_ids count = 1 (CME only — Option A) | setup_status = 'Complete', market_data_billable = False; if contract_status = 'Signed' → internal Webhook dispatched to trigger Flow 3H in separate process; Flow 3F Zap terminates |
| AC-5.5-09 | Flow 3F | addon_ids count > 1 (premium add-ons — Option B) | POST /calculate-cart + POST /execute-checkout called on dashboard; setup_status = 'Pending_Payment'; Zap terminates; Flow 3H webhook NOT dispatched |
| AC-5.5-10 | Flow 3G | payment_success webhook received | setup_status = 'Complete', market_data_billable = True; if contract_status = 'Signed' → internal Webhook dispatched to trigger Flow 3H in separate process; Flow 3G Zap terminates |
| AC-5.5-11 | Flow 3D | Rippling ICA signed via Flow 3E | ICA contains NO W-9 or W-8BEN forms; tax forms collected separately by Dots in UC_5.4 (KYC/Payout flow) |
END OF UC_5.5