Interview Study Guide

UBB Analytics: Product & Technical Deep Dive

Usage-Based Billing analytics features built during the 2025 Code Yellow — covering product decisions, API design, technical architecture, SDP/Sigma datasets, and key incidents.

1. Code Yellow Context & Strategy

What is the UBB Code Yellow?

A cross-organizational effort (April 28 – June 20, 2025) to win AI application-layer companies (Cursor, Perplexity, Replit, Midjourney) for Usage-Based Billing, competing against Metronome and Orb.

Success Criteria

Operating Model

Stripe evolved UBB "from skateboard phase to bicycle phase" — optimized for speed of learning:

Teams Involved

UBB Team

Owns upstream pipeline — UAP (Usage Aggregation Pipeline), RTR (Real-Time Ratings) Flink apps

Revenue Intelligence

Owns analytics Flink apps, dashboard charts, Meter Usage API, Spend API

Product Catalog

V1 products/prices and V2 RateCards/PricingPlans — heavy overlap with code yellow primitives

Analytics Core

Platform APIs (v1/analytics/metrics, metric_run) powering analytics data surfaces

BillingScript

Borrowed engineers during code yellow for UBB-related projects

Billing UX Platform

Frontend dashboard surfaces for billing including UBB products

Resource Impact

4.5 HC reallocated from Billing Analytics (subscription adoption) → UBB/genAI acquisition through H1. Subscription PLG, Essential Journey, and UI lib migration all deferred to Q4 2025+.

Timeline

Late April 2025

Code Yellow declared; API review filed (target: May 2)

May 2025

Meter Usage API approved for Private Preview; rate limiting implemented; code complete May 9

June-July 2025

Kafka over-provisioning, incident remediation, SDK private preview releases

Jan 2025

Rated Usage PRD authored — rated usage metrics for dashboard

Oct 2025

Spend Analytics API PRD — usage & spend for customer portals

April 2026

Spend API launched in Private Preview for Sessions

March 2026

ir-canny-tradition incident with Perplexity (3-track data quality failure)

2. Product Overview

What is UBB Analytics?

UBB Analytics provides real-time usage and spending data for merchants using Usage-Based Billing. It powers three fundamental capabilities:

Aggregate Usage

Query raw usage by meter, customer, dimension, tenant — 1-3 min freshness

Rated Usage (Spend)

Usage × price to forecast upcoming invoice amounts — 5-10 min freshness

Spending Trends

Time-series data for individual customers or cohorts — hourly/daily/weekly/monthly

Key Use Cases

Use CaseWhoExample
Pre-invoice usage checkEnd customers"How much have I used this billing period?"
High-usage monitoringMerchantsPrevent surprise bills, identify expansion opps
Spend forecastingSales teams"Top 10 customers by forecasted spend this month"
Billing dispute resolutionSupport"Why was I charged $X?"
Customer portalMerchants → their customers"Your current usage = ~$X charge"

User Problem (from PRD)

The Gap

AI companies (Perplexity, Cursor, Lovable, Together AI) need to give their customers clear visibility into usage and spend. Competitors (Metronome, Orb) already provide this. Without it, Stripe loses deals.

Target Users

Perplexity, Together AI, Vercel, Figma, UiPath, Cursor, Lovable — primarily AI application layer companies with usage-based pricing models.

Key User Stories (Spend API — Prioritized)

PriorityStoryRequested By
P0Period-to-date spend with ≤2 min freshnessLovable, Perplexity
P0Filter/group by pricing dimensions, meter dimensions, tenant IDMultiple
P1Historical period spendMultiple
P1Time series breakdown (hourly/daily granularity)Multiple
P2Pure UBB spend for any chosen time windowFuture

3. APIs — Shape & Design

3.1 Meter Usage API Private Preview

EndpointGET /v1/billing/analytics/meter_usage
PurposeQuery aggregate usage grouped/filtered by meter dimensions and tenants
GateBillingAnalyticsUsagePrivatePreview
Permissionbilling_analytics_meter_usage_read
Rate Limit100 RPS / merchant, 100 concurrent requests
ErrorHTTP 429 on violation
ApprovedMay 7, 2025 (APIREVIEW-3649)

