Revenue from Stripe and RevenueCat
Last updated
Connect your Stripe account or RevenueCat project to an app and its purchases, renewals, refunds and cancellations arrive in Metrickle on their own, on the same person your SDK identified. You don't need to send them as custom events. A refund then takes back the task that person completed, a cancellation can be a protected flow's revoke step, and revenue kept is a real number. You set it up on the app's Integrations page, under Revenue. You need to be an owner or admin, or have the integrations.manage permission.
Tie payments to people
Metrickle can only put a payment on the right person if the payment provider knows the same user id you pass to identify(). Do this first.
Stripe
Give Stripe the user id as Checkout's client_reference_id, or as metadata.metrickle_user_id on the customer, subscription or PaymentIntent. Once Metrickle has seen a customer with a user id, later payments from that customer are matched automatically.
// Client: identify the person after sign-in.
metrickle.identify(user.id);
// Server, when you create the Checkout Session: the same id.
const session = await stripe.checkout.sessions.create({
mode: "subscription", // or "payment"
line_items: [{ price: "price_…", quantity: 1 }],
client_reference_id: user.id,
metadata: { metrickle_user_id: user.id },
subscription_data: { metadata: { metrickle_user_id: user.id } }, // subscriptions only
success_url: "https://example.com/welcome",
});
// Without Checkout (Payment Element): put it on the PaymentIntent, or on the customer once.
await stripe.paymentIntents.create({ amount: 4900, currency: "usd", customer: customer.id, metadata: { metrickle_user_id: user.id } });
await stripe.customers.update(customer.id, { metadata: { metrickle_user_id: user.id } });
From a server that sends events over the HTTP ingest API:
# Send events with "userId" set to your user's id, and give their Stripe customer the same id:
curl https://api.stripe.com/v1/customers/cus_… \
-H "Authorization: Bearer $STRIPE_SECRET_KEY" \
-d "metadata[metrickle_user_id]=user-123"
# Checkout Sessions: client_reference_id=user-123 (or metadata[metrickle_user_id]=user-123)
RevenueCat
Log in to RevenueCat with the same user id you pass to identify(). If RevenueCat's app user id has to be something else, set the metrickle_user_id attribute instead.
iOS
import RevenueCat
// After sign-in, the same id for both:
Metrickle.shared?.identify(user.id)
_ = try await Purchases.shared.logIn(user.id)
// If RevenueCat's app user id has to stay something else, name the Metrickle user instead:
// Purchases.shared.attribution.setAttributes(["metrickle_user_id": user.id])
Android
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.logInWith
// After sign-in, the same id for both:
Metrickle.identify(user.id)
Purchases.sharedInstance.logInWith(user.id)
// If RevenueCat's app user id has to stay something else, name the Metrickle user instead:
// Purchases.sharedInstance.setAttributes(mapOf("metrickle_user_id" to user.id))
Flutter
import 'package:purchases_flutter/purchases_flutter.dart';
// After sign-in, the same id for both:
Metrickle.instance.identify(user.id);
await Purchases.logIn(user.id);
// If RevenueCat's app user id has to stay something else, name the Metrickle user instead:
// await Purchases.setAttributes({'metrickle_user_id': user.id});
React Native
import Purchases from "react-native-purchases";
// After sign-in, the same id for both:
metrickle.identify(user.id);
await Purchases.logIn(user.id);
// If RevenueCat's app user id has to stay something else, name the Metrickle user instead:
// Purchases.setAttributes({ metrickle_user_id: user.id });
Connect Stripe
You can connect Stripe with a restricted key, a webhook, or both. Both is best: the webhook brings events within seconds, and the key fills gaps.
-
Restricted key (recommended). In Stripe, go to Developers → API keys → Create restricted key. Give it Read on Charges, Refunds, Customers, Subscriptions, Checkout Sessions and Events, and nothing else. Paste it into Metrickle. It backfills the last 30 days, looks up who a customer is, and reads new events every 15 minutes. Keys that can change your account are refused.
-
Webhook. In Metrickle, choose Show the endpoint URL. In Stripe, go to Developers → Webhooks → Add destination, paste the URL and select these events:
checkout.session.completed checkout.session.async_payment_succeeded invoice.paid payment_intent.succeeded charge.refunded customer.subscription.created customer.subscription.updated customer.subscription.deletedThen paste the endpoint's signing secret (
whsec_…) into Metrickle. Every delivery'sStripe-Signatureis checked against it.
Connect RevenueCat
- In Metrickle, choose Create webhook details. You get a webhook URL and an
Authorizationheader value. The value is shown once. - In RevenueCat, go to Project settings → Integrations → Webhooks → Add new configuration. Paste the URL and the
Authorizationvalue, choose Production (and Sandbox, to test), then send a test event. - Optionally, add a RevenueCat v2 secret key with read access, so Metrickle can show which project is connected.
If you lose the Authorization value, issue a new one in Metrickle and update it in RevenueCat. The old one stops working straight away.
Settings
- Report revenue in: a 3-letter currency code. Amounts in other currencies are converted at the day's rate. Use the currency your other revenue events are in.
- Record test events: includes Stripe test mode or RevenueCat sandbox purchases, for trying the setup. Turn it off afterwards.
What arrives
| Metrickle event | Revenue | Means |
|---|---|---|
purchase | Yes | A one-off payment: Checkout in payment mode, a paid invoice, an in-app purchase |
subscription_started | Yes | The first payment of a subscription |
subscription_renewed | Yes | A renewal payment |
trial_started | No | A free trial began |
refund | Negative | Money returned. Takes back a task completed in the 7 days before it |
subscription_canceled | No | The person chose to cancel, or a payment failed for good. Use it as a protected flow's revoke step |
subscription_ended | No | Access ran out after a cancel. It takes nothing back |
Each payment is counted once, however many provider events describe it. A redelivered webhook, or the same event read again through the key, changes nothing.
Check it's working
Each connection shows when the last event arrived. What arrived lists the last 50 provider events and what each became:
| Status | Means |
|---|---|
| Recorded | Stored as a Metrickle event |
| Waiting for user | Metrickle doesn't know the customer's user id yet. It's recorded as soon as a later event names the customer |
| No user found | No user id turned up within 7 days. Set metadata.metrickle_user_id on the customer, then run a backfill |
| Skipped | Not something Metrickle records, a test event while test events are off, or already recorded |
| Failed | Metrickle couldn't read the event |
A webhook delivery Metrickle refuses, such as one with a wrong signature, shows on the connection with the reason.
Don't count revenue twice
If your app already sends revenue on a purchase event from the client, remove it there once a provider is connected. Otherwise the same payment is counted twice.
Keys and privacy
Keys and webhook secrets are encrypted and never shown again. Free-text cancellation comments aren't stored. Disconnecting a provider removes its log, but keeps the events already recorded.