StackTrading Docs

SRS: UC_5.2 — Flow 3B: Identity Verification Handler (Veriff / Forex)

FieldValue
BA in Chargelinh.nguyen34
Date Created2026-08-08
Versionv2.2
Last Updated2026-08-25 — CR-20260825-001: Step 4A-0 extended to 5-field Dots health check; Step 4A-2 endpoint confirmed PUT /v2/users/{id}/compliance + address normalization rules; Exc-7 (addressinvalid fallback); BR_5.2.11/12 added.
Document ReferencesZapier Integration V7.pdf (§Flow 3B: Identity Verification Handler, §Flow 3.1: BPS Manual Veriff Reset, §Users table schema) · RFQ_ Stack Trading Prop Tech V7.pdf (§Process Veriff Handoff, §Reset Veriff KYC endpoint) · CR-20260720-004 (Freshdesk replaces Zendesk —CR_summary.md)

<a id="UC_5.2"></a>

UC_5.2 — Flow 3B: Identity Verification Handler (Veriff)

1. Overview

FieldContent
IDUC_5.2
Use CaseFlow 3B — Identity Verification Handler (Veriff — ALL traders)
DescriptionHandles inbound Veriff webhooks for ALL traders (Futures and Forex). Updated STAGE3-037 [CHR-46] 2026-08-12: All traders use Veriff. On APPROVED: (1) saves legal_name, address, kyc_country to Users table; (2) executes 3-step Dots payee creation process (POST /v2/users with SIM data → Submit Compliance Information with Veriff-extracted legal_name + address → POST /v2/flows to get flow_link); (3) updates identity_status and institution_approval_status; (4) checks aggregation gate. Second-cycle logic: if dots_payee_id IS NOT NULL at APPROVED, skip Dots creation and set payout_status = 'Approved' directly. On RESUBMISSION_REQUESTED: sends a retry email (max 3 attempts, shared counter). On EXPIRED or ABANDONED: auto-renews Veriff session, increments veriff_attempts, sends Identity_Verification_Retry email; at attempt 2 also creates a Freshdesk support ticket; at attempt 3 switches to DECLINED path. On DECLINED: sends final-fail email, creates high-priority Freshdesk ticket tagged Compliance_Review, and halts onboarding.
Zapier FlowFlow 3B (Identity Verification Handler — Veriff) · Flow 3.1 (BPS Manual Veriff Reset)
Zapier Table
3rd PartyVeriff (inbound webhook source — APPROVED / RESUBMISSION_REQUESTED / DECLINED / expired / abandoned) · Freshdesk (ticket creation on final fail and attempt-2 escalation —CR-20260720-004) · AWS SES (email dispatch)

No wireframe available. Stage 3 wireframes not yet in References/Wireframe/.


2. Trigger

Inbound Veriff webhook received by Middleware Hub (Process Veriff Handoff endpoint).

Webhook payload fields:

FieldTypeDescription
provider_signatureStringVeriff HMAC signature for payload authenticity
user_idUUIDTrader's internal ID
verification_statusEnum'APPROVED' / 'RESUBMISSION_REQUESTED' / 'DECLINED'
legal_nameStringExtracted from verified ID document (APPROVED only)
addressStringExtracted from verified ID document (APPROVED only)
kyc_countryStringCountry extracted from verified ID document (APPROVED only) — used by Flow 3D for ICA routing (STAGE3-045)
reasonStringPopulated on DECLINED — reason code (e.g.,Security_Reset)

(Source: RFQ_ Stack Trading Prop Tech V7.pdf §Process Veriff Handoff; Zapier Integration V7.pdf §Flow 3B)


🔄 CR — STAGE3-037 [CHR-46]: Flow 3B scope expanded to ALL traders. Ironbeam WLP / Flow 3B.2 deprecated.

3. Pre-conditions

IDCondition
P-1Trader's Asset_Class = 'Forex' — Flow 3B handles Forex KYC only; Futures KYC is handled by Flow 3B.2 (UC_5.3) UPDATED (STAGE3-037 [CHR-46] 2026-08-12): Flow 3B now handles ALL traders — both Futures and Forex. Futures traders use Veriff (Ironbeam manual KYC waived). UC_5.3 / Flow 3B.2 is deprecated.
P-2account_status = 'Passed_Challenge' — set by Flow 2.2 prior to Flow 3A execution
P-3identity_status = 'Pending' — set by Flow 3A
P-4Veriff HMAC signature is valid
P-5Freshdesk API is reachable (required only for DECLINED path)

4. Post-conditions

APPROVED path:

  • identity_status = 'Approved'
  • institution_approval_status = 'Approved' (simultaneously with identity approval)
  • Aggregation gate evaluated: if institution_approval_status = 'Approved' AND payout_status = 'Approved' → Flow 3D triggered
  • legal_name and address extracted from Veriff payload and saved to Users table (Ironbeam compliance handoff only — NOT used for Dots payee)

RESUBMISSION_REQUESTED path (attempt < 3):

  • Identity_Verification_Retry email dispatched to trader
  • veriff_attempts incremented by 1
  • Zap terminated — awaiting next Veriff webhook

RESUBMISSION_REQUESTED path (attempt = 3 — exhausted):

  • Treated as DECLINED: identity_status = 'Failed', veriff_failed_flag = true
  • Identity_Verification_Failed_Final email dispatched
  • Freshdesk high-priority ticket created (tag: Compliance_Review)
  • Onboarding halted

EXPIRED (Code 9104) or ABANDONED path (attempt 1–2):

  • New Veriff session generated via POST /sessions
  • veriff_attempts incremented by 1
  • Identity_Verification_Retry email dispatched with new link
  • If veriff_attempts = 2: Freshdesk support ticket also created (standard priority) — Ops notified while automation continues
  • Zap terminated — awaiting next Veriff webhook

EXPIRED or ABANDONED path (attempt = 3 — exhausted):

  • Same as DECLINED exhausted path: renewals halted; identity_status = 'Failed'; Identity_Verification_Failed_Final email; high-priority Freshdesk ticket (tag: Compliance_Review)
  • Total window: 7 days × 3 = 21 days maximum before permanent halt

DECLINED path:

  • identity_status = 'Failed', veriff_failed_flag = true
  • Identity_Verification_Failed_Final email dispatched
  • Freshdesk ticket created (tag: Compliance_Review)
  • Onboarding halted (unless reason = 'Security_Reset' — see BR_5.2.4)

