Official JavaScript SDK for SubLoop's payment analytics API. Works in both Node.js and browser environments.
npm install subloop-js
const SubLoop = require('subloop-js');
// Initialize the client
const subloop = new SubLoop('sk_your_api_key_here');
// Send payment data
const payment = await subloop.payments.createSuccessful(
'cust_001', // customerId
29.99, // amount
'USD', // currency
'sub_001' // subscriptionId
);
// Get analytics
const overview = await subloop.analytics.getOverview();
const mrr = await subloop.analytics.getMRR();
Get your API key from your SubLoop dashboard:
const subloop = new SubLoop('sk_your_api_key_here');
// For development/testing
const subloop = new SubLoop('sk_your_api_key_here', 'http://localhost:8000');
// Manual payment creation
const payment = await subloop.payments.create({
customer_id: 'cust_001',
subscription_id: 'sub_001', // Optional for recurring payments
amount: 29.99,
currency: 'USD',
status: 'succeeded', // succeeded, failed, pending, refunded
payment_date: '2025-07-31T00:00:00Z',
payment_method: 'card',
metadata: {
gateway_transaction_id: 'txn_123',
customer_email: '[email protected]'
}
});
// Helper methods for common scenarios
const successfulPayment = await subloop.payments.createSuccessful(
'cust_001',
29.99,
'USD',
'sub_001'
);
const failedPayment = await subloop.payments.createFailed(
'cust_002',
19.99,
'USD'
);
const refundedPayment = await subloop.payments.createRefunded(
'cust_003',
39.99,
'USD',
'sub_002'
);
// Get all payments
const payments = await subloop.payments.list();
// With pagination
const payments = await subloop.payments.list({ page: 2 });
// Get specific payment
const payment = await subloop.payments.get(123);
const overview = await subloop.analytics.getOverview();
console.log(`MRR: $${overview.mrr}`);
console.log(`Total Revenue (30d): $${overview.total_revenue_30d}`);
console.log(`Active Subscriptions: ${overview.active_subscriptions}`);
console.log(`Success Rate: ${overview.payment_success_rate}%`);
const mrr = await subloop.analytics.getMRR();
console.log(`Current MRR: $${mrr.mrr}`);
console.log(`Previous MRR: $${mrr.previous_mrr}`);
console.log(`Growth: ${mrr.growth_percentage}%`);
// Get revenue for different periods
const revenue30d = await subloop.analytics.getRevenue('30days');
const revenue7d = await subloop.analytics.getRevenueLast7Days();
const revenue90d = await subloop.analytics.getRevenueLast90Days();
// Custom date range
const customRevenue = await subloop.analytics.getRevenueForDateRange(
'2025-06-01',
'2025-07-31'
);
// Get recent payments
const recentPayments = await subloop.analytics.getPayments(10);
// Get only successful payments
const successfulPayments = await subloop.analytics.getSuccessfulPayments(20);
// Get only recurring payments
const recurringPayments = await subloop.analytics.getRecurringPayments(15);
// Filter by status
const failedPayments = await subloop.analytics.getFailedPayments(10);
const express = require('express');
const SubLoop = require('subloop-js');
const app = express();
const subloop = new SubLoop(process.env.SUBLOOP_API_KEY);
app.use(express.json());
// Stripe webhook handler
app.post('/webhooks/stripe', async (req, res) => {
const event = req.body;
if (event.type === 'payment_intent.succeeded') {
const paymentIntent = event.data.object;
try {
await subloop.payments.createSuccessful(
paymentIntent.customer,
paymentIntent.amount_received / 100, // Convert from cents
paymentIntent.currency.toUpperCase(),
paymentIntent.metadata.subscription_id,
{
stripe_payment_intent_id: paymentIntent.id,
stripe_charge_id: paymentIntent.charges.data[0]?.id
}
);
console.log('Payment tracked in SubLoop');
} catch (error) {
console.error('SubLoop error:', error.message);
}
}
res.json({ received: true });
});
app.listen(3000);
// pages/api/webhooks/payment.js
import SubLoop from 'subloop-js';
const subloop = new SubLoop(process.env.SUBLOOP_API_KEY);
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { customerId, amount, currency, subscriptionId } = req.body;
const payment = await subloop.payments.createSuccessful(
customerId,
amount,
currency,
subscriptionId
);
res.status(200).json({ success: true, payment });
} catch (error) {
console.error('SubLoop error:', error);
res.status(500).json({ error: 'Failed to track payment' });
}
}
import React, { useState, useEffect } from 'react';
import SubLoop from 'subloop-js';
const subloop = new SubLoop(process.env.REACT_APP_SUBLOOP_API_KEY);
function Dashboard() {
const [analytics, setAnalytics] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchAnalytics() {
try {
const [overview, mrr, recentPayments] = await Promise.all([
subloop.analytics.getOverview(),
subloop.analytics.getMRR(),
subloop.analytics.getPayments(5)
]);
setAnalytics({ overview, mrr, recentPayments });
} catch (error) {
console.error('Failed to fetch analytics:', error);
} finally {
setLoading(false);
}
}
fetchAnalytics();
}, []);
if (loading) return <div>Loading...</div>;
return (
<div className="dashboard">
<h1>Revenue Analytics</h1>
<div className="metrics">
<div className="metric">
<h3>MRR</h3>
<p>${analytics.overview.mrr}</p>
</div>
<div className="metric">
<h3>Total Revenue (30d)</h3>
<p>${analytics.overview.total_revenue_30d}</p>
</div>
<div className="metric">
<h3>Active Subscriptions</h3>
<p>{analytics.overview.active_subscriptions}</p>
</div>
</div>
<div className="recent-payments">
<h3>Recent Payments</h3>
{analytics.recentPayments.data.map(payment => (
<div key={payment.id} className="payment">
<span>${payment.amount}</span>
<span>{payment.status}</span>
<span>{payment.customer_id}</span>
</div>
))}
</div>
</div>
);
}
export default Dashboard;
<!DOCTYPE html>
<html>
<head>
<title>SubLoop Analytics</title>
</head>
<body>
<div id="analytics"></div>
<script src="https://unpkg.com/[email protected]/dist/subloop.min.js"></script>
<script>
const subloop = new SubLoop('sk_your_api_key_here');
async function loadAnalytics() {
try {
const overview = await subloop.analytics.getOverview();
document.getElementById('analytics').innerHTML = `
<h2>Revenue Overview</h2>
<p>MRR: $${overview.mrr}</p>
<p>Total Revenue: $${overview.total_revenue_30d}</p>
<p>Active Subscriptions: ${overview.active_subscriptions}</p>
`;
} catch (error) {
console.error('Error loading analytics:', error);
}
}
loadAnalytics();
</script>
</body>
</html>
const { SubLoopError } = require('subloop-js');
try {
const payment = await subloop.payments.create({
customer_id: 'cust_001',
amount: 29.99,
currency: 'USD',
status: 'succeeded',
payment_date: '2025-07-31T00:00:00Z'
});
} catch (error) {
if (error instanceof SubLoopError) {
console.log('SubLoop Error:', error.message);
console.log('Status Code:', error.getStatusCode());
if (error.isValidationError()) {
console.log('Validation errors:', error.getDetails());
} else if (error.isAuthenticationError()) {
console.log('Authentication failed - check your API key');
} else if (error.isRateLimitError()) {
console.log('Rate limit exceeded - please try again later');
}
} else {
console.log('General Error:', error.message);
}
}
The SDK includes TypeScript definitions:
import SubLoop from 'subloop-js';
interface PaymentData {
customer_id: string;
amount: number;
currency: string;
status: 'succeeded' | 'failed' | 'pending' | 'refunded';
payment_date: string;
subscription_id?: string;
metadata?: Record<string, any>;
}
const subloop = new SubLoop('sk_your_api_key_here');
const payment: PaymentData = await subloop.payments.create({
customer_id: 'cust_001',
amount: 29.99,
currency: 'USD',
status: 'succeeded',
payment_date: new Date().toISOString()
});
MIT License. See LICENSE for more information.