Skip to main content
Question

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

  • March 8, 2026
  • 1 reply
  • 101 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.

This post has been closed for comments

1 reply

KitRCAdvocate
Forum|alt.badge.img+2

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!