5. Basic Flow

  1. Receive Veriff webhook. Middleware Hub receives the inbound Process Veriff Handoff POST request from Veriff.

  2. Validate HMAC signature.

    • Verify provider_signature using the Veriff shared secret.
    • If invalid → return HTTP 400; log security event; halt. (Source: RFQ_ Stack Trading Prop Tech V7.pdf §Process Veriff Handoff — Step 1: Security)
  3. Parse payload.

    • Extract: user_id, verification_status, legal_name, address, reason.

    • Save legal_name, address, and kyc_country to Users table (STAGE3-041 + STAGE3-045 2026-08-12):

      UPDATE Users
      SET legal_name   = payload.legal_name,
          address      = payload.address,
          kyc_country  = payload.kyc_country
      WHERE user_id = payload.user_id

      This write must occur for all APPROVED events. legal_name and address are required by two downstream consumers: (1) Ironbeam outbound compliance handoff (STAGE3-037 [CHR-46]); (2) Level 6 W-2 onboarding. kyc_country is required by a third consumer: (3) Flow 3D ICA routing — replaces Billing_Country as the source field for ICA contract selection (STAGE3-045). See BR_5.2.10.

    • If verification_status != 'APPROVED' → route to Outcome B/C/D. Dots payee creation does NOT run. (Source: RFQ_ Stack Trading Prop Tech V7.pdf §Process Veriff Handoff — Step 2: Parsing)

  4. Route by verification_status:

    → Outcome A: APPROVED

    4A-0. Returning trader health check (replaces simple null-check — CR-20260825-001).

    • Query: SELECT dots_payee_id FROM Users WHERE user_id = webhook.user_id.
    • IF dots_payee_id IS NULL: first cycle — proceed to 4A-1.
    • IF dots_payee_id IS NOT NULL: call Dots API GET /v2/users/{dots_payee_id} and validate all 5 conditions:
    FieldRequired
    status"verified"
    default_payout_methodnon-null
    compliance.must_collect_1099false
    compliance.w8_ben_collectedtrue or w8_ben_skipped (international only)
    compliance.flaggedfalse
    • All 5 pass: Skip steps 4A-1 through 4A-3. Proceed directly to 4A-4 and set payout_status = 'Approved' directly in DB — Dots does NOT re-issue an Active/Payable webhook for existing accounts. (Source: STAGE3-055 / H-07; health check extended CR-20260825-001)
    • Any condition fails:
      • status != 'verified' → escalate to Ops; block onboarding.
      • default_payout_method IS NULL → skip 4A-1 (user exists); proceed to 4A-3 to re-issue flow_link; dispatch payout email.
      • compliance.flagged == true → SEV-1 CloudWatch → Slack #risk-ops; block onboarding; escalate.
      • Other field failed → treat as partial; route through payout setup again.

    Note: Subscribe to user.updated Dots webhook to be notified when compliance fields change, rather than polling GET /v2/users/{id} repeatedly. (Source: CR-20260825-001)

    4A-1. Create Dots user (first cycle only) — POST /v2/users with Veriff legal name + SIM contact data.

    • Query Users table: first_name, last_name (from Veriff legal_name — already written at Step 3), email, country_code, phone_number.
    • CRITICAL — use Veriff legal name, not SIM registration name: first_name/last_name sent to POST /v2/users MUST be the legal name extracted by Veriff (stored in Users table at Step 3). Dots IRS TIN matching runs against the stored profile name, not against the W-9 payload, so profile name must match the trader's legal identity from the start. (Source: CR-20260825-001 — Dots bug confirmed 2026-08-25)
    • Call Dots API POST /v2/users:
      {
        "first_name":  "<Users.legal_name — first part, from Veriff>",
        "last_name":   "<Users.legal_name — last part, from Veriff>",
        "email":       "<Users.email>",
        "country_code": "<Users.country_code>",
        "phone_number": "<Users.phone_number>",
        "metadata": { "internal_id": "<user_id>" }
      }
    • Store returned Dots user ID as dots_payee_id in Users table.
    • Auth: Basic Auth — Base64(API Key + Shared Secret) in Authorization header (STAGE3-053 / H-05 confirmed 2026-08-15).
    • On non-200: Retry up to 8× Exponential Backoff (+5s, +15s, +1m, +5m, +15m, +1h, +3h, +12h) via BullMQ/Redis. After exhaustion → Dead Letter Queue + SEV1 Slack alert. (Source: STAGE3-085 / Kịch bản 4 confirmed 2026-08-15)

    4A-2. Pre-fill address on Dots profile — PUT /v2/users/{dots_payee_id}/addresses with Veriff-extracted address. (CR-20260825-001)

    • Endpoint: PUT /v2/users/{dots_payee_id}/addresses — this is the pre-fill endpoint (address only, no TIN, no signature required). NOT PUT /v2/users/{id}/compliance.
    • What PUT /compliance does (do NOT call from middleware): PUT /v2/users/{id}/compliance is the submission endpoint — it signs and finalizes the W-8BEN or W-9 form immediately. Once called successfully, the form is complete and the trader never sees the compliance step. Only call this endpoint if middleware has all required fields (W-9: TIN required; W-8BEN: DOB + signature object required). With the current flow where trader enters TIN/signs themselves, do NOT call PUT /compliance from middleware.
    • Address normalization (MANDATORY before API call): Middleware MUST parse the raw address string from Veriff webhook into the following JSON structure:
      {
        "line_1": "<street number + street name>",
        "line_2": "<apt / floor / unit — omit key if absent>",
        "city":   "<city or district>",
        "state":  "<province or state>",
        "postcode": "<max 5 chars — truncate if longer>",
        "country": "<ISO-3166 alpha-2>"
      }
      Combined line_1 + line_2 must be under 255 characters; truncate line_2 first if needed.
    • DOB null-safe (W-8BEN): Check date_of_birth from Veriff payload. If non-null: include in POST /v2/users payload for profile. If null: skip DOB — trader enters it manually in Dots Flow UI. Do NOT block onboarding on null DOB.
    • Result: When trader opens Dots Flow UI via flow_link, the W-8BEN/W-9 form is pre-filled with Legal Name (from Step 4A-1) and Address (from this step). For W-9: trader enters TIN only. For W-8BEN: trader enters DOB (if null) + citizenship country + digital signature.
    • 400 addressinvalid fallback: If Dots returns 400 addressinvalid, proceed with blank address profile. Trader enters address manually in Dots Flow UI. Non-blocking. See Exc-7.
    • Separation of concerns: legal_name/address for Dots compliance = Veriff-extracted (verified). email/country_code/phone_number for Dots user contact = SIM registration data (step 4A-1). (Source: STAGE3-052 / H-04, confirmed 2026-08-15; endpoint corrected CR-20260825-001)

    4A-3. Generate personalized Dots flow link — POST /v2/flows (manage-payouts step).

    • Call Dots API POST /v2/flows with manage-payouts step type.
    • Receive flow_link — personalized, session-scoped payout setup URL with pre-filled tax form.
    • Store flow_link in Users table (payout_flow_link or equivalent column) for email dispatch.

    4A-4. Update KYC and payout status.

    -- First-cycle path (dots_payee_id was NULL):
    UPDATE Users
    SET identity_status               = 'Approved',
        institution_approval_status   = 'Approved'
    WHERE user_id = webhook.user_id
    
    -- Second-cycle path (dots_payee_id was NOT NULL — H-07):
    UPDATE Users
    SET identity_status               = 'Approved',
        institution_approval_status   = 'Approved',
        payout_status                 = 'Approved'
    WHERE user_id = webhook.user_id

    Note on institution_approval_status: Applies to ALL traders (Futures + Forex) per STAGE3-037 [CHR-46]. (Source: STAGE3-037 [CHR-46] confirmed 2026-08-12)

    4A-5. Dispatch "Payout Profile Setup" email (first cycle only).

    • Send email via AWS SES containing flow_link to trader's registered email.
    • Template: Payout_Profile_Setup (or Level_6_International_Contractor_Dots_Profile_Action_Needed for international path — BA to confirm exact template key per Billing_Country routing).
    • Second cycle: Skip — payout_status already set to 'Approved' at 4A-4; no payout email dispatched.

    4A-6. Proceed to Step 5: Aggregation Check.


    → Outcome B: RESUBMISSION_REQUESTED

    4B-1. Increment veriff_attempts counter in Users table.

    • Check current veriff_attempts value.
    • IF veriff_attempts < 3: send Identity_Verification_Retry email containing new session link. Terminate Zap. (Source: Zapier Integration V7.pdf §Flow 3B — Outcome B)
    • IF veriff_attempts >= 3: treat as DECLINED → proceed to Outcome C path.

    → Outcome C: DECLINED

    4C-1. Security Reset bypass check.

    • IF reason == 'Security_Reset' (from Flow 16): ALLOW re-entry. Generate new Veriff session link and send retry email. Do NOT set identity_status = 'Failed'. (Source: Zapier Integration V7.pdf §Flow 3B — Outcome C bypass)
    • ELSE: proceed to 4C-2.

    4C-2. Send Identity_Verification_Failed_Final email to trader.

    4C-3. Create Freshdesk ticket and send Slack alert for Operations.

    • Create ticket via Freshdesk API with the following mandatory fields:
    FieldValue
    Subject"KYC DECLINED — [trader legal_name] ([user_id])"
    PriorityHigh
    TagCompliance_Review
    user_idwebhook.user_id
    emailtrader's email from Users table
    legal_nameextracted from Veriff APPROVED data (or Users table if already written)
    veriff_session_urlVeriff session URL for this verification attempt
    failure_reason_codewebhook.reason (e.g. "DOCUMENT_NOT_SUPPORTED", "FACE_NOT_MATCHING", etc.)
    • Send standard Slack webhook to Ops Slack room simultaneously. (Client confirmed 2026-08-19: ticket MUST contain User ID, Email, Legal Name, Veriff Session URL, and the specific failure reason code from Veriff. Slack alert to Ops room confirmed.) (Source: Zapier Integration V7.pdf §Flow 3B — Outcome C; CR-20260720-004)

    4C-4. Update Users table:

    UPDATE Users
    SET identity_status     = 'Failed',
        veriff_failed_flag  = true
    WHERE user_id = webhook.user_id

    4C-5. HALT — Zap terminates. No further onboarding steps fire.


    🔄 CR — STAGE3-023 [CHR-43]: EXPIRED and ABANDONED events added as Outcome D. Auto-renewal via POST /sessions, veriff_attempts increment, Freshdesk escalation at attempt 2.

    → Outcome D: EXPIRED (Code 9104) or ABANDONED

    4D-1. Increment veriff_attempts.

    • UPDATE Users SET veriff_attempts = veriff_attempts + 1 WHERE user_id = webhook.user_id
    • Read updated veriff_attempts value.

    4D-2. Hard limit check.

    • IF veriff_attempts >= 3: HALT auto-renewal. Proceed to Outcome C path (4C-2 → 4C-5). (Source: STAGE3-023 [CHR-43] confirmed 2026-08-11 — max 3 retries rule applies across all verification event types)

    4D-3. Generate new Veriff session.

    • Call Veriff POST /sessions to create a fresh session URL.
    • Save new session URL to Users table. (Source: STAGE3-023 [CHR-43] confirmed 2026-08-11)

    4D-4. Send renewal email.

    • Dispatch Identity_Verification_Retry email via AWS SES with new session link. (Source: STAGE3-023 [CHR-43] — standard Identity_Verification_Retry template used; no dedicated template)

    4D-5. Support escalation check (Attempt 2 only).

    • IF veriff_attempts = 2: simultaneously:
      1. Trigger Freshdesk API to create support ticket (standard priority) with mandatory fields:
    FieldValue
    Subject"KYC Escalation (Attempt 2) — [trader legal_name] ([user_id])"
    PriorityNormal
    TagCompliance_Review
    user_idwebhook.user_id
    emailtrader's email from Users table
    legal_namefrom Users table
    veriff_session_urlnew session URL from Step 4D-3
    failure_reason_codewebhook.reason (event type: expired / abandoned)
    1. Send standard Slack webhook to Ops Slack room to alert Operations.
    • Both actions are non-blocking — automation continues regardless of outcome. (Client confirmed 2026-08-19: mandatory ticket fields confirmed; Slack webhook to Ops room confirmed.) (Source: STAGE3-023 [CHR-43] confirmed 2026-08-11)

    4D-6. HALT — Zap terminates. Awaiting next Veriff webhook (next attempt or APPROVED).

  5. Aggregation Check (APPROVED path only).

    • Query Users table: SELECT identity_status, institution_approval_status, payout_status FROM Users WHERE user_id = webhook.user_id.
    • IF institution_approval_status = 'Approved' AND payout_status = 'Approved' → trigger Flow 3D via internal webhook.
    • ELSE → terminate Zap; wait for remaining approvals.

      Note: identity_status is fetched for completeness and auditability. The gate condition checks institution_approval_status and payout_status only (per Zapier V7 §Flow 3B) because identity_status was just set to 'Approved' in Step 4A-4 of this same execution — it is guaranteed 'Approved' at this point. In the second-cycle path (H-07), all three fields are set atomically and the gate fires immediately without a query. (Source: Zapier Integration V7.pdf §Flow 3B — Aggregation Check)

  6. Terminate Zap. (All paths except aggregation gate firing → Flow 3D)