Parameters

ParamRequiredTypeNotes
start_timeYestimestampQuery range start
end_timeYestimestampQuery range end
customer_idNostringFilter by customer
metersYesarraymeter_id + dimension_group_by_keys + dimension_filters + tenant_filters
value_grouping_windowNoenumhour / day / week / month
timezoneNostringIANA timezone

Response Shape

{
  "data_refreshed_at": 1715100000,
  "data": [
    {
      "bucket_start_time": 1715000000,
      "bucket_end_time": 1715003600,
      "meter_id": "mbm_xxx",
      "dimensions": {"model": "gpt-4"},
      "bucket_value": 1542.0
    }
  ]
}

Key Design Decisions

3.2 Spend API Private Preview

EndpointGET /v2/billing/analytics/usage_spend
PurposeRated usage (usage × price) for forecasting upcoming invoice amounts
LaunchedApril 2026 (Sessions)
Rate Limit25 RPS initially (scalable to 10,000 QPS planned)
Namespacev2/ — aligned with Billing Product Catalog domain

Parameters

ParamRequiredType
customer_idYesstring
periodYestime_range / subscription / billing_cadence
value_grouping_windowNohour / day / week / month
group_by_keysNometered_item / rate_card
filters.metered_itemsNoarray of IDs

Response Shape

{
  "refreshed_at": 1715100000,
  "rows": [
    {
      "starts_at": 1715000000,
      "ends_at": 1715086400,
      "rated_usage_amount": 15420,
      "discount_amount": 1000,
      "promotional_credit_amount": 500,
      "paid_credit_amount": 200,
      "total_excluding_tax_amount": 13720,
      "currency": "usd"
    }
  ]
}

Spend Terminology

TermFormula
Rated usageprice × quantity (gross)
Paid usagerated_usage − discounts − free credits
Amount pretaxrated_usage − discounts − all credits

3.3 Customer Portal Usage Analytics API

EndpointGET /v1/billing_portal/sessions/{session}/exp/usage_analytics
PurposePowers merchant customer portals — end-customers see their own usage
AuthEphemeral key (validates customer ownership)
Gatecustomer_portal_usage_analytics

Key feature: Portal configuration stores allowed_dimensions — merchants control which dimensions their end-customers can group/filter by.

3.4 Dashboard Analytics Metric

The Analytics Core metric usage_based_billing.gross_usage_revenue powers the dashboard charts:

4. Technical Architecture

4.1 Real-Time Ratings Stack (2025 — Current)

Usage Event (Meter API) Kafka Topic UAP Flink (ubb-agg-usage-v2) Aggregates raw usage by dimensions • 30s tumble window • Exactly-once Owner: UBB Team Kafka RTR Flink (Real-Time Ratings) Applies pricing tiers • Calculates rated_amount • 1-2 min eviction (→10-15 min) Owner: UBB Team • NOT Active/Active Kafka Analytics Flink (ubb-ratings-analytics) Transforms for dashboard/API • Exactly-once sink • Dedup with 24hr window Owner: Revenue Intelligence Apache Pinot (RDP Cluster) Hybrid tables (realtime + daily batch) • 15-min bucket granularity Meter Usage API Spend API Dashboard

4.2 Freshness SLAs

Data TypeFreshnessNotes
Aggregate usage1-3 minutesUAP tumble (30s) + processing
Rated usage5-10 minutesWithout artificial delay; 15-20 min p95
Dashboard charts<1 hour SLATypically ~10 seconds in practice
Latency Breakdown

Current: 30s (UAP) + 1-2 min (RTR) + 30s (processing) = 2-3 minutes
Future: 30s (UAP) + 10-15 min (RTR) + 30s (processing) = 11-16 minutes (accuracy tradeoff)

4.3 Pinot Table Schema

Table: prod_rdp_express_12h_billing_meter_granular_ratings_analytics_nw_v4_data

Dimension & Metric Fields

Dimensions

