Transactions API
The Transactions API enables you to process payments, track purchases, manage refunds, and analyze revenue across your games. Support both real-money transactions and virtual currency exchanges with comprehensive financial analytics and reporting.
Authentication
Most endpoints require authentication using either:
- API Key: Include
x-api-keyheader - Cognito JWT: Include
Authorization: Bearer <token>header - Developer Auth: Special authentication for developer operations
- Admin Auth: Required for refund operations
The payment webhook endpoint (processPaymentWebhook) is public for integration with payment providers.
Base URL
https://sdk.getjar.com/transactions
Core Concepts
Transaction Types
| Type | Description |
|---|---|
| PURCHASE | Real-money purchase of products |
| REFUND | Refund of a previous purchase |
| EARNED | Currency earned through gameplay/rewards |
| SPENT | Virtual currency spent on in-game items |
| VIRTUAL_PURCHASE | Purchase using virtual currency |
Transaction Status Flow
PENDING → PROCESSING → COMPLETED
↓ ↓
FAILED CANCELLED
COMPLETED → REFUNDED (after refund)
Currency Support
- Real Money: USD, EUR, GBP, and other standard currency codes
- Virtual: In-game currencies (gold, gems, credits, etc.)
Payment Methods
- CREDIT_CARD: Credit/debit card payments
- PAYPAL: PayPal payments
- STRIPE: Stripe payment processing
- APPLE_PAY: Apple Pay payments
- GOOGLE_PAY: Google Pay payments
- VIRTUAL_CURRENCY: Virtual currency transactions
Create Transaction
Initialize a new transaction for purchases, virtual currency exchanges, or user rewards. Virtual currency transactions are auto-completed.
Endpoint
POST /transactions
Request Body
{
userId: string; // Required: User identifier
appId: string; // Required: Application identifier
productId?: string; // Product identifier (for purchases)
amount: number; // Required: Transaction amount
currency: string; // Required: USD, EUR, GBP, VIRTUAL
type: string; // Required: PURCHASE, REFUND, EARNED, SPENT, VIRTUAL_PURCHASE
paymentMethod?: string; // CREDIT_CARD, PAYPAL, STRIPE, APPLE_PAY, GOOGLE_PAY, VIRTUAL_CURRENCY
description?: string; // Transaction description
metadata?: object; // Additional metadata
virtualCurrency?: { // For virtual currency transactions
currencyType: string; // Currency type (e.g., 'gold', 'gems')
balanceBefore: number; // Balance before transaction
balanceAfter: number; // Balance after transaction
};
}
Response
{
transactionId: string;
userId: string;
appId: string;
productId: string | null;
amount: number;
currency: string;
type: string;
status: string; // PENDING or COMPLETED (for virtual)
paymentMethod: string | null;
virtualCurrency: {
currencyType: string;
balanceBefore: number;
balanceAfter: number;
} | null;
createdAt: string;
}
Example: Real Money Purchase
import { TransactionsApi } from "@getjar-iap/sdk";
const transactionsApi = new TransactionsApi(configuration);
const transaction = await transactionsApi.createTransaction({
body: {
appId: "app_123",
userId: "user_123",
productId: "prod_123",
amount: 9.99,
currency: "USD",
type: "PURCHASE",
paymentMethod: "STRIPE",
description: "Gold Pack 100",
metadata: {
platform: "IOS",
appVersion: "1.2.3",
},
},
});
console.log("Transaction ID:", transaction.data.transactionId);
console.log("Status:", transaction.data.status); // PENDING
Example: Virtual Currency Transaction
const virtualTransaction = await transactionsApi.createTransaction({
body: {
appId: "app_123",
userId: "user_123",
amount: 100,
currency: "VIRTUAL",
type: "VIRTUAL_PURCHASE",
paymentMethod: "VIRTUAL_CURRENCY",
description: "Health Potion",
virtualCurrency: {
currencyType: "gold",
balanceBefore: 500,
balanceAfter: 400,
},
},
});
console.log("Status:", virtualTransaction.data.status); // COMPLETED (auto-completed)
console.log(
"New Balance:",
virtualTransaction.data.virtualCurrency?.balanceAfter
);
Example: Earned Currency
const reward = await transactionsApi.createTransaction({
body: {
appId: "app_123",
userId: "user_123",
amount: 50,
currency: "VIRTUAL",
type: "EARNED",
description: "Daily login bonus",
virtualCurrency: {
currencyType: "gold",
balanceBefore: 400,
balanceAfter: 450,
},
},
});
console.log("Earned:", reward.data.amount, "gold");
Response Codes
| Code | Description |
|---|---|
| 201 | Transaction created successfully |
| 400 | Insufficient balance or invalid data |
| 401 | Unauthorized |
| 404 | User or product does not exist |
Complete Transaction
Mark a transaction as completed after successful payment processing. Updates user virtual currency balance if applicable.
Endpoint
PUT /transactions/:transactionId/complete
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| transactionId | string | Yes | The unique transaction identifier |
Request Body
{
externalTransactionId?: string; // Payment provider transaction ID
receiptId?: string; // Receipt identifier
metadata?: object; // Additional metadata
}
Response
{
transactionId: string;
status: string; // COMPLETED
externalTransactionId: string;
updatedAt: string;
}
Example
const completed = await transactionsApi.completeTransaction({
transactionId: "txn_1234567890_abc123",
body: {
externalTransactionId: "stripe_ch_1234567890",
receiptId: "receipt_abc123",
metadata: {
completedAt: new Date().toISOString(),
ipAddress: "192.168.1.1",
},
},
});
console.log("Transaction completed:", completed.data.transactionId);
console.log("Status:", completed.data.status);
Response Codes
| Code | Description |
|---|---|
| 200 | Transaction completed successfully |
| 400 | Transaction cannot be completed (not PENDING/PROCESSING) |
| 401 | Unauthorized |
| 404 | Transaction does not exist |
Fail Transaction
Mark a transaction as failed with a reason. Used when payment processing fails.
Endpoint
PUT /transactions/:transactionId/fail
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| transactionId | string | Yes | The unique transaction identifier |
Request Body
{
failureReason: string; // Required: Reason for failure
}
Response
{
transactionId: string;
status: string; // FAILED
failureReason: string;
updatedAt: string;
}
Example
const failed = await transactionsApi.failTransaction({
transactionId: "txn_1234567890_abc123",
body: {
failureReason: "Insufficient funds",
},
});
console.log("Transaction failed:", failed.data.failureReason);
Response Codes
| Code | Description |
|---|---|
| 200 | Transaction marked as failed |
| 400 | Transaction cannot be failed (not PENDING/PROCESSING) |
| 401 | Unauthorized |
| 404 | Transaction does not exist |
Process Refund
Create a refund transaction for a completed purchase. Original transaction will be marked as REFUNDED.
Endpoint
POST /transactions/:transactionId/refund
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| transactionId | string | Yes | The original transaction identifier |
Request Body
{
refundAmount: number; // Required: Amount to refund
refundReason?: string; // Reason for refund
metadata?: object; // Additional metadata
}
Response
{
transactionId: string; // New refund transaction ID
userId: string;
amount: number;
type: string; // REFUND
status: string; // COMPLETED
metadata: {
originalTransactionId: string;
refundReason: string;
}
}
Example
const refund = await transactionsApi.refundTransaction({
transactionId: "txn_1234567890_abc123",
body: {
refundAmount: 9.99,
refundReason: "Customer request",
metadata: {
requestedBy: "support_agent_42",
ticketId: "TICKET-12345",
},
},
});
console.log("Refund transaction:", refund.data.transactionId);
console.log("Original:", refund.data.metadata?.originalTransactionId);
Response Codes
| Code | Description |
|---|---|
| 201 | Refund processed successfully |
| 400 | Only completed transactions can be refunded |
| 401 | Unauthorized |
| 404 | Transaction does not exist |
Get Transaction by ID
Retrieve detailed information about a specific transaction including related user, app, and product details.
Endpoint
GET /transactions/:transactionId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| transactionId | string | Yes | The unique transaction identifier |
Response
{
transactionId: string;
userId: string;
appId: string;
productId: string | null;
userProductId: string | null;
amount: number;
currency: string;
type: string;
status: string;
paymentMethod: string | null;
externalTransactionId: string | null;
receiptId: string | null;
description: string | null;
failureReason: string | null;
virtualCurrency: {
currencyType: string;
balanceBefore: number;
balanceAfter: number;
} | null;
metadata: object;
createdAt: string;
updatedAt: string;
user: object | null;
app: object | null;
product: object | null;
}
Example
const transaction = await transactionsApi.getTransactionById({
transactionId: "txn_1234567890_abc123",
});
console.log("Amount:", `$${transaction.data.amount}`);
console.log("Status:", transaction.data.status);
console.log("Payment Method:", transaction.data.paymentMethod);
console.log("User:", transaction.data.user);
console.log("Product:", transaction.data.product);
Response Codes
| Code | Description |
|---|---|
| 200 | Transaction retrieved |
| 401 | Unauthorized |
| 404 | Transaction does not exist |
Get User Transactions
Retrieve a paginated list of transactions for a specific user with optional filters by status, type, and date range.
Endpoint
GET /transactions/user/:userId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| page | number | No | Page number (default: 1) |
| limit | number | No | Items per page (default: 20) |
| status | string | No | Filter by status |
| type | string | No | Filter by type |
| startDate | string | No | Start date (ISO format) |
| endDate | string | No | End date (ISO format) |
Response
{
items: Array<{
transactionId: string;
userId: string;
appId: string;
amount: number;
currency: string;
type: string;
status: string;
paymentMethod: string;
description: string;
createdAt: string;
}>;
pagination: {
total: number;
page: number;
limit: number;
totalPages: number;
hasNextPage: boolean;
hasPreviousPage: boolean;
}
}
Example
// Get all user transactions
const transactions = await transactionsApi.getUserTransactions({
userId: "user_123",
page: 1,
limit: 20,
});
console.log("Total transactions:", transactions.data.pagination.total);
// Get completed purchases only
const purchases = await transactionsApi.getUserTransactions({
userId: "user_123",
status: "COMPLETED",
type: "PURCHASE",
page: 1,
limit: 50,
});
console.log("Completed purchases:", purchases.data.items);
// Get transactions for date range
const monthlyTransactions = await transactionsApi.getUserTransactions({
userId: "user_123",
startDate: "2025-10-01T00:00:00Z",
endDate: "2025-10-31T23:59:59Z",
page: 1,
limit: 100,
});
console.log("October transactions:", monthlyTransactions.data.items.length);
Response Codes
| Code | Description |
|---|---|
| 200 | Transactions retrieved |
| 401 | Unauthorized |
| 404 | User does not exist |
Get User Spending Summary
Retrieve comprehensive spending and earning analytics for a user with breakdowns by type and currency.
Endpoint
GET /transactions/user/:userId/summary
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| startDate | string | No | Start date (ISO format) |
| endDate | string | No | End date (ISO format) |
Response
{
totalSpent: number;
totalEarned: number;
netBalance: number; // earned - spent
transactionCount: number;
byType: {
PURCHASE: number;
EARNED: number;
SPENT: number;
VIRTUAL_PURCHASE: number;
}
byCurrency: {
USD: number;
EUR: number;
VIRTUAL: number;
}
byStatus: {
COMPLETED: number;
PENDING: number;
REFUNDED: number;
}
averageTransactionAmount: number;
largestTransaction: {
transactionId: string;
amount: number;
createdAt: string;
}
}
Example
const summary = await transactionsApi.getUserSpendingSummary({
userId: "user_123",
});
console.log("💰 User Spending Summary:");
console.log("Total Spent:", `$${summary.data.totalSpent.toFixed(2)}`);
console.log("Total Earned:", `$${summary.data.totalEarned.toFixed(2)}`);
console.log("Net Balance:", `$${summary.data.netBalance.toFixed(2)}`);
console.log("Transactions:", summary.data.transactionCount);
console.log("Average:", `$${summary.data.averageTransactionAmount.toFixed(2)}`);
console.log("\n📊 By Type:");
Object.entries(summary.data.byType).forEach(([type, amount]) => {
console.log(`${type}: $${amount.toFixed(2)}`);
});
console.log("\n💵 By Currency:");
Object.entries(summary.data.byCurrency).forEach(([currency, amount]) => {
console.log(`${currency}: $${amount.toFixed(2)}`);
});
// Get summary for specific period
const monthlySummary = await transactionsApi.getUserSpendingSummary({
userId: "user_123",
startDate: "2025-10-01T00:00:00Z",
endDate: "2025-10-31T23:59:59Z",
});
console.log(
"\nOctober Spending:",
`$${monthlySummary.data.totalSpent.toFixed(2)}`
);
Response Codes
| Code | Description |
|---|---|
| 200 | Summary retrieved |
| 401 | Unauthorized |
| 404 | User does not exist |
Get App Transactions
Retrieve a paginated list of all transactions for a specific app with optional filters.
Endpoint
GET /transactions/app/:appId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| appId | string | Yes | The application identifier |
| page | number | No | Page number (default: 1) |
| limit | number | No | Items per page (default: 20) |
| status | string | No | Filter by status |
| type | string | No | Filter by type |
| startDate | string | No | Start date (ISO format) |
| endDate | string | No | End date (ISO format) |
Example
const appTransactions = await transactionsApi.getAppTransactions({
appId: "app_123",
page: 1,
limit: 100,
});
console.log("Total transactions:", appTransactions.data.pagination.total);
console.log("Total revenue:", calculateRevenue(appTransactions.data.items));
Response Codes
| Code | Description |
|---|---|
| 200 | Transactions retrieved |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | App does not exist |
Get App Revenue Statistics
Retrieve comprehensive revenue analytics for an app including total revenue, transaction counts, and breakdowns.
Endpoint
GET /transactions/app/:appId/stats
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| appId | string | Yes | The application identifier |
| startDate | string | No | Start date (ISO format) |
| endDate | string | No | End date (ISO format) |
Response
{
totalRevenue: number;
totalTransactions: number;
completedTransactions: number;
pendingTransactions: number;
failedTransactions: number;
refundedTransactions: number;
totalRefunds: number;
netRevenue: number; // revenue - refunds
averageTransactionValue: number;
byType: {
PURCHASE: number;
VIRTUAL_PURCHASE: number;
}
byCurrency: {
USD: number;
EUR: number;
GBP: number;
}
byPaymentMethod: {
STRIPE: number;
APPLE_PAY: number;
GOOGLE_PAY: number;
PAYPAL: number;
}
topProducts: Array<{
productId: string;
productName: string;
revenue: number;
salesCount: number;
}>;
revenueOverTime: Array<{
date: string; // YYYY-MM-DD
revenue: number;
transactionCount: number;
}>;
}
Example
const stats = await transactionsApi.getAppRevenueStats({
appId: "app_123",
});
console.log("📈 Revenue Statistics:");
console.log("Total Revenue:", `$${stats.data.totalRevenue.toLocaleString()}`);
console.log("Net Revenue:", `$${stats.data.netRevenue.toLocaleString()}`);
console.log("Total Transactions:", stats.data.totalTransactions);
console.log(
"Average Transaction:",
`$${stats.data.averageTransactionValue.toFixed(2)}`
);
console.log("Completed:", stats.data.completedTransactions);
console.log("Refunded:", stats.data.refundedTransactions);
console.log("\n💳 By Payment Method:");
Object.entries(stats.data.byPaymentMethod).forEach(([method, count]) => {
console.log(`${method}: ${count} transactions`);
});
console.log("\n🏆 Top Products:");
stats.data.topProducts.slice(0, 5).forEach((product, index) => {
console.log(
`${index + 1}. ${
product.productName
}: $${product.revenue.toLocaleString()} (${product.salesCount} sales)`
);
});
// Get monthly stats
const monthlyStats = await transactionsApi.getAppRevenueStats({
appId: "app_123",
startDate: "2025-10-01T00:00:00Z",
endDate: "2025-10-31T23:59:59Z",
});
console.log(
"\nOctober Revenue:",
`$${monthlyStats.data.totalRevenue.toFixed(2)}`
);
Response Codes
| Code | Description |
|---|---|
| 200 | Statistics retrieved |
| 401 | Unauthorized |
| 404 | App does not exist |
Process Payment Webhook
Endpoint for payment provider webhooks (Stripe, PayPal, etc.). Updates transaction status based on payment provider events. This endpoint is public.
Endpoint
POST /transactions/webhook/payment
Request Body
{
transactionId: string; // Required: Transaction identifier
externalTransactionId: string; // Required: Provider transaction ID
status: string; // Required: 'success' or 'failed'
receiptData?: string; // Optional receipt data
metadata?: object; // Additional metadata
}
Response
{
transactionId: string;
status: string; // COMPLETED or FAILED
message: string;
}
Example: Stripe Webhook Handler
// Server-side webhook handler
app.post("/stripe/webhook", async (req, res) => {
const signature = req.headers["stripe-signature"];
const event = stripe.webhooks.constructEvent(
req.body,
signature,
webhookSecret
);
if (event.type === "charge.succeeded") {
const charge = event.data.object;
await transactionsApi.processPaymentWebhook({
body: {
transactionId: charge.metadata.transactionId,
externalTransactionId: charge.id,
status: "success",
receiptData: JSON.stringify(charge),
},
});
}
res.json({ received: true });
});
Response Codes
| Code | Description |
|---|---|
| 200 | Webhook processed successfully |
| 404 | Transaction not found |
Complete Example
Here's a complete workflow for processing transactions:
import { Configuration, TransactionsApi } from "@getjar-iap/sdk";
const configuration = new Configuration({
basePath: "https://sdk.getjar.com",
apiKey: "your-api-key",
});
const transactionsApi = new TransactionsApi(configuration);
async function processPayment() {
const appId = "app_123";
const userId = "user_123";
const productId = "prod_123";
console.log("💳 Processing payment...\n");
try {
// 1. Create transaction
const transaction = await transactionsApi.createTransaction({
body: {
appId,
userId,
productId,
amount: 9.99,
currency: "USD",
type: "PURCHASE",
paymentMethod: "STRIPE",
description: "Gold Pack 100",
metadata: {
platform: "IOS",
appVersion: "1.2.3",
},
},
});
console.log("✓ Transaction created:", transaction.data.transactionId);
console.log("Status:", transaction.data.status);
const transactionId = transaction.data.transactionId;
// 2. Process payment with Stripe (example)
// const stripeCharge = await stripe.charges.create({...});
// 3. Complete transaction after successful payment
const completed = await transactionsApi.completeTransaction({
transactionId,
body: {
externalTransactionId: "stripe_ch_1234567890",
receiptId: "receipt_abc123",
metadata: {
completedAt: new Date().toISOString(),
},
},
});
console.log("\n✓ Transaction completed");
console.log("External ID:", completed.data.externalTransactionId);
// 4. Get transaction details
const details = await transactionsApi.getTransactionById({
transactionId,
});
console.log("\n📄 Transaction Details:");
console.log("Amount:", `$${details.data.amount}`);
console.log("Type:", details.data.type);
console.log("Status:", details.data.status);
console.log("Method:", details.data.paymentMethod);
// 5. Get user summary
const summary = await transactionsApi.getUserSpendingSummary({
userId,
});
console.log("\n💰 User Summary:");
console.log("Total Spent:", `$${summary.data.totalSpent.toFixed(2)}`);
console.log("Total Transactions:", summary.data.transactionCount);
return transaction;
} catch (error: any) {
console.error("\n❌ Payment failed:", error.response?.data?.message);
// Mark transaction as failed
if (error.response?.data?.transactionId) {
await transactionsApi.failTransaction({
transactionId: error.response.data.transactionId,
body: {
failureReason: error.message || "Payment processing failed",
},
});
}
throw error;
}
}
// Run the payment flow
processPayment()
.then(() => console.log("\n✅ Payment processed successfully!"))
.catch((error) => console.error("\n❌ Error:", error));
Virtual Currency Example
Complete example for virtual currency transactions:
async function virtualCurrencySystem(userId: string, appId: string) {
// User's current balance
let goldBalance = 500;
// 1. User earns gold from daily login
const dailyReward = await transactionsApi.createTransaction({
body: {
appId,
userId,
amount: 50,
currency: "VIRTUAL",
type: "EARNED",
description: "Daily login bonus",
virtualCurrency: {
currencyType: "gold",
balanceBefore: goldBalance,
balanceAfter: goldBalance + 50,
},
},
});
goldBalance += 50;
console.log("✓ Earned 50 gold. New balance:", goldBalance);
// 2. User purchases item with gold
const purchase = await transactionsApi.createTransaction({
body: {
appId,
userId,
amount: 100,
currency: "VIRTUAL",
type: "SPENT",
description: "Health Potion",
virtualCurrency: {
currencyType: "gold",
balanceBefore: goldBalance,
balanceAfter: goldBalance - 100,
},
},
});
goldBalance -= 100;
console.log("✓ Spent 100 gold. New balance:", goldBalance);
// 3. Get user's virtual currency history
const transactions = await transactionsApi.getUserTransactions({
userId,
type: "EARNED",
limit: 10,
});
console.log("\n💎 Recent Earnings:");
transactions.data.items.forEach((txn) => {
console.log(
`${txn.description}: +${txn.amount} ${txn.virtualCurrency?.currencyType}`
);
});
return { goldBalance, transactions };
}
Revenue Analytics Dashboard
Build a comprehensive revenue dashboard:
async function buildRevenueDashboard(appId: string) {
// Get current month stats
const now = new Date();
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
const stats = await transactionsApi.getAppRevenueStats({
appId,
startDate: monthStart.toISOString(),
endDate: now.toISOString(),
});
// Calculate key metrics
const conversionRate =
(stats.data.completedTransactions / stats.data.totalTransactions) * 100;
const refundRate =
(stats.data.refundedTransactions / stats.data.completedTransactions) * 100;
const dashboard = {
overview: {
totalRevenue: `$${stats.data.totalRevenue.toLocaleString()}`,
netRevenue: `$${stats.data.netRevenue.toLocaleString()}`,
transactions: stats.data.totalTransactions,
avgTransaction: `$${stats.data.averageTransactionValue.toFixed(2)}`,
conversionRate: `${conversionRate.toFixed(1)}%`,
refundRate: `${refundRate.toFixed(1)}%`,
},
status: {
completed: stats.data.completedTransactions,
pending: stats.data.pendingTransactions,
failed: stats.data.failedTransactions,
refunded: stats.data.refundedTransactions,
},
paymentMethods: Object.entries(stats.data.byPaymentMethod).map(
([method, count]) => ({
method,
transactions: count,
percentage: ((count / stats.data.totalTransactions) * 100).toFixed(1),
})
),
topProducts: stats.data.topProducts.slice(0, 5),
timeline: stats.data.revenueOverTime.map((day) => ({
date: day.date,
revenue: `$${day.revenue.toFixed(2)}`,
transactions: day.transactionCount,
})),
};
console.log("📊 Revenue Dashboard\n");
console.log("Overview:");
console.log(JSON.stringify(dashboard.overview, null, 2));
console.log("\nTransaction Status:");
console.log(JSON.stringify(dashboard.status, null, 2));
console.log("\nPayment Methods:");
console.log(JSON.stringify(dashboard.paymentMethods, null, 2));
console.log("\nTop 5 Products:");
console.log(JSON.stringify(dashboard.topProducts, null, 2));
return dashboard;
}
Best Practices
Transaction Processing
-
Always Handle Errors: Payment processing can fail
try {
const transaction = await createTransaction({...});
// Process payment
await completeTransaction({...});
} catch (error) {
await failTransaction({...});
// Notify user
} -
Idempotency: Use unique transaction IDs
const transactionId = `txn_${Date.now()}_${userId}`; -
Metadata: Include useful context
metadata: {
platform: "IOS",
appVersion: "1.2.3",
deviceId: "device_abc123",
ipAddress: "192.168.1.1"
} -
Receipt Storage: Always store receipt IDs
await completeTransaction({
transactionId,
body: {
receiptId: providerReceiptId,
externalTransactionId: providerTransactionId,
},
});
Virtual Currency
-
Balance Tracking: Always track before/after balances
virtualCurrency: {
currencyType: "gold",
balanceBefore: currentBalance,
balanceAfter: currentBalance - amount
} -
Validate Sufficient Balance: Check before creating transaction
if (userBalance < purchaseAmount) {
throw new Error("Insufficient balance");
} -
Auto-Completion: Virtual currency transactions complete automatically
const virtualTxn = await createTransaction({
type: "VIRTUAL_PURCHASE",
currency: "VIRTUAL",
});
// Already completed, no need to call completeTransaction
Refund Management
-
Document Reasons: Always include refund reason
await refundTransaction({
transactionId,
body: {
refundAmount: originalAmount,
refundReason: "Customer request - accidental purchase",
metadata: {
supportTicket: "TICKET-12345",
},
},
}); -
Partial Refunds: Support partial refund amounts
refundAmount: originalAmount * 0.5; // 50% refund -
Track Refund Rates: Monitor for abuse
const stats = await getAppRevenueStats({ appId });
const refundRate =
(stats.refundedTransactions / stats.completedTransactions) * 100;
if (refundRate > 5) {
// Investigate high refund rate
}
Analytics & Reporting
-
Regular Monitoring: Check revenue stats daily
// Daily revenue check
const today = new Date();
const stats = await getAppRevenueStats({
appId,
startDate: today.toISOString(),
endDate: new Date(today.getTime() + 24 * 60 * 60 * 1000).toISOString(),
}); -
Compare Periods: Month-over-month growth
const thisMonth = await getAppRevenueStats({
appId,
startDate: thisMonthStart,
endDate: now,
});
const lastMonth = await getAppRevenueStats({
appId,
startDate: lastMonthStart,
endDate: lastMonthEnd,
});
const growth =
((thisMonth.totalRevenue - lastMonth.totalRevenue) /
lastMonth.totalRevenue) *
100; -
User Segmentation: Identify high-value users
const summary = await getUserSpendingSummary({ userId });
if (summary.totalSpent > 100) {
// High-value user - offer VIP rewards
}
Common Patterns
Payment Gateway Integration
async function stripePaymentFlow(
userId: string,
productId: string,
amount: number
) {
// 1. Create GetJar transaction
const transaction = await transactionsApi.createTransaction({
body: {
appId: "app_123",
userId,
productId,
amount,
currency: "USD",
type: "PURCHASE",
paymentMethod: "STRIPE",
},
});
try {
// 2. Process with Stripe
const paymentIntent = await stripe.paymentIntents.create({
amount: Math.round(amount * 100), // cents
currency: "usd",
metadata: {
transactionId: transaction.data.transactionId,
},
});
// 3. Complete on success
await transactionsApi.completeTransaction({
transactionId: transaction.data.transactionId,
body: {
externalTransactionId: paymentIntent.id,
receiptId: paymentIntent.receipt_email,
},
});
return { success: true, transaction };
} catch (error) {
// 4. Fail on error
await transactionsApi.failTransaction({
transactionId: transaction.data.transactionId,
body: {
failureReason: error.message,
},
});
throw error;
}
}
Subscription Billing
async function processSubscriptionPayment(
userId: string,
subscriptionId: string,
amount: number
) {
const transaction = await transactionsApi.createTransaction({
body: {
appId: "app_123",
userId,
productId: subscriptionId,
amount,
currency: "USD",
type: "PURCHASE",
paymentMethod: "STRIPE",
description: "Monthly subscription",
metadata: {
subscriptionId,
billingPeriod: new Date().toISOString(),
},
},
});
return transaction;
}
Transaction History Export
async function exportTransactionHistory(
userId: string,
startDate: string,
endDate: string
) {
const allTransactions = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const result = await transactionsApi.getUserTransactions({
userId,
startDate,
endDate,
page,
limit: 100,
});
allTransactions.push(...result.data.items);
hasMore = result.data.pagination.hasNextPage;
page++;
}
// Convert to CSV or export format
const csv = allTransactions
.map(
(txn) =>
`${txn.transactionId},${txn.amount},${txn.currency},${txn.type},${txn.status},${txn.createdAt}`
)
.join("\n");
return csv;
}
Error Handling
async function safeTransactionOperation() {
try {
const transaction = await transactionsApi.createTransaction({
body: {
/* ... */
},
});
return {
success: true,
data: transaction.data,
};
} catch (error) {
if (error.response) {
switch (error.response.status) {
case 400:
if (error.response.data.message.includes("Insufficient balance")) {
console.error("User doesn't have enough virtual currency");
} else {
console.error("Invalid transaction data");
}
break;
case 401:
console.error("Authentication required");
break;
case 404:
console.error("User or product not found");
break;
default:
console.error("Unexpected error:", error.response.status);
}
}
return {
success: false,
error: error.message,
};
}
}
Support
For additional help or questions:
- Documentation: https://docs.getjar.com
- API Reference: https://sdk.getjar.com/api/docs
- Support: support@getjar.com