6. Alternative Flows

Alt-1 — Trader in second or later KYC cycle (dots_payee_id IS NOT NULL at APPROVED).

  • Trigger: Veriff APPROVED webhook fires, but Users table already has dots_payee_id populated.
  • Behavior (STAGE3-055 / H-07): Middleware detects dots_payee_id IS NOT NULL at Step 4A-0. Skips Dots POST /v2/users + Submit Compliance + POST /v2/flows (steps 4A-1 through 4A-3). Sets payout_status = 'Approved' directly in DB (step 4A-4 second-cycle path). No payout onboarding email dispatched. Aggregation check fires immediately — if identity_status + institution_approval_status + payout_status all 'Approved', trigger Flow 3D.
  • Rationale: Dots does NOT re-issue an Active/Payable webhook for existing payee accounts. Payout is set directly by Middleware rather than waiting for a Dots webhook that will never arrive. (Source: STAGE3-055 confirmed 2026-08-15)

Alt-2 — First-cycle Veriff APPROVED: Dots steps complete, payout email sent, but trader has not yet completed payout setup (Flow 3C Dots webhook pending).

  • Veriff returns APPROVED, Dots 3-step completes, flow_link dispatched in payout email.
  • payout_status remains 'Pending' (trader hasn't finished Dots payout portal yet) → aggregation gate holds → Zap terminates and waits.
  • When Flow 3C fires later (Dots Active/Payable webhook) and sets payout_status = 'Approved', that flow's own aggregation check will trigger Flow 3D.

Alt-3 — BPS admin triggers Manual Veriff Reset (Flow 3.1).

  • Trigger: Middleware Hub receives webhook VERIFF_MANUAL_RESET (from BPS admin action via POST /kyc-reset).
  • Action: Zapier generates a new Veriff session link via Veriff API.
  • Email: "Action Required: Your ID Verification has been reset. Please try again using clear lighting and a valid government ID." (with session link included).
  • Slack alert sent to Operations: "Veriff session manually reset for Trader [ID].".
  • Clears veriff_failed_flag = false and resets veriff_attempts = 0 in Users table. (Source: Zapier Integration V7.pdf §Flow 3.1: BPS Manual Veriff Reset; RFQ_ Stack Trading Prop Tech V7.pdf §Reset Veriff KYC)

7. Exceptional Flows

Exc-1 — Invalid HMAC signature (Step 2).

  • Middleware returns HTTP 400. Security event logged. Zap does not proceed.
  • ⚠️ [ASSUMPTION] Alert to Operations / security monitoring. BA to confirm alerting path.

Exc-2 — Dots API failure during 3-step payee creation (Steps 4A-1, 4A-2, or 4A-3).

  • Dots POST /v2/users, Submit Compliance, or POST /v2/flows returns non-200 or connection timeout.
  • Retry: Exponential Backoff 8× via BullMQ/Redis queue (+5s, +15s, +1m, +5m, +15m, +1h, +3h, +12h — ~16h total). (Source: STAGE3-085 / Kịch bản 4 confirmed 2026-08-15)
  • On exhaustion: Dead Letter Queue + SEV1 Slack alert to #ops-compliance + Ops intervenes via Ops Console.
  • identity_status / institution_approval_status: NOT updated until Dots steps complete. Prevents aggregation gate from firing without a valid flow_link.
  • Payout email: NOT dispatched until flow_link received at step 4A-3.
  • Special case — POST /v2/users returns HTTP 200 but no payee_id: Treated as Payload Validation Exception. Validation Gate blocks NULL write to dots_payee_id, enqueues retry. (Source: STAGE3-069 / M-10 confirmed 2026-08-15)

Exc-3 — Freshdesk API failure on DECLINED (Step 4C-3).

  • Freshdesk ticket cannot be created.
  • Confirmed (client 2026-08-19): Log error; send Slack webhook to Ops Slack room as fallback notification. identity_status = 'Failed' write still proceeds regardless of ticket creation outcome — Freshdesk failure is non-blocking.

Exc-4 — Users table write failure (Step 4A-1 or 4C-4).

  • DB update fails for identity_status / institution_approval_status / veriff_failed_flag.
  • ⚠️ [ASSUMPTION] Log DB error; alert Operations. Retry logic TBD. BA to confirm rollback behavior.

Exc-5 — Duplicate Veriff webhook (same event fires twice).

  • Veriff may retry delivery if the first webhook does not return HTTP 200 within timeout.
  • ⚠️ [ASSUMPTION] No explicit idempotency guard documented. Duplicate processing could double-increment veriff_attempts or duplicate Freshdesk ticket creation. BA to confirm idempotency guard using provider_event_id.
  • Note: Users table has a provider_event_id column (String, Unique Index) — this field may serve as the deduplication key. BA to confirm. (Source: Zapier Integration V7.pdf §Users table schema — provider_event_id)

Exc-6 — Veriff POST /sessions failure during auto-renewal (Step 4D-3).

  • If the Veriff POST /sessions call fails (connection error or non-200) during auto-renewal of an expired/abandoned session:
  • Renewal halted. veriff_attempts has already been incremented. Send Slack webhook to Ops Slack room for manual follow-up.
  • ⚠️ [OPEN] Whether the incremented veriff_attempts is rolled back on renewal failure, and whether fallback to manual Ops reset (Flow 3.1) is automatically triggered, are not yet confirmed. BA to confirm. (Source: STAGE3-023 [CHR-43] confirmed 2026-08-11 — auto-renewal path requires POST /sessions; failure path not explicitly addressed)

Exc-7 — 400 addressinvalid from Dots during compliance submission (Step 4A-2 — CR-20260825-001).

  • Cause: Dots rejects the address from the Veriff-extracted payload because it fails the Google Address Validator or USPS validator (applies to 37 validated countries).
  • Behavior: Do NOT block the onboarding flow. Log the address validation failure to CloudWatch. Proceed with a Dots payee profile that has no pre-filled address.
  • Action: Continue to Step 4A-3 (POST /v2/flows) to generate flow_link as normal. When trader opens the Dots payout portal, they will see the address fields blank and must enter their address manually.
  • Alerting: Log address_prefill_skipped=true to bps_audit_logs for the user_id. No Slack alert required — non-blocking, trader self-serves via Dots UI.
  • Field lock note: Once trader submits address in Dots Flow UI and Dots locks the field, the address cannot be overwritten via API. Do NOT retry the PUT /compliance address pre-fill after the trader has completed the form. (Source: CR-20260825-001)

8. Business Rules

🔄 CR — STAGE3-037 [CHR-46]: Flow 3B scope changed to all traders. Ironbeam WLP / UC_5.3 deprecated.

<a id="BR_5.2.1"></a>

BR_5.2.1: Flow 3B applies to ALL traders — UPDATED (STAGE3-037 [CHR-46] 2026-08-12)

Flow 3B processes Veriff webhooks for Asset_Class = 'Forex' traders only. Futures KYC is handled by Flow 3B.2 (UC_5.3) via the Ironbeam email parser. There is no Veriff session for Futures traders.

Flow 3B now processes Veriff webhooks for ALL traders — both Futures and Forex. Ironbeam confirmed that because traders are independent contractors trading corporate capital, their full manual KYC applications are waived. All traders go through Veriff for identity verification. UC_5.3 / Flow 3B.2 is deprecated (STAGE3-039 [CHR-46]).

(Source: STAGE3-037 confirmed 2026-08-12 — supersedes Zapier Integration V7.pdf §Flow 3A Futures branch)


🔄 CR — STAGE3-037 [CHR-46]: institution_approval_status now set synchronously for all traders at Flow 3B APPROVED. Flow 3B.2 / UC_5.3 deprecated.

<a id="BR_5.2.2"></a>

BR_5.2.2: institution_approval_status auto-approved with identity — for ALL traders (STAGE3-037 [CHR-46] 2026-08-12)

For ALL traders (Futures and Forex), institution_approval_status is set to 'Approved' simultaneously with identity_status = 'Approved' on Veriff APPROVED. There is no separate institution approval step.

For Futures traders, institution_approval_status is set separately by Flow 3B.2 (Ironbeam email parser — UC_5.3). DELETED — Flow 3B.2 / UC_5.3 deprecated (STAGE3-037 [CHR-46]/039 2026-08-12).

(Source: STAGE3-037 [CHR-46] confirmed 2026-08-12; Zapier Integration V7.pdf §Flow 3B — Outcome A: IF Asset_Class == 'Forex', Set institution_approval_status = 'Approved' [now applies to all traders])


<a id="BR_5.2.3"></a>

BR_5.2.3: Retry limit — max 3 Veriff attempts (shared counter)

veriff_attempts is a shared counter across ALL verification event types: RESUBMISSION_REQUESTED, expired (Code 9104), and abandoned. The counter increments by 1 on each event regardless of type. At veriff_attempts = 3, the system switches to the DECLINED path: identity_status = 'Failed', veriff_failed_flag = true, final-fail email dispatched, high-priority Freshdesk ticket created (tag: Compliance_Review). Total maximum window: 7 days × 3 = 21 days.

Counter is reset to 0 by BPS POST /kyc-reset (Flow 3.1 — Alt-3).

(Source: Zapier Integration V7.pdf §Flow 3B — Outcome B: Limit: Max 3 Retries; STAGE3-023 [CHR-43] confirmed 2026-08-11 — "7 days × 3"; counter shared across event types)


<a id="BR_5.2.4"></a>

BR_5.2.4: Security Reset bypass on DECLINED

If reason == 'Security_Reset' in the DECLINED webhook (originating from Flow 16 — Security Reset Protocol MFA), the DECLINED outcome is overridden: the trader is ALLOWED re-entry. A new Veriff session link is generated and sent. identity_status is NOT set to 'Failed'.

This bypass only applies when the DECLINED reason is explicitly Security_Reset. All other DECLINED reasons follow the standard halt path.

(Source: Zapier Integration V7.pdf §Flow 3B — Outcome C: Bypass Check: IF Reason == Security_Reset (from Flow 16), ALLOW re-entry)


<a id="BR_5.2.5"></a>

BR_5.2.5: Freshdesk ticket — mandatory fields and Slack alert

Per CR-20260720-004, Freshdesk replaces Zendesk for all support ticketing. The Zapier source (zapier_v7_full.txt §Flow 3B) references Zendesk API — this is superseded.

Every Freshdesk ticket created by UC_5.2 MUST include the following fields (client confirmed 2026-08-19):

Mandatory fieldSource
user_idwebhook.user_id
emailUsers table
legal_nameUsers table (written at Veriff APPROVED)
veriff_session_urlCurrent Veriff session URL
failure_reason_codewebhook.reason (specific Veriff failure reason code, e.g. DOCUMENT_NOT_SUPPORTED, FACE_NOT_MATCHING, expired, abandoned)

Slack alert: A standard Slack webhook MUST also be sent to the Ops Slack room whenever a Freshdesk ticket is created (DECLINED path and attempt-2 escalation). The Slack alert is non-blocking. (Client confirmed 2026-08-19.)

Tag Compliance_Review is applied on both the DECLINED ticket (Step 4C-3) and the attempt-2 escalation ticket (Step 4D-5).

Identity_Verification_Failed_Final email is fully automated via AWS SES — it is NOT sent manually by the Ops team. (Client confirmed 2026-08-19.)

veriff_attempts counter is owned by our system — Veriff does NOT track our 3-strike rule across multiple sessions. The system MUST increment veriff_attempts in the Users table on every DECLINED / expired / abandoned event. Veriff's DECLINED status alone does not indicate the attempt count. (Client confirmed 2026-08-19.)

(Source: CR-20260720-004 — CR wins over zapier_v7_full.txt §Flow 3B; client confirmed 2026-08-19)


<a id="BR_5.2.6"></a>

BR_5.2.6: Aggregation gate — three conditions required for Forex

Flow 3D is triggered only when ALL three of the following are true for the same user_id:

  • identity_status = 'Approved' (set by Flow 3B — this UC)
  • institution_approval_status = 'Approved' (set by Flow 3B simultaneously for Forex)
  • payout_status = 'Approved' (set by Flow 3C — UC_5.4)

If payout_status is still 'Pending' at the time Flow 3B fires, the gate holds and waits. Flow 3C's own aggregation check will re-evaluate and fire Flow 3D when it completes.

(Source: Zapier Integration V7.pdf §Flow 3B — Aggregation Check)


<a id="BR_5.2.7"></a>

BR_5.2.7: Dots payee creation — 3-step process in Flow 3B (Process Veriff Handoff) after APPROVED

Dots payee creation is a 3-step sequential process triggered inside Flow 3B immediately after Veriff APPROVED and only when dots_payee_id IS NULL (first cycle):

  1. POST /v2/users — creates Dots user with Veriff-extracted legal_name (split into first/last) + SIM contact fields (email, country_code, phone_number, metadata.internal_id). Must use Veriff legal name — NOT SIM registration name — because Dots IRS TIN matching runs against stored profile name, not W-9 payload (Dots bug, fix in progress as of 2026-08-25).
  2. PUT /v2/users/{dots_payee_id}/addresses — pre-fills normalized Veriff address on Dots profile (line_1/line_2/city/state/postcode/country). No TIN, DOB, or signature required. This populates the address field on W-8BEN/W-9 form in Dots Flow UI. See BR_5.2.11 for normalization rules.
  3. POST /v2/flows (manage-payouts step) — generates personalized flow_link for "Payout Profile Setup" second email.

What trader does in Dots Flow UI: Sees Legal Name + Address pre-filled. For W-9: enters TIN only. For W-8BEN: enters DOB (if not pre-filled) + citizenship country + signs.

PUT /v2/users/{id}/compliance — NOT called from middleware in current flow: This endpoint signs and finalizes the form immediately. Only invoke if middleware has all required fields (TIN for W-9; DOB + signature for W-8BEN). With current design where trader self-enters TIN/signs, do not call this endpoint.

Second cycle (returning trader health check passes — all 5 fields OK): Steps 1–3 are skipped. Middleware sets payout_status = 'Approved' directly (STAGE3-055 / H-07). No payout email. See BR_5.2.12 for health check rules.

Second cycle (health check partial — any field fails): Skip step 1 only (Dots user exists); run steps 2–3 as needed based on which fields failed.

Auth for Dots API calls: Basic Auth — Base64(API Key + Shared Secret) in Authorization header (STAGE3-053 / H-05).

(Source: Zapier Integration V7.pdf §Flow 3B; STAGE3-050 / STAGE3-052 / STAGE3-055 confirmed 2026-08-15; pre-fill endpoint corrected CR-20260825-001 2026-08-25)


<a id="BR_5.2.8"></a>

BR_5.2.8: provider_event_id as deduplication key

Users table contains a provider_event_id column (String, Unique Index). This field is intended to prevent duplicate processing of the same Veriff webhook event. Middleware must reject (or idempotently handle) duplicate webhook deliveries where provider_event_id already exists in the DB. ⚠️ [ASSUMPTION — BA to confirm idempotency implementation details]

(Source: Zapier Integration V7.pdf §Users table schema — provider_event_id (String, Unique Index))


🔄 CR — STAGE3-023 [CHR-43]: EXPIRED and ABANDONED events added as Outcome D. Auto-renewal via POST /sessions, veriff_attempts increment, Freshdesk escalation at attempt 2, hard limit at attempt 3.

<a id="BR_5.2.9"></a>

BR_5.2.9: Auto-renewal on expired/abandoned — Freshdesk escalation at attempt 2

When a Veriff expired (Code 9104) or abandoned webhook is received and veriff_attempts becomes exactly 2 after incrementing, the system MUST simultaneously:

  1. Execute auto-renewal (call Veriff POST /sessions, send Identity_Verification_Retry email).
  2. Create a standard-priority Freshdesk support ticket to alert Operations for follow-up.

The Freshdesk ticket creation at attempt 2 is non-blocking — it must NOT prevent the renewal email from being sent. Automation continues regardless of Freshdesk ticket creation outcome.

At veriff_attempts = 3, the system switches to the DECLINED path (see BR_5.2.3) — no further renewal attempted.

(Source: STAGE3-023 [CHR-43] confirmed 2026-08-11 — "Support Escalation (Attempt 2)"; "Hard Limit (Attempt 3)")


🔄 CR — STAGE3-041 + STAGE3-045: legal_name, address, and kyc_country must be written to Users table atomically on APPROVED. kyc_country replaces Billing_Country as ICA routing source in Flow 3D.

<a id="BR_5.2.10"></a>

The PostgreSQL Users table must include three new columns:

  • legal_name (String)
  • address (JSON or formatted String)
  • kyc_country (String) — country extracted from Veriff government ID document

When Process Veriff Handoff parses the webhook and verification_status = 'APPROVED', the backend MUST write the extracted legal_name, address, and kyc_country to these columns in the same DB transaction as the KYC status update.

Reason — three downstream consumers require this data:

  1. Ironbeam compliance handoff (STAGE3-037 [CHR-46]): After Veriff APPROVED for a Futures trader, Node.js Middleware must automatically assemble and transmit a compliance package to Ironbeam's compliance team. The package must contain all four of the following components:
    • Veriff KYC result data (JSON payload from webhook)
    • All supporting PII identity documents (passport/ID photo + selfie) — downloaded by Middleware via the Veriff Media API immediately after APPROVED webhook is received
    • Trader's full legal name (legal_name)
    • Assigned Ironbeam sub-account number (fcm_subaccount_id)
    • Transfer mechanism: CONFIRMED (Ironbeam 2026-08-13) — SFTP drop or Secure Shared Drive (Ironbeam confirmed both options work; Stack Trading to select preferred method before implementation).
    • Notification cadence: CONFIRMED (Ironbeam 2026-08-13) — end of day (EOD) batch summary report.
  2. Level 6 W-2 onboarding: The Execute Level 6 Transition endpoint requires stored KYC name and address data to pre-fill the Rippling W-2 (/worker.hire) onboarding.
  3. Flow 3D ICA routing (STAGE3-045): Flow 3D must use kyc_country (not Billing_Country) to select the correct Rippling ICA variant. kyc_country is guaranteed non-NULL at Flow 3D trigger time — if Veriff fails to extract a country, KYC fails and Flow 3D never fires.

(Source: STAGE3-041 confirmed 2026-08-12; STAGE3-045 confirmed 2026-08-12)


<a id="BR_5.2.11"></a>

BR_5.2.11: Address normalization rules before Dots compliance submission (CR-20260825-001)

Before calling PUT /v2/users/{dots_payee_id}/compliance, Middleware MUST normalize the raw address extracted from the Veriff webhook into a structured JSON object. Five rules apply:

  1. JSON structure: Parse raw address string into line_1 (street), line_2 (apt/unit/floor — omit key if absent), city, state, postcode, country (ISO-3166 alpha-2).
  2. 255-character constraint: Combined line_1 + line_2 must be under 255 characters. If over, truncate line_2 first, then line_1 as last resort.
  3. ZIP/postcode truncation: Truncate postcode to exactly 5 characters before submission. Dots applies the same truncation server-side, but pre-truncating avoids ambiguity.
  4. 37-country validator: For the 37 countries where Dots uses Google Address Validator (international) or USPS (US), an address that fails validation returns 400 addressinvalid. See Exc-7 for fallback behavior — this is non-blocking.
  5. No auto-void / field lock: Once a field is submitted and accepted by Dots, it is locked — cannot be overwritten via API. Do NOT re-submit PUT /compliance after the trader has completed the form in Dots Flow UI. If a field needs correction after lock, trader must contact Dots support directly.

UTF-8 / TIN matching note: Dots stores all name and address data as UTF-8 (diacritics supported). For US W-9 IRS TIN matching, Dots transliterates the stored legal name to ASCII [A-Za-z0-9& -] before submitting to IRS. Names with non-Latin scripts (Chinese, Arabic, etc.) will fail IRS matching. BA to flag if non-Latin-script traders exist in target markets.

(Source: CR-20260825-001 — Dots vendor response 2026-08-25)


<a id="BR_5.2.12"></a>

BR_5.2.12: Returning trader 5-field Dots health check (CR-20260825-001)

When dots_payee_id IS NOT NULL at Step 4A-0, Middleware MUST call GET /v2/users/{dots_payee_id} and validate all 5 compliance fields before bypassing Dots creation:

FieldRequired valueOn failure
status"verified"Escalate to Ops; block onboarding
default_payout_methodnon-nullRe-issue POST /v2/flows payout link (skip step 4A-1 only)
compliance.must_collect_1099false (US traders)Escalate; trader may need to re-submit W-9
compliance.w8_ben_collectedtrue or w8_ben_skipped (international)Escalate; trader may need to re-submit W-8BEN
compliance.flaggedfalseSEV-1 CloudWatch → Slack #risk-ops; block onboarding

All 5 pass: Proceed directly to Step 4A-4; set payout_status = 'Approved' without calling Dots APIs (H-07 logic preserved).

Any field fails: Do NOT set payout_status = 'Approved'. Handle per the "On failure" column above.

Webhook subscription: Subscribe to Dots user.updated event to receive real-time updates when compliance fields change, rather than polling GET /v2/users/{id}.

(Source: CR-20260825-001 — Dots vendor response 2026-08-25; STAGE3-055 / H-07 baseline)


9. NFRs

AreaRequirement
SecurityHMAC signature (provider_signature) MUST be validated before any payload is processed. Invalid signature → reject and log immediately.
Idempotencyprovider_event_id (Unique Index) must be used to detect duplicate Veriff webhook deliveries. See BR_5.2.8. ⚠️ [ASSUMPTION — implementation TBD]
AtomicityFor APPROVED path:identity_status + institution_approval_status updates MUST be atomic. Partial writes could leave the aggregation gate in an indeterminate state.
AuditAll Veriff webhook events (APPROVED / RESUBMISSION_REQUESTED / DECLINED) must be logged with user_id, verification_status, reason, timestamp, and action taken.
3rd Party SLAFreshdesk ticket creation (DECLINED path) is non-blocking — ticket creation failure must not prevent identity_status = 'Failed' from being written.
Retry email deliveryIdentity_Verification_Retry email must include an active session link. If the Veriff session has expired, a new session must be generated before the email is sent. ⚠️ [ASSUMPTION — BA to confirm session re-generation logic on retry]

10. Acceptance Criteria

IDScenarioExpected Result
AC-5.2-01Veriff APPROVED, dots_payee_id IS NULL (first cycle, any trader)legal_name, address, kyc_country saved; Dots POST /v2/users called with SIM data → dots_payee_id stored; Submit Compliance called with Veriff data; POST /v2/flows called → flow_link stored; identity_status = institution_approval_status = 'Approved' written; "Payout Profile Setup" email dispatched with flow_link; aggregation gate evaluated
AC-5.2-02Veriff APPROVED, dots_payee_id IS NOT NULL (second cycle)Steps 4A-1 through 4A-3 skipped; identity_status = institution_approval_status = 'Approved' + payout_status = 'Approved' written directly; no payout email; aggregation gate fires immediately if all conditions met (STAGE3-055 / H-07)
AC-5.2-03Veriff APPROVED,payout_status = 'Approved' already setAggregation gate passes; Flow 3D triggered via internal webhook
AC-5.2-04Veriff APPROVED,payout_status = 'Pending'Aggregation gate holds; Zap terminates; no Flow 3D trigger
AC-5.2-05First RESUBMISSION_REQUESTED webhook (veriff_attempts = 0)veriff_attempts incremented to 1; Identity_Verification_Retry email sent with session link; Zap terminates
AC-5.2-06Second RESUBMISSION_REQUESTED webhook (veriff_attempts = 1)veriff_attempts incremented to 2; retry email sent again; Zap terminates
AC-5.2-07Third RESUBMISSION_REQUESTED webhook (veriff_attempts = 2)Treated as DECLINED:identity_status = 'Failed', veriff_failed_flag = true; Identity_Verification_Failed_Final email sent; Freshdesk ticket created with tag Compliance_Review
AC-5.2-08DECLINED webhook with reason ≠ 'Security_Reset'identity_status = 'Failed', veriff_failed_flag = true; final-fail email sent; Freshdesk ticket created; onboarding halted
AC-5.2-09DECLINED webhook with reason = 'Security_Reset' (from Flow 16)Standard DECLINED path bypassed; new Veriff session link generated and sent;identity_status NOT set to 'Failed'
AC-5.2-10Webhook arrives with invalid HMAC signatureHTTP 400 returned; no DB writes; security event logged
AC-5.2-11Same provider_event_id arrives twice (duplicate webhook)Second webhook rejected / idempotently ignored; no duplicate DB writes, emails, or Freshdesk tickets
AC-5.2-12BPS admin triggers Flow 3.1 (POST /kyc-reset)New Veriff session generated; retry email sent to trader;veriff_failed_flag = false, veriff_attempts = 0; Slack alert to Operations
AC-5.2-13Freshdesk API returns non-200 on DECLINED pathidentity_status = 'Failed' write still proceeds; Freshdesk failure logged; Slack alert as fallback
AC-5.2-14Dots POST /v2/users returns HTTP 200 but response body lacks payee_idValidation Gate rejects NULL write; Payload Validation Exception thrown; task enqueued for BullMQ retry (STAGE3-069 / M-10)
AC-5.2-15expired (Code 9104) webhook received, veriff_attempts = 0veriff_attempts incremented to 1; Veriff POST /sessions called; new session URL saved; Identity_Verification_Retry email sent; no Freshdesk ticket; Zap terminates
AC-5.2-16abandoned webhook received, veriff_attempts = 1veriff_attempts incremented to 2; Veriff POST /sessions called; renewal email sent; Freshdesk support ticket created simultaneously; Zap terminates
AC-5.2-17expired webhook received, veriff_attempts = 2veriff_attempts incremented to 3; HALT auto-renewal; Identity_Verification_Failed_Final email sent; high-priority Freshdesk ticket created (tag: Compliance_Review); identity_status = 'Failed'; veriff_failed_flag = true
AC-5.2-18RESUBMISSION_REQUESTED webhook received, veriff_attempts = 1; then expired webhook receivedSecond event:veriff_attempts incremented to 2; renewal email sent + Freshdesk escalation ticket created (counter is shared across event types)

11. Update History

| Date | Version | Section | Change From | Change To | Source |

2026-08-19v1.10 → v2.0§5 Step 4C-3, Step 4D-5; §7 Exc-3, Exc-6; §8 BR_5.2.5Step 4C-3/4D-5: Freshdesk ticket fields unspecified. Exc-3: [ASSUMPTION]. Exc-6: Slack unconfirmed. BR_5.2.5: veriff_attempts ownership and email automation not documented.Freshdesk mandatory ticket payload table added (User ID, Email, Legal Name, Veriff Session URL, failure reason code). Slack webhook to Ops confirmed on DECLINED and attempt-2 escalation. Exc-3 confirmed: Slack fallback on Freshdesk API failure. BR_5.2.5 rewritten: email via AWS SES automated, veriff_attempts tracked by system (not Veriff), Slack alert mandatory.Client confirmed 2026-08-19
2026-08-15v1.8 → v1.9§1 Description, §5 Step 4A (all sub-steps), §6 Alt-1/Alt-2, §7 Exc-2, §8 BR_5.2.7, §10 AC-5.2-01/02/14Step 4A had only identity_status + institution_approval_status update; no Dots call; Alt-1/Exc-2 marked N/AProcess Veriff Handoff now owns full 3-step Dots payee creation (POST /v2/users SIM data → Submit Compliance Veriff data → POST /v2/flows → flow_link). Step 4A-0 second-cycle check (H-07). Alt-1 rewritten. Exc-2 restored with Dots failure handling + 8× retry + Dead Letter Queue. BR_5.2.7 updated. AC-5.2-01/02/14 updated.STAGE3-050/052/053/055/069/085 confirmed 2026-08-15
2026-08-16v1.9 → v1.10§5 Step 5 Aggregation Check — SQL querySELECT institution_approval_status, payout_status (missing identity_status)Added identity_status to SELECT for completeness/auditability. Added note: gate condition still checks institution_approval_status + payout_status only (identity_status guaranteed Approved at this step).
2026-08-15v1.7 → v1.8§5 Step 4A-1/4A-2/4A-3, §6 Alt-1, §7 Exc-2, §8 BR_5.2.7, §11 AC-5.2-01/02/14Dots POST /payees called inside Process Veriff Handoff (Step 4A-2), using Veriff-extracted legal_name/address; identity_status gated on Dots successDots creation moved to Flow 3A (UC_5.1) using SIM registration data. Flow 3B only sets identity_status and institution_approval_status. No Dots call, no dots_payee_id check in Process Veriff Handoff. Alt-1, Exc-2, AC-5.2-01/02/14, BR_5.2.7 updated accordingly.Confirmed 2026-08-15 (later superseded by v1.9)
2026-08-12v1.5 → v1.6§5 Step 4A-2Step 4A-2 note clarifiedRemoved erroneous STAGE3-046 note. Per Zapier V7, Flow 3A creates Dots and KYC simultaneously. UC_5.2 Step 4A-2 creates the Dotspayee profile (post-Veriff APPROVED), which is a distinct step from the initial onboarding link generated in Flow 3A.STAGE3-046 reverted — Zapier V7 original spec applies
2026-08-12v1.4 → v1.5§2 Trigger / §5 Step 3 / §8 BR_5.2.10kyc_country field absentkyc_country added to Veriff webhook payload table; written to Users table at APPROVED alongside legal_name/address; BR_5.2.10 updated to list three downstream consumers (Ironbeam, Level 6 W-2, Flow 3D ICA routing)STAGE3-045 confirmed 2026-08-12
2026-08-12v1.3 → v1.4§5 Step 3 — parse stepExtracted user_id, verification_status, legal_name, address (no explicit DB save)legal_name and address must be saved to Users table at this step (STAGE3-041). Two new DB columns required.STAGE3-041 confirmed 2026-08-12
2026-08-14v1.6 → v1.7§5 Step 4A-2 / §7 Exc-2 — Dots sequencing conflict flag removed⚠️ STAGE3-036 flagged: "Dots begins ONLY AFTER both Veriff AND Rippling contract complete — current Flow 3B call is architecturally incorrect, structural rewrite required"Flag incorrect. Correct sequence confirmed: Dots payee created at Veriff APPROVED (Flow 3B) → trader completes Dots onboarding (payout_status = 'Approved', Flow 3C) → aggregation gate → Flow 3D sends Rippling ICA. Dots completes BEFORE Rippling, not after.institution_approval_status in STAGE3-036 referred to post-Veriff flag, not post-Rippling. No rewrite required.BA linh.nguyen34 confirmed 2026-08-14
2026-08-11v1.1 → v1.2§1 Overview descriptionDescribed only RESUBMISSION/DECLINED pathsAdded EXPIRED/ABANDONED auto-renewal path with Freshdesk escalation at attempt 2 and hard limit at attempt 3STAGE3-023 [CHR-43] confirmed 2026-08-11
2026-08-11v1.1 → v1.2§4 Post-conditionsRESUBMISSION_REQUESTED and DECLINED paths onlyAdded EXPIRED/ABANDONED path (attempt 1–2 auto-renew; attempt 2 Freshdesk; attempt 3 DECLINED; 21-day max window)STAGE3-023 [CHR-43] confirmed 2026-08-11
2026-08-11v1.1 → v1.2§5 Basic Flow — Outcome D (new)Not presentAdded Steps 4D-1 to 4D-6: increment counter → hard limit check → POST /sessions → send retry email → Freshdesk at attempt 2 → haltSTAGE3-023 [CHR-43] confirmed 2026-08-11
2026-08-11v1.1 → v1.2§7 Exc-2 — Dots POST /payees retry"No automated async retry queue. Break-Glass Runbook."Updated: async retry queue confirmed; Break-Glass as fallback if retry exhaustedSTAGE3-026 confirmed 2026-08-11
2026-08-11v1.1 → v1.2§7 Exc-6 (new)Not presentAdded: Veriff POST /sessions failure during auto-renewal — behavior TBD, assumption flaggedSTAGE3-023 [CHR-43] confirmed 2026-08-11
2026-08-11v1.1 → v1.2§8 BR_5.2.3"Max 3 RESUBMISSION_REQUESTED retries"Updated: shared counter across RESUBMISSION / expired / abandoned; 7 days × 3 = 21-day max windowSTAGE3-023 [CHR-43] confirmed 2026-08-11
2026-08-11v1.1 → v1.2§8 BR_5.2.9 (new)Not presentAdded: auto-renewal on expired/abandoned; Freshdesk escalation at veriff_attempts = 2; non-blockingSTAGE3-023 [CHR-43] confirmed 2026-08-11
2026-08-11v1.1 → v1.2§11 AC-5.2-14Break-Glass only in expected resultUpdated: async retry queued + Break-Glass as fallbackSTAGE3-026 confirmed 2026-08-11
2026-08-11v1.1 → v1.2§11 AC-5.2-15 to AC-5.2-18 (new)Not presentAdded: expired/abandoned auto-renewal scenarios, attempt-2 Freshdesk escalation, attempt-3 hard limit, mixed counter scenarioSTAGE3-023 [CHR-43] confirmed 2026-08-11
2026-08-11v1.0 → v1.1§7 Exc-2 — Dots POST /payees non-200[ASSUMPTION] Log error; alert Operations. Retry logic TBD.Confirmed: identity_status stays 'Pending', dots_payee_id stays NULL, no auto-retry; Break-Glass Runbook (POST /api/bps/kyc/reset or Ops Console manual override)STAGE3-025 confirmed 2026-08-11
2026-08-11v1.0 → v1.1§11 AC-5.2-01identity_status = 'Approved' listed before Dots call in expected resultCorrected: Dots call first, dots_payee_id saved, then identity_status writtenSTAGE3-025 confirmed 2026-08-11
2026-08-11v1.0 → v1.1§11 AC-5.2-14 (new)Not presentAdded: Dots POST /payees non-200 → identity_status stays 'Pending', aggregation blocked, Break-Glass RunbookSTAGE3-025 confirmed 2026-08-11
2026-08-22v2.0 → v2.1All sections — CHR tag standardizationBare STAGE3 codes without CHR tags; date-based CR refsB4: STAGE3-037 → STAGE3-037 [CHR-46] (13 occurrences). A35: CR-20260813-001 → [CHR-46] (3 occurrences). B3: STAGE3-023 → STAGE3-023 [CHR-43] (16 occurrences). B5: STAGE3-039 → STAGE3-039 [CHR-46] (1 occurrence).CHR_Tag_Change_Plan_20260822_v4.md
2026-08-25v2.1 → v2.2Step 4A-0; Step 4A-2; §7 Exc-7 (new); §8 BR_5.2.7; BR_5.2.11 (new); BR_5.2.12 (new)Step 4A-0: check dots_payee_id IS NOT NULL only. Step 4A-2: no endpoint specified, no address normalization. No Exc-7. BR_5.2.7: no endpoint. No BR_5.2.11/12.Step 4A-0: 5-field health check via GET /v2/users/{id} (status, default_payout_method, must_collect_1099, w8_ben_collected, flagged). Step 4A-2: endpoint PUT /v2/users/{id}/compliance; W-9 vs W-8BEN payload; address normalization JSON + 255-char + ZIP truncate + 400 addressinvalid fallback. Exc-7: addressinvalid non-blocking fallback. BR_5.2.11: 5 address normalization rules. BR_5.2.12: returning trader health check table + webhook subscription.CR-20260825-001 (Dots vendor response 2026-08-25)

On this page