ColumnType
_viewing_merchantSTRING
modeSTRING
meter_idSTRING
customer_idSTRING
price_idSTRING
product_idSTRING
currencySTRING
billable_item_idSTRING
segment_jsonJSON

Metrics

ColumnTypeAggregation
metric_value_bucketedLONGSUM(metric_value)
max_received_atLONGMAX(received_at)

Configuration

  • Cluster: pinot-a200-rdp, region: northwest
  • Tenant: ubbanalytics
  • Realtime: 3 replicas, 90-day retention
  • Offline: daily refresh, 50 MURMUR partitions on _viewing_merchant
  • Inverted indexes on: _viewing_merchant, mode, meter_id
  • Bloom filter on: _viewing_merchant

4.4 Kafka Topics

Input & Output Topics

Input (CDC from databases)

  • online_db.cdc.v2db_d_ubb_uap_91my.UsageAggregationSummary (low cardinality)
  • online_db.cdc.v2db_d_ubb_uap_high_cardinality_nd5v.UsageAggregationSummaryHighCardinality
  • online_db.cdc.v2db_d_billing_rating_fycu.RatingWindowSummary (rated usage)
  • online_db.cdc.v2db_d_billing_rating_fycu.PaidUsageWindowSummary (paid usage)

Output (exactly-once sink)

  • billingmeter.combined_aggregated_analytics_northwest.bson
  • billingmeter.combined_high_card_aggregated_analytics_northwest.bson
  • billingmeter.granular_ratings_analytics_northwest.bson
  • billingmeter.paid_usage_analytics_northwest.bson

4.5 Legacy Stack: "Tom/Jerry" Deprecated 2025

Named after two Flink apps in the original design. Replaced because:

4.6 Data Pipeline (Airflow/Spark)

Daily offline pipeline owned by RUN_REVINTEL:

  1. SQL task reads from Iceberg (rated usage data)
  2. Spark repartitions into 50 partitions on _viewing_merchant
  3. Pinot segment push to offline table
  4. AdvanceTimeBoundary shifts query boundary between offline/realtime

5. SDP & Sigma Datasets

5.1 UBB-Specific Tables

TableDescriptionStatus
billing_metersMeter definitions (ID, event_name, aggregation formula)GA
billing_meter_event_summariesAggregated usage per customer/meter/segmentGA
billing_meter_invalid_eventsFailed validation eventsGA
billing_meter_invalid_events_payloadKey/value payload of invalid eventsGA
paid_usage (fka subscriptions_paid_usage)Rated usage per subscription — 15-min bucketsPreview

5.2 Paid Usage Schema (subscriptions_paid_usage)

ColumnTypeNotes
customer_idPK/FKForeign key to customers
start_timePK/Bigint15-min bucket start (Unix seconds)
billing_meter_idPK/FKForeign key to billing_meters
billable_item_source_idPK/FKProduct or metered_item ID
billable_item_typeVarchar"product" or "metered_item"
price_source_idVarcharPrice or rate_card_rate ID
currencyVarcharISO currency code
gross_amountBigintRated usage before adjustments
discount_amountBigintDiscounts applied
promotional_credit_amountBigintFree credits applied
paid_credit_amountBigintPurchased credits applied
segmentPK/VarcharJSON of meter dimension key/values
Design Decision

Single table for v1/v2 — consolidated from originally separate tables. Segments stored as JSON varchar column (not separate table) for query simplicity.

5.3 Billing Analytics Sigma Exports

DatasetPurposeEntry Point
sigma_customer_change_events_v1_localizedCustomer MRR changes (churn/retention)Billing Overview → Churn
sigma_subscription_item_change_eventsSubscription changes impacting MRRBilling Overview → Revenue

5.4 Export Pipeline

Source (Iceberg tables)
    │
    ▼
Simple Blueprint Pipeline (SQL in Airflow)
    │
    ▼
Blueprint Datasource (Python function)
    │
    ▼
Reporting Data Warehouse (RDW)
    │
    ▼
Sigma / SDP Configuration (YAML, feature-flagged)

