Skip to main content
Question

Trying to replicate RC's ARR chart from webhook data — close but not exact

  • March 8, 2026
  • 1 reply
  • 33 views

Forum|alt.badge.img

Hey RC community 👋

I've been building an internal ARR model using data from RC's webhook events and I'm having trouble matching the exact number shown in the RC dashboard.

My approach:

  • Use INITIAL_PURCHASE and RENEWAL events as subscription periods
  • Apply expiration overrides from EXPIRATIONBILLING_ISSUESUBSCRIPTION_EXTENDED events
  • Normalize price to MRR using the multipliers from the RC MRR chart docs
  • Active subscription = purchased_at <= snapshot_date < effective_expiration_at
  • Filter: production only, no family share, no promotional store, NORMAL/INTRO period types

I'm consistently getting a small but persistent gap vs the RC dashboard for the same date — less than 1% off, but it's blocking us from fully trusting our internal numbers.

RC support was kind enough to share a raw export CSV, and comparing row-by-row I can see some specific discrepancies, but haven't been able to fully close the gap.

A few things I'm still unsure about:

  1. How does RC handle BILLING_ISSUE periods in MRR — grace period subscribers counted at $0 or excluded?
  2. Are Customer Support refunds reflected in ARR at the time of the refund event, or at end-of-period?
  3. Are there edge cases with SUBSCRIPTION_EXTENDED or TRANSFER events that affect active period logic?

Has anyone successfully built an ARR model from webhook data that closely matches the dashboard? Would love to compare notes.

1 reply

KitRCAdvocate
Forum|alt.badge.img

Great breakdown — you're very close to the right approach. A few things that commonly cause that small persistent gap:

 

1. BILLING_ISSUE grace period handling: RC counts grace period subscribers at their full price in MRR (not $0, not excluded). If your model is excluding them or zeroing them out, that'll cause a consistent underage.

 

2. Refund timing: RC reflects refunds at the time of the CANCELLATION or refund event, not at end-of-period. If you're holding them until expiration, you'll have a lag discrepancy on any snapshot date mid-period.

 

3. TRANSFER events: When a transfer happens, the old app user ID loses the subscription and the new one gains it. If your model isn't correctly handling the cutover point (purchased_at on the new record resets to transfer date), you can get double-counting or gaps around the transfer window.

 

4. Trial conversion edge case: INITIAL_PURCHASE after a free trial uses the trial start as purchased_at in some contexts — make sure your period start anchor is consistent with what RC uses for MRR attribution.

 

The RC MRR chart docs note they use the store-reported expiration date, not a calculated one — so if you're computing expiration from duration + purchase date instead of using the expiration_at_ms field directly from the webhook payload, rounding differences compound over large cohorts.

 

Hope that helps close the gap!