Installation
Set up revenue tracking. Identify customers in the browser, connect Stripe or get the secret token, and choose between the HTTP API and the @supapulse/revenue SDK.
1. Identify customers in the browser
Install the browser tracker and call identify() once the user is known, after login or signup:
supapulse.identify(user.id); // window.supapulse with the script tagIn React, use useIdentify(). identify() never counts toward your event usage.
2. Pick how payments arrive
- Stripe: open the site's settings, find the Revenue section, and follow the Stripe guide. You don't need the secret token.
- Anything else: continue below.
3. Get the secret token
Open the site's settings in the dashboard and regenerate the secret token. It's shown once, so copy it then. It starts with sec_.
Regenerating replaces the old token right away. If a server is already using it, update that server at the same time.
SUPAPULSE_SECRET_TOKEN=sec_your_secret_tokenDon't prefix it with NEXT_PUBLIC_, VITE_ or anything else that bundles it into browser code.
4. Send revenue
@supapulse/revenue SDK
npm install @supapulse/revenueimport { Revenue } from '@supapulse/revenue';
export const revenue = new Revenue({ apiToken: process.env.SUPAPULSE_SECRET_TOKEN! });
await revenue.track({
customer_id: 'user_123',
amount: 49.9,
currency: 'USD',
transaction_id: 'in_1Q8x…',
event_type: 'renewal',
});track() validates its input, retries network errors and 429 responses, and throws straight away on any other 4xx. It warns in the console if it's loaded in a browser. The full surface is in the Revenue API reference.
HTTP API
No package needed. Any language that can make an HTTPS request works:
type Revenue = {
customerId: string;
amount: number;
transactionId: string;
eventType?: 'purchase' | 'subscription' | 'renewal' | 'upgrade' | 'downgrade' | 'churn' | 'refund';
currency?: string;
visitorFingerprint?: string;
sessionId?: string;
paymentProcessor?: string;
subscriptionId?: string;
mrrImpact?: number;
occurredAt?: string;
};
export async function trackRevenue(revenue: Revenue): Promise<void> {
const response = await fetch('https://supapulse.app/api/ingest', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Token': process.env.SUPAPULSE_SECRET_TOKEN!,
},
body: JSON.stringify({
type: 'revenue',
data: {
customer_id: revenue.customerId,
amount: revenue.amount,
transaction_id: revenue.transactionId,
event_type: revenue.eventType,
currency: revenue.currency ?? 'USD',
visitor_fingerprint: revenue.visitorFingerprint,
session_id: revenue.sessionId,
payment_processor: revenue.paymentProcessor,
subscription_id: revenue.subscriptionId,
mrr_impact: revenue.mrrImpact,
occurred_at: revenue.occurredAt,
},
}),
});
if (!response.ok) {
throw new Error(`Supapulse ingest failed: ${response.status} ${await response.text()}`);
}
}JSON.stringify drops undefined fields, so optional values can be left out. The rest of these docs use this trackRevenue() helper.
5. Check it
Send a test payment through your provider's test mode, then open the site's revenue view. The payment shows up once the worker has processed it, usually within seconds.
If nothing appears:
401 Invalid API token: the token is wrong or was regenerated.402: the site's team has no active plan. The body'scodeisplan_inactive.422: the body is missingcustomer_id,amountortransaction_id, or a field is invalid. The response lists each field. A public token also gets422, because it can't sendrevenue.202but no new revenue: a payment with the sametransaction_idandevent_typewas already stored.