Process: Schema Review (3-7 days) → Simple Blueprint Pipeline → Sigma/SDP YAML config

6. Key Decisions & Tradeoffs

Decision 1: Real-time vs. Batch

Choice: Real-time streaming (Flink → Kafka → Pinot)
Why: Merchants need current-period usage data to forecast bills. The "surprise bill" problem is solved only with real-time data. Competitors (Metronome, Orb) already offer this.
Tradeoff: Higher operational complexity, more failure modes, requires Flink expertise. Bootstrap takes 12-24 hours.

Decision 2: RTR Eviction Timer — Accuracy vs. Freshness

Choice: Currently 1-2 min, planned increase to 10-15 min
Why: Longer windows let RTR collect more usage events before rating, improving accuracy for bursty patterns. Dashboard SLA (<1 hour) gives headroom.
Tradeoff: Freshness degrades from 2-3 min to 11-16 min. Acceptable for dashboard; may not be for customer portal (P0 = ≤2 min).

Decision 3: Hybrid Pinot Tables

Choice: Real-time ingestion from Flink + daily batch segments
Why: Real-time provides freshness; batch provides correctness (backfills, corrections). AdvanceTimeBoundary mechanism controls query routing.
Tradeoff: Complexity managing time boundaries; potential overlap during transitions. AdvanceTimeBoundary failures block settings changes.

Decision 4: Metered Billing Excluded from MRR

Choice: Usage-based charges excluded from MRR metric
Why: MRR = "predictable recurring revenue." Usage is inherently unpredictable month-to-month. This is industry-standard.
Tradeoff: 100% metered merchants see $0 MRR / $0 active subscribers. "Total Monthly Revenue" metric (MRR + usage) is in development.

Decision 5: Separate Aggregate vs. Rated APIs

Choice: /meter_usage (raw) vs. /spend (rated)
Why: Different freshness guarantees (1-3 min vs 5-10 min), different consumers, different query patterns. Aggregate = operational monitoring; Spend = financial forecasting.
Tradeoff: Two APIs to learn, two data paths to monitor, potential confusion on which to use.

Decision 6: v2 Namespace for Spend API

Choice: GET /v2/billing/analytics/usage_spend
Why: Aligned with Billing Product Catalog domain (rate_cards, metered_items are v2 concepts). Also allows cleaner resource-oriented design.
Tradeoff: v2 APIs initially required Sandbox (not Legacy Testmode). DEeP team built dual-projection to support LTM for code yellow by July 2025.

Decision 7: 15-Minute Bucket Granularity

Choice: Data stored in 15-min time buckets in Pinot
Why: Enables timezone flexibility (can re-bucket to hour/day/week/month at query time). Sub-minute precision not needed for billing analytics.
Tradeoff: Cannot drill into sub-15-min patterns. Acceptable for the "how much have I spent?" use case.

Decision 8: No Pagination (Pinot Limitation)

Choice: Limit response via cardinality restrictions and validation errors
Why: Pinot doesn't efficiently support cursor-based pagination. Max ~200 rows estimated per query.
Tradeoff: Can't return unbounded result sets. Mitigated by max 90-day range for day/hour granularity and validation errors for excessive cardinality.

7. Incident: ir-canny-tradition (Perplexity)

Critical Learning

March 12–19, 2026: Three distinct data quality failures in 7 days on the subscriptions_paid_usage dataset — with Perplexity as the only gated Private Preview merchant. All issues surfaced by the merchant, not detected by Stripe.

Track 1 — Correctness: Credit columns zeroed out

CauseBlueprint v2 feature caused all credit columns to be zeroed
ImpactPerplexity saw incorrect credit amounts across entire dataset
MissingNo data correctness checker comparing dataset against closed invoices (source of truth)

Track 2 — Freshness: Data stale for 5 days

CauseTeam disabled spend pipeline during a planned rollout — created data blackout window
ImpactDataset stale during Perplexity's critical board meeting
MissingNo freshness SLA defined; no parallel pipeline approach

Track 3 — Completeness: 10% of rows missing credits

