StackTrading Docs

SRS: UC_9.11 — Flow 34: Rippling Payroll Ledger Sync

FieldValue
UC_IDUC_9.11
Versionv1.1
Last Updated2026-11-04
BA PiClinh.nguyen34
CategoryBACKGROUND MECHANISMS & CRON JOBS
ModuleFlow 34 (UC_4.15.2)
FunctionRippling Payroll Ledger Sync
Document ReferencesZapier Integration V7.pdf (§Flow 34; §7.2 Flow 34 Payroll Trigger — Option A/B) · RFQ_ Stack Trading Prop Tech V7.pdf (§Record Immutable Ledger POST /api/ledger/record; §3.6.1 Smart Contract Architecture; §Audit Requirements CFTC 1.31) · StackTrading_Backend_Technical_Proposal_v1.6.docx (§Option B provider list) · QnA_STAGE5_PAYOUT_WITHDRAWAL.md (A-33)

1. UC Index

UC_IDFunctionDescription
UC_9.11Flow 34 — Rippling Payroll Ledger SyncWhen Rippling clears a bi-weekly/monthly payroll run for an active W-2 trader, Zapier calls POST /api/ledger/record to mint a W2 Payroll Executed event on the Polygon PoS StackTradingLedger contract. Middleware stores the returned tx_hash in PostgreSQL. Duplicate Rippling deliveries are de-duplicated by provider_event_id / receipt_hash.

UC_9.11 — Flow 34: Rippling Payroll Ledger Sync

FieldValue
Use CaseRippling Payroll Ledger Sync
DescriptionPublishes proof of W-2 payroll (base salary + benefits) to the Immutable Ledger. Each cleared regular scheduled Rippling payroll run (bi-weekly/monthly) for an active W-2 trader produces exactly one CorporateMetricVerified event on Polygon PoS, with the Rippling Transaction ID as verificationHash. Off-cycle runs are ignored.
ActorSystem (Rippling → Zapier → Middleware Hub → Polygon PoS)
Zapier FlowFlow 34
Trigger SourceRippling webhook — Payroll Run Cleared (PAYROLL_CLEARED)
3rd PartyRippling · Zapier · Alchemy RPC · Polygon PoS
Middleware EndpointPOST /api/ledger/record
Related UCsUC_7.4 Immutable Ledger (Payout) · UC_4.15.2 Career & HR Widget · Flow 5 (performance bonus), Flow 9 (severance), Flow 17 (Pod Leader vesting) — each logs its own off-cycle W-2 payout to the ledger, see BR_9.11.6

2. Trigger

Event: Rippling fires a webhook when a regular scheduled bi-weekly or monthly payroll run is cleared (funds disbursed).

Off-cycle runs (Flow 5 performance bonus, Flow 9 severance, Flow 17 Pod Leader vesting — all via Rippling Off-Cycle Payroll API) are not processed by Flow 34, even if Rippling fires the same webhook. See Alt-3.

SourceEventDelivery path
RipplingPayroll Run Cleared (PAYROLL_CLEARED)Option A — direct to Zapier (Rippling is not in the Option B hardened-ingress provider list)

(Source: Zapier Integration V7.pdf §Flow 34; §7.2 Option A/B · StackTrading_Backend_Technical_Proposal_v1.6.docx §Option B provider list — Rippling marked "—")

⚠️ Option B (POST /webhooks/payroll/rippling → POST /zapier/events/payroll_cleared) is described in Zapier Integration V7.pdf §7.2 but is not in the adopted Option B scope (8 providers: NMI, Triple-A, Skrill, Nomupay, EBANX, Dusupay, Veriff, Dots). See Q1.


3. Pre-conditions

IDPre-condition
P1Rippling webhook subscription to Payroll Run Cleared is configured to the Zapier Flow 34 catch hook.
P2Payload contains a Rippling Transaction ID (used as receipt_hash) and the payroll amount (Total_Amount).
P3The Rippling worker maps to a Stack Trading user (trader_id) whose Employment_Type = 'W-2' and status is active.
P4StackTradingLedger contract is deployed on Polygon PoS Mainnet; the server-side owner wallet private key is available to Middleware (secured environment).

