- An app revenue API returns aggregates — MRR, paying customers, revenue by rail — never raw charge rows or customer names.
- Call it from your server with a secret key; publishable keys and browsers are rejected.
- One read API can serve revenue, errors, read-cost, and the cross-match, so you build in your own stack instead of exporting CSVs.
Definitions used in this guide
A verified view of subscription state, renewals, refunds, and active access across all payment rails.
A policy that lets one customer unlock the same entitlement across iOS, Android, and web.
The process of checking incoming events against the source system so missed webhooks do not leave access or revenue wrong.
What should be true before you start?
Before you call a revenue API, decide what your own product actually needs to show — and what it should never hold. Most teams want headline numbers (MRR, paying customers, revenue by rail) rendered in an internal admin panel or a customer-facing dashboard, not a copy of every charge. If you have read why building a subscription analytics dashboard from scratch usually backfires, this is the version that does not: the platform keeps the pipeline and you call an endpoint.
Teams that do this well make the data model boring before they make the UI impressive. They decide what the product trusts, how the customer is identified, and which events prove that a premium flow worked. That upfront discipline prevents pricing changes, support escalations, or platform additions from turning into a rewrite later.
- Decide which metrics your UI shows: MRR, paying customers, revenue by rail, an optional daily series.
- Keep secret keys on the server; never ship one to a browser or a mobile binary.
- Treat the API as a read of the reconciled ledger, not a place to reconstruct individual charges.
How should you implement this step by step?
A revenue API call is a server-side GET with a secret key. You ask for a granularity and a window, and you get back aggregates plus a freshness marker so you know the number came from the reconciled ledger, not a guess. The same gate fronts the other products, so once one call works, comparing iOS, Android, and web revenue in one place is the same request with the rail split already attached.
Implementation should move from trust to explanation. First make the purchase and access state reliable. Then add the events and context that explain whether the path is working for real customers. That order matters because a beautiful funnel built on unreliable access logic will still mislead the team.
- Create a secret key (prefix
cd_sk_live_) and store it as a server-side environment variable. - Call
GET https://api.cross-deck.com/v1/revenue?granularity=day&days=90with anAuthorization: Bearerheader. - Read
data.current.mrrCents,data.current.payingCustomers, anddata.current.byRailfor the headline cards. - Add
/v1/errorsand/v1/bucketswhen you want reliability and database read-cost in the same view.
| You ask for | You get back | You never get |
|---|---|---|
| Headline revenue | MRR, paying customers, revenue by rail | Individual charge rows |
| A time series | Daily MRR and customers across your window | Customer names or emails |
| Reliability and cost | Error counts and read-cost via /v1/errors and /v1/buckets | Raw user records |
const url = "https://api.cross-deck.com/v1/revenue?days=90";
const res = await fetch(url, {
headers: { Authorization: "Bearer " + process.env.CROSSDECK_SECRET_KEY }
});
const { data, meta } = await res.json();
// aggregates only — no charge rows, no customer names
renderMrr(data.current.mrrCents, data.current.byRail);
console.log(meta.freshness); // "ledger"
Where do teams make mistakes?
The mistakes with a revenue API are rarely about the HTTP call. They are about treating it like a data export instead of a read.
Most production problems here are not caused by missing one API call; they are caused by model mistakes. Teams mix catalog structure with access logic, treat frontend success states as final truth, or log events without preserving identity. Those shortcuts often feel fine during integration and expensive during the first real support incident.
- Calling the API from the browser or a mobile app — a revenue endpoint is secret-key only, and a publishable key is rejected.
- Trying to rebuild per-customer billing from an aggregates endpoint; if you need a customer's state, check the entitlement, not the revenue ledger.
- Ignoring the freshness marker and rendering an unreconciled number as if it were final.
How does Crossdeck operationalize the workflow?
Crossdeck exposes the read API behind one secret-key gate, but the reason it matters is identity. Because Crossdeck owns the identity that joins every layer, revenue is never a lonely number: from a revenue view you pivot to the cross-match — for any customer, their revenue, entitlements, and read-cost in one call — or to errors to see how many of an issue's affected users actually pay you. The aggregates are the entry point; the join is the moat.
The practical effect is that your app's numbers stop living only in our dashboard, and they arrive already connected: revenue beside the paying customers behind it, the entitlements they hold, and what they cost to serve. Crossdeck is the revenue source of truth — and the join across layers is the difference between surfacing data and surfacing Crossdeck.
The operating win is not just cleaner instrumentation. It is that product, support, and engineering can all look at the same customer and reason from the same truth. That shortens the loop between insight, bug fixing, and revenue recovery.
What should a healthy rollout let your team do?
After rollout, the team should be able to inspect one customer and answer four basic questions quickly: what they bought, what access they should have, what they did before the key moment, and whether an error or product break interrupted the path. If those answers still live in different systems, the rollout is not finished yet.
A healthy setup should also make pricing, platform, and lifecycle changes cheaper. New SKUs, trial structures, payment rails, or premium features should mostly be mapping and instrumentation updates, not excuses to rewrite the access model from scratch.
- Trace one premium journey from paywall view to verified access.
- Confirm support can explain a paid-user issue without engineering stitching exports together.
- Review whether new products can be attached without changing feature checks.
What should you review after launch?
The first review cycle should happen with real production questions, not a checklist alone. Look at a new conversion, a failed payment or retry, a support ticket, and a customer who used a premium feature successfully. If the workflow is sound, those stories should be easy to reconstruct.
From there, keep reviewing the signal as an operating surface. The point is not only to collect data. It is to make the next pricing change, onboarding improvement, or incident response faster because the evidence is already joined.
- Review the earliest events that predict retained value.
- Check the gap between entitlement state and what the UI showed.
- Use the next support conversation as a live test of the model.
How should the whole team use the workflow?
A workflow like this becomes more valuable when it is not trapped inside engineering. Support should be able to confirm access and recent failure context. Product should be able to connect the path to adoption or conversion quality. Engineering should be able to see which state or step broke first.
When those three views line up, the system starts compounding. Each incident teaches the team something about pricing, onboarding, premium UX, or instrumentation instead of dying as a one-off ticket.
- Support: confirm entitlement state and the last premium action quickly.
- Product: review which steps correlate with value or friction.
- Engineering: prioritize breaks by customer and revenue impact.
Frequently asked questions
What is an app revenue API?
An app revenue API is a server-side endpoint that returns your subscription revenue as aggregates — MRR, paying customers, and revenue by rail — so your own backend can render the numbers instead of relying only on a dashboard.
Does a revenue API expose individual customers or charges?
It should not. Crossdeck's /v1/revenue returns aggregates only — no named customer and no single charge row — because financial data is the highest-sensitivity surface. Per-customer access state belongs to entitlement checks, not the revenue ledger.
How do I authenticate to the revenue API?
With a secret key (prefix cd_sk_live_) sent as a Bearer token from your server. Publishable keys are rejected and the browser never calls the API directly, so the key stays on your backend.
Can I get errors and database read-cost from the same API?
Yes. The same gate fronts /v1/errors, /v1/buckets read-cost, and /v1/crossmatch, so one integration can power revenue, reliability, and cost views in your own product.
Does Crossdeck work across iOS, Android, and web?
Yes. Crossdeck is designed around one customer timeline across Apple, Google Play, Stripe, and web or mobile product events, so the same entitlement and revenue model can travel across surfaces.
Take this into the product
Open the Reporting API reference, create a secret key, and pull your first /v1/revenue aggregate from your own backend in one session.