CausePrevious Billing migration missed 32 tiered rate card versions; pipeline silently dropped them
Impact10% of rows correlated with ASI% meters had zero credits
MissingNo validation at ingestion for unsupported pricing types — silently produced incomplete output

Key Learnings

"Private Preview" is a lie

Once data is shared, merchants treat it as production-critical and build dashboards, board presentations, and internal tools on it.

Never create data blackout windows

Stand up new version in parallel, dual-write, validate, cut over. Never take a consumed dataset offline.

Known limitations must be monitored

Don't silently drop unsupported data. Alert when tiered prices enter a pipeline that doesn't support them.

Four dimensions of data quality

Correctness, freshness, completeness, consistency — all require continuous automated monitoring, not one-time Hubble queries.

Post-Incident: Data Quality Framework

DimensionDetector AddedPurpose
CorrectnessCorrectness checker vs invoicesCatches divergence from source of truth
Freshness9-hour SLA with PagerDutyPages on-call when data goes stale
CompletenessKnown-limitation guardrailsRejects/alerts on unsupported pricing types
CompletenessSigmaDataCheckSuite (every 6 hours)Row count within 5% of source + freshness <24h

8. Revenue & Usage Metrics

UBB Revenue Metrics (Billing Analytics)

MetricDefinition
MRRMonthly Recurring Revenue — subscription amounts of active subscribers. Builds incrementally; each change adds/subtracts MRR diff.
Active SubscribersCustomers with non-zero MRR (metered-only = NOT counted)
ARPSAverage Revenue Per Subscriber = MRR / Active Subscribers
Churn Rate% of subscribers that stopped paying (trailing 30 days)
LTVLifetime Value ≈ ARPS / Churn Rate

Usage & Spend Metrics

MetricDefinition
Aggregate UsageRaw event count/sum aggregated by meter dimensions
Rated Amountusage × price (applying tiers, transforms)
Gross Usage RevenueTotal monetary amount from usage events, excluding taxes and discounts
Paid UsageRated usage − discounts − free credits (what appears on invoice)
Outstanding SpendUsage not yet invoiced

Total Monthly Revenue (PRD: Apr 2025)

New Metric In Development

Total Revenue = MRR + Usage-based revenue − percent discounts − free credits

Addresses the gap for hybrid business models. Weekly view uses "additive rated usage" model (actual rated usage stacked on MRR). Forecasting only viable for ~22.5% of merchants due to high volatility.

Currency Handling

9. Customer Portal & Configuration

Portal Usage Analytics

Merchants can enable a usage analytics experience in their customer portal, allowing end-customers to see their own usage and spend data.

Implementation Pattern

// Portal configuration model
{
  enabled: true,
  usage_analytics: {
    group_by_dimensions: ["model", "region"]  // merchant controls
  },
  credit_balance: { ... }
}

// At API layer:
// 1. Auth via ephemeral key
// 2. Validate customer ownership
// 3. Filter group_by/filters against portal config's allowed_dimensions
// 4. Delegate to GetUsageAnalytics command

Branching Logic

report_typeDataStory UsedData Source
"usage"billing_meter.combined_usage_event_aggregations.2Aggregate usage Pinot table
"spend"billing_meter.rated_usage_customer_portal.1Rated usage Pinot table

Response Shape

{
  "object": "billing.analytics.usage_analytics",
  "livemode": true,
  "refreshed_at": 1715100000,
  "rows": [
    {
      "starts_at": 1715000000,
      "ends_at": 1715086400,
      "value": 1542.0,
      "meter": "mbm_xxx",
      "dimensions": {"model": "gpt-4"}
    }
  ]
}

Key Architectural Patterns

10. Interview Prep Questions