4. Post-conditions

#Post-condition
1One CorporateMetricVerified event emitted on Polygon PoS with metricCategory = "W2 Payroll Executed".
2Polygon tx_hash written to PostgreSQL (ledger record) against trader_id + receipt_hash.
3receipt_hash / provider_event_id marked processed — any redelivery is a no-op.
4Execution logged to BPS_Audit_Log.
5Event becomes visible on GET /public/ledger (Live Payout Ledger ticker) after the cache refresh.
6Zap terminates.

5. Basic Flow

Step 1 — Receive webhook (Zapier)

Zapier catch hook receives the Rippling Payroll Run Cleared payload.

Step 2 — Filter: active W-2 trader, regular payroll run only (Zapier)

  • Resolve the Rippling worker to trader_id.
  • Continue only if the trader is an active Stack Trading W-2 trader (Employment_Type = 'W-2', account active).
  • Continue only if the payroll run is a regular scheduled run (not off-cycle). Off-cycle → stop (see Alt-3).
  • Otherwise → stop (see Alt-2).
  • ⚠️ The Rippling payload field that distinguishes a regular run from an off-cycle run is not in the sources — Dev to confirm against the Rippling API.

(Source: Zapier Integration V7.pdf §Flow 34 — "Ensure payload corresponds to an active Stack Trading W2 Trader Only"; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016] — client sheet 2026-11-04)

Step 3 — Dedup check

Before calling the ledger, check provider_event_id (Rippling event / transaction ID) against the dedup store. If already processed → Alt-1.

(Source: Zapier Integration V7.pdf §7.2 Option A — "Store provider_event_id in DB to dedup (required for payroll/ledger events)")

Step 4 — Call Middleware POST /api/ledger/record

FieldValue
trader_idGlobal trader UUID
metric_category"W2 Payroll Executed" (fixed)
metric_value"$[Total_Amount] Base + Benefits Paid" — amount formatted to 2 decimal places with thousands separator, e.g. "$4,500.00 Base + Benefits Paid"
dateToday (ISO 8601 UTC)
receipt_hashRippling Transaction ID

(Source: Zapier Integration V7.pdf §Flow 34)

Step 5 — Middleware mints on Polygon

  1. Validate the Zapier JWT signature. Reject if invalid (Exc-1).
  2. Initialize the server-side Ethers.js wallet using the secured environment private key.
  3. Execute contract.recordMetric(_traderId, _metricCategory, _metricValue, _timestamp, _verificationHash) via Alchemy RPC, mapping: trader_id → _traderId, metric_category → _metricCategory, metric_value → _metricValue, date → _timestamp, receipt_hash → _verificationHash.
  4. Await block confirmation.
  5. Write tx_hash to PostgreSQL; log to BPS_Audit_Log.
  6. Return HTTP 200 { "status": "success", "tx_hash": "0x..." }.

(Source: RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger; §3.6.1 Smart Contract Architecture)

Step 6 — Terminate Zap.


6. Alternative Flows

Alt-1 — Duplicate delivery

  • provider_event_id / receipt_hash already processed.
  • Middleware does not call recordMetric() again; returns HTTP 200 with the previously stored tx_hash.
  • No second ledger event; no second ticker row.

Alt-2 — Payload is not an active W-2 trader

  • Filter fails (contractor, terminated, unknown worker, non-trader employee).
  • Zap stops at Step 2. No ledger call. No error.

Alt-3 — Rippling reports an off-cycle payroll run

  • Zap stops at Step 2. No ledger call. No error.
  • Off-cycle W-2 payouts are already logged by their own flow via POST /api/ledger/record: Flow 5 (Performance Bonus, Path C), Flow 9 (Severance, Path C), Flow 17 (Pod Leader Vesting, US W-2 path). Logging them again in Flow 34 would create duplicate on-chain entries.

(Source: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016] — client sheet 2026-11-04; Zapier Integration V7.pdf §Flow 5 Path C, §Flow 9 Path C; RFQ_ Stack Trading Prop Tech V7.pdf §Process Pod Vesting — Immutable Ledger Logging)


7. Exceptional Flows

Exc-1 — Invalid / expired Zapier JWT

  • Middleware returns HTTP 401; no contract call; log to BPS_Audit_Log with execution_status = REJECTED.

Exc-2 — Polygon RPC / transaction failure

  • recordMetric() fails or confirmation is not received.
  • Middleware returns non-2xx; nothing written as processed (so the retry can mint).
  • Zapier retry applies (see Q3). On final failure → Slack alert to Ops (channel per slack_channel_usage.md, see Q3).

Exc-3 — trader_id cannot be resolved from the Rippling worker

  • Treated as Alt-2 (stop) and logged to BPS_Audit_Log as UNMAPPED_RIPPLING_WORKER for manual review. (BA assumption — see Q4)

8. Business Rules

BR_9.11.1: Scope — Active W-2 Traders Only

Flow 34 logs payroll only for active Stack Trading W-2 traders. International contractors are handled by Flow 36 (UC_9.13).

(Source: Zapier Integration V7.pdf §Flow 34)

BR_9.11.2: Fixed Ledger Mapping

metric_category is always "W2 Payroll Executed". metric_value format is "$[Total_Amount] Base + Benefits Paid", amount formatted to 2 decimal places (e.g. "$2,500.00 Base + Benefits Paid"). receipt_hash is always the Rippling Transaction ID.

(Source: Zapier Integration V7.pdf §Flow 34; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016])

BR_9.11.3: One Payroll Run = One Ledger Event (Idempotency)

provider_event_id must be stored and checked before minting. Rippling retries must never produce a second on-chain event. Duplicates return HTTP 200 with the original tx_hash.

(Source: Zapier Integration V7.pdf §7.2 Option A)

BR_9.11.4: Ledger Write Is Owner-Only, Event-Only

The contract stores no state; data is written only as CorporateMetricVerified event logs. Only the owner wallet may call recordMetric().

(Source: RFQ_ Stack Trading Prop Tech V7.pdf §3.6.1)

BR_9.11.5: tx_hash Persisted Before Success Response

Middleware returns success to Zapier only after block confirmation and after tx_hash is written to PostgreSQL.

(Source: RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger — "Await confirmation and write the Polygon transaction hash to PostgreSQL")

BR_9.11.6: Flow 34 Logs Regular Payroll Only — Off-Cycle Payouts Are Logged by Their Own Flow

Flow 34 logs only regular scheduled W-2 payroll (base salary, benefits). Off-cycle W-2 payouts are logged by the flow that triggers them, via POST /api/ledger/record: Flow 5 (Performance Bonus), Flow 9 (Severance), Flow 17 (Pod Leader Vesting). Flow 34 filters off-cycle runs out so each payment produces exactly one ledger entry.

(Source: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016] — client sheet 2026-11-04, supersedes the QnA_STAGE5_PAYOUT_WITHDRAWAL.md A-33 assumption that Flow 34 logs Path C off-cycle payouts; Zapier Integration V7.pdf §Flow 5, §Flow 9; RFQ_ Stack Trading Prop Tech V7.pdf §Process Pod Vesting)

BR_9.11.7: Audit Retention

Every execution is written to BPS_Audit_Log. Retention: 5 years + 1 month (CFTC 1.31 / NFA); objects older than 25 months move to cold storage.

(Source: RFQ_ Stack Trading Prop Tech V7.pdf §Audit Requirements)


9. Acceptance Criteria

AC_IDFlowGivenThenType
AC-9.11-01Happy pathPayroll Run Cleared for active W-2 trader, $4,500.00, new transaction IDOne CorporateMetricVerified event with metricCategory = "W2 Payroll Executed", metricValue = "$4,500.00 Base + Benefits Paid", verificationHash = Rippling Transaction ID; tx_hash stored; HTTP 200Integration
AC-9.11-02DuplicateSame Rippling event delivered twiceSecond call returns HTTP 200 with original tx_hash; only one on-chain eventIntegration
AC-9.11-03Filter — contractorPayload for a non-W-2 workerZap stops at filter; no ledger callIntegration
AC-9.11-04Filter — inactivePayload for terminated W-2 traderZap stops; no ledger callIntegration
AC-9.11-05Bad JWTRequest with invalid signatureHTTP 401; no contract call; audit row REJECTEDSecurity
AC-9.11-06RPC failureAlchemy returns errorNon-2xx returned; event not marked processed; retry mints exactly onceIntegration
AC-9.11-07Public ledgerAC-9.11-01 completedEvent appears in GET /public/ledger recent_events after cache refreshIntegration
AC-9.11-08Filter — off-cycleRippling off-cycle run (e.g. severance) cleared for an active W-2 traderZap stops at filter; no ledger call; no on-chain event from Flow 34Integration
AC-9.11-09Amount formatRegular payroll run cleared, $2,500metricValue = "$2,500.00 Base + Benefits Paid" (2 decimal places)Integration

10. API Reference

POST /api/ledger/record

FieldValue
CallerZapier (Flow 34)
AuthZapier JWT signature

Request:

{
  "trader_id": "94a2b1c8-3f4e-4b21-a123-890abcdef123",
  "metric_category": "W2 Payroll Executed",
  "metric_value": "$4,500.00 Base + Benefits Paid",
  "date": "2026-03-15T18:00:00Z",
  "receipt_hash": "rip_pay_8830192a7c41f"
}

Response (HTTP 200):

{ "status": "success", "tx_hash": "0x..." }
FieldTypeRequiredDescription
trader_idSTRINGYesGlobal trader UUID
metric_categorySTRINGYes"W2 Payroll Executed"
metric_valueSTRINGYes"$[Total_Amount] Base + Benefits Paid"
dateSTRINGYesISO 8601 UTC
receipt_hashSTRINGYesRippling Transaction ID

(Source: RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger)


11. Open Questions

IDPriorityQuestionAssumption
Q1HRippling is not in the Option B provider list. Is Flow 34 delivered via Option A (Rippling → Zapier direct) or should Rippling be added to Option B (POST /webhooks/payroll/rippling)?Option A; dedup done in Middleware at POST /api/ledger/record.
Q2MDoes a Rippling off-cycle run (severance, client said Flow 34 covers severance — A-33) also fire Payroll Run Cleared? If yes, should metric_value still read "Base + Benefits Paid"?✅ Answered 2026-11-04 — Flow 34 ignores off-cycle runs; see Alt-3, BR_9.11.6 ([BG-016]).
Q3MZapier retry count / backoff and Slack channel on final failure are not specified in V7.Zapier default auto-replay; alert to Ops channel.
Q4LShould an unmapped Rippling worker raise an Ops alert or only an audit row?Audit row only.
Q5LTotal_Amount = gross or net pay? Currency always USD?Gross, USD.

12. Changelog

DateVersionChangePreviousAfterSource
2026-11-04v1.1§1 Description, Related UCs; §2 Trigger; §5 Step 2 (off-cycle filter), Step 4 metric_value format; §6 Alt-3 (new); §8 BR_9.11.2, BR_9.11.6 (rewritten); §9 AC-9.11-08/09 (new); §11 Q2Flow 34 assumed to also log off-cycle runs incl. severance (A-33); BR_9.11.6 = Flow 34 vs Flow 5 onlyFlow 34 = regular scheduled payroll only; off-cycle W-2 payouts logged by Flow 5 / Flow 9 / Flow 17; metric_value 2 decimal placesClient sheet 2026-11-04 [BG-016]; Zapier Integration V7.pdf §Flow 5, §Flow 9; RFQ V7 §Process Pod Vesting
2026-10-27v1.0Initial document creation—Full spec: trigger, W-2 filter, dedup, ledger mint, BR_9.11.1–7, AC-9.11-01–07Zapier Integration V7.pdf §Flow 34, §7.2; RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger, §3.6.1; QnA A-33

On this page