Why real-time over batch for UBB analytics?
Merchant trust requires current-period visibility. The core use case — "how much will my bill be?" — is only valuable with fresh data. Batch (hourly/daily) was too stale. Competitors (Metronome, Orb) already offered this. The "surprise bill" problem is solved only with real-time data, and AI companies (our target market) expect sub-minute freshness for their customer portals.
How do you balance accuracy vs. freshness?
The RTR eviction timer is the key lever. Currently 1-2 min (fast but may miss late events), planned 10-15 min (more accurate for bursty patterns). The insight: dashboard SLA is 1 hour, so we have headroom to prioritize accuracy without breaking user expectations. For the customer portal (P0 = ≤2 min), we'd keep the shorter window. This is a per-surface tradeoff, not a system-wide one.
What went wrong with Perplexity (ir-canny-tradition)?
Three-track failure in 7 days: (1) correctness — credits zeroed by Blueprint v2 bug, (2) freshness — 5-day blackout during planned rollout, (3) completeness — tiered pricing silently dropped. Root cause: treating "Private Preview" as permission to have lower quality bars. Key learning: once data is shared, merchants build on it immediately regardless of preview status. Fix: same observability as GA (freshness SLAs, correctness checkers, known-limitation guardrails), plus never create data blackout windows (parallel pipelines instead).
Why separate aggregate and rated/spend APIs?
Different latency profiles (1-3 min vs 5-10 min), different consumers (operational vs financial), different query patterns (raw counts vs dollar forecasts). Aggregate usage answers "how much did I use?" (operations teams). Spend answers "how much will I owe?" (finance, customer success). Combining them would force the slower freshness on the faster use case, or expose confusing schema mixing raw and monetary values.
How does the system scale for enterprise merchants?
Three key design choices: (1) Pinot for low-latency analytical queries at scale (sub-second even at millions of rows), (2) Flink for stateful stream processing with exactly-once guarantees, (3) Kafka for decoupling producers from consumers. Hybrid tables bridge real-time freshness with batch correctness. Per-merchant rate limits (100 RPS) protect the shared cluster. For Perplexity-scale (their largest customer), we introduced high-cardinality Pinot tables with tenant filters.
Why exclude metered billing from MRR?
MRR means "predictable recurring revenue" — the industry standard definition. Usage-based charges are inherently unpredictable (a customer might use 10x one month and 0.1x the next). Including them would make MRR volatile and useless for forecasting. The tradeoff: 100% metered merchants see $0 MRR. Solution: "Total Monthly Revenue" metric (MRR + rated usage) in development, with forecasting toggle (only viable for 22.5% of merchants due to volatility).
How do you ensure data quality at scale?
Four dimensions, each with continuous automated monitoring: (1) Correctness — checkers comparing dataset against upstream source of truth (invoices), (2) Freshness — SLA monitoring with PagerDuty integration (9-hour SLA), (3) Completeness — row count validation within 5% of source, detection of unexpected nulls, known-limitation guardrails, (4) Consistency — cross-surface validation between Dashboard/Sigma/API/SDP. The SigmaDataCheckSuite runs every 6 hours. Critical learning: manual Hubble queries don't scale.
What was the code yellow's impact on the product org?
Massive reallocation: 4.5 HC moved from subscription analytics to UBB/genAI. Subscription PLG, Essential Journey, and multiprocessor support all deferred 2+ quarters. The bet: AI companies represent a larger growth opportunity than incremental subscription improvements. Operating model shifted to 1-week sprints with engineers co-developing in customer Slack channels. This enabled same-day API design and rapid private preview iteration.
How do SDP/Sigma datasets differ from the API?
APIs serve real-time queries (seconds-old data, ≤200 rows, rate-limited). SDP/Sigma serve bulk data extraction (daily freshness, full history, SQL-queryable). Different consumers: APIs power live dashboards and customer portals; SDP powers data warehouses and board reports. The paid_usage dataset schema stores 15-min buckets with the full spend breakdown (gross, discounts, credits), enabling merchants to build custom analytics beyond what the API exposes.
What's the customer portal design and why does it matter?
The portal lets merchants expose usage/spend data directly to their end-customers — a key requirement from AI companies (Cursor users seeing their token usage, Perplexity users seeing query counts). Key design: merchants configure which dimensions are visible via allowed_dimensions in the portal config. This prevents data leakage (e.g., a customer shouldn't see other customers' usage) while enabling flexible self-serve analytics. Auth uses ephemeral keys with customer ownership validation.