Products API
The Products API enables you to create and manage in-app purchases including consumables, non-consumables, subscriptions, and virtual currency packs. Build a complete in-game economy with flexible pricing, product visibility controls, and comprehensive analytics.
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
Public endpoints like getProductById, getAppProducts, and getProductsByCategory don't require authentication.
Base URL
https://sdk.getjar.com/products
Product Types
GetJar supports four types of in-app products:
CONSUMABLE
Single-use items that can be purchased multiple times.
Examples:
- Health potions
- Energy refills
- Booster packs
- Consumable power-ups
NON_CONSUMABLE
One-time purchases that unlock permanent features.
Examples:
- Premium features
- Character unlocks
- Level packs
- Ad removal
SUBSCRIPTION
Recurring purchases that provide benefits for a period.
Examples:
- Premium membership
- VIP access
- Season passes
- Monthly content subscriptions
VIRTUAL_CURRENCY
In-game currency packs with optional bonus percentages.
Examples:
- Gold coin packs
- Gem bundles
- Credit packages
- Premium currency
Create Product
Create a new in-app product with custom configuration.
Endpoint
POST /products
Request Body
{
appId: string; // Required: Application ID
developerId: string; // Required: Developer ID
productReference?: string; // Unique reference code
name: string; // Required: Product name
description: string; // Required: Product description
shortDescription?: string; // Brief description for listings
productType: string; // Required: CONSUMABLE, NON_CONSUMABLE, SUBSCRIPTION, VIRTUAL_CURRENCY
category: string; // Required: Category (e.g., 'Currency', 'Power-ups')
subCategory?: string; // Optional subcategory
pricing: { // Required: Pricing configuration
amount: number; // Price amount
currency: string; // Currency code (USD, EUR, etc.)
displayPrice: string; // Formatted price for display
compareAtPrice?: number; // Original price for discounts
taxInclusive?: boolean; // Whether tax is included
};
isActive?: boolean; // Default: true
isVisible?: boolean; // Default: true
availableFrom?: string; // ISO date when product becomes available
availableUntil?: string; // ISO date when product expires
tags?: string[]; // Tags for filtering
metadata?: object; // Custom metadata
subscriptionConfig?: { // For subscription products
interval: string; // DAY, WEEK, MONTH, YEAR
intervalCount: number; // Number of intervals
trialPeriodDays?: number; // Free trial days
gracePeriodDays?: number; // Grace period after failed payment
maxRetries?: number; // Max payment retry attempts
};
virtualCurrency?: { // For virtual currency products
currencyToPay: number; // Cost in virtual currency
currencyToReceive: number; // Amount received
bonusPercentage?: number; // Bonus percentage
};
}
Response
{
productId: string;
productReference: string;
appId: string;
developerId: string;
name: string;
description: string;
productType: string;
category: string;
pricing: object;
isActive: boolean;
isVisible: boolean;
createdAt: string;
updatedAt: string;
}
Example: Consumable Product
import { ProductsApi } from "@getjar-iap/sdk";
const productsApi = new ProductsApi(configuration);
const product = await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
productReference: "GOLD_PACK_100",
name: "100 Gold Coins",
description: "A pack of 100 gold coins for in-game purchases",
shortDescription: "100 gold coins",
productType: "CONSUMABLE",
category: "Currency",
subCategory: "Gold Packs",
pricing: {
amount: 4.99,
currency: "USD",
displayPrice: "$4.99",
compareAtPrice: 9.99,
taxInclusive: true,
},
isActive: true,
isVisible: true,
tags: ["popular", "best-value"],
},
});
console.log("Product ID:", product.data.productId);
Example: Subscription Product
const subscription = await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
name: "Premium Monthly Subscription",
description: "Get premium features and exclusive content",
productType: "SUBSCRIPTION",
category: "Subscriptions",
pricing: {
amount: 9.99,
currency: "USD",
displayPrice: "$9.99/month",
},
subscriptionConfig: {
interval: "MONTH",
intervalCount: 1,
trialPeriodDays: 7,
gracePeriodDays: 3,
maxRetries: 3,
},
},
});
console.log("Subscription created:", subscription.data);
Example: Virtual Currency Product
const virtualCurrency = await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
name: "Mega Gem Pack",
description: "1000 gems with 20% bonus!",
productType: "VIRTUAL_CURRENCY",
category: "Currency",
pricing: {
amount: 19.99,
currency: "USD",
displayPrice: "$19.99",
},
virtualCurrency: {
currencyToPay: 1999,
currencyToReceive: 1000,
bonusPercentage: 20,
},
},
});
console.log("Virtual currency pack created:", virtualCurrency.data);
Response Codes
| Code | Description |
|---|---|
| 201 | Product created successfully |
| 400 | Invalid product data |
| 401 | Unauthorized |
| 404 | App or developer does not exist |
Update Product
Update an existing product's details including pricing, description, or availability.
Endpoint
PUT /products/:productId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Request Body
{
name?: string;
description?: string;
shortDescription?: string;
pricing?: {
amount?: number;
currency?: string;
displayPrice?: string;
compareAtPrice?: number;
};
category?: string;
subCategory?: string;
isActive?: boolean;
isVisible?: boolean;
availableFrom?: string;
availableUntil?: string;
tags?: string[];
metadata?: object;
subscriptionConfig?: object;
virtualCurrency?: object;
}
Example
const updated = await productsApi.updateProduct({
productId: "prod_123",
updateProductDto: {
name: "100 Gold Coins - Limited Edition",
description: "Updated with bonus content!",
pricing: {
amount: 3.99,
currency: "USD",
displayPrice: "$3.99",
compareAtPrice: 4.99,
},
tags: ["limited-time", "sale"],
},
});
console.log("Updated:", updated.data.name);
Response Codes
| Code | Description |
|---|---|
| 200 | Product updated successfully |
| 400 | Invalid update data |
| 401 | Unauthorized |
| 404 | Product does not exist |
Toggle Product Visibility
Control whether a product is visible in the store. Hidden products can still be purchased if users have the direct link.
Endpoint
PUT /products/:productId/visibility
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Request Body
{
isVisible: boolean; // Required
}
Example
// Hide product
await productsApi.toggleProductVisibility({
productId: "prod_123",
toggleProductVisibilityRequest: {
isVisible: false,
},
});
console.log("Product hidden from store");
// Show product
await productsApi.toggleProductVisibility({
productId: "prod_123",
toggleProductVisibilityRequest: {
isVisible: true,
},
});
console.log("Product visible in store");
Response Codes
| Code | Description |
|---|---|
| 200 | Visibility updated successfully |
| 401 | Unauthorized |
| 404 | Product does not exist |
Activate Product
Activate a product to make it available for purchase. Only active products can be sold.
Endpoint
POST /products/:productId/activate
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Example
await productsApi.activateProduct({
productId: "prod_123",
});
console.log("Product activated");
Response Codes
| Code | Description |
|---|---|
| 200 | Product activated successfully |
| 401 | Unauthorized |
| 404 | Product does not exist |
Deactivate Product
Deactivate a product to prevent new purchases. Existing subscriptions will continue until expiration.
Endpoint
POST /products/:productId/deactivate
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Example
await productsApi.deactivateProduct({
productId: "prod_123",
});
console.log("Product deactivated");
Response Codes
| Code | Description |
|---|---|
| 200 | Product deactivated successfully |
| 401 | Unauthorized |
| 404 | Product does not exist |
Upload Product Image
Upload or replace the product image. Images are stored in S3 and automatically optimized.
Endpoint
POST /products/image/upload/:productId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Request Body
multipart/form-data
Form Fields:
file: Image file (PNG, JPG, JPEG, WEBP)
Response
{
success: boolean;
key: string; // S3 storage key
url: string; // Public URL
uploadedAt: string;
}
Example
// Browser example
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
const result = await productsApi.uploadProductImage({
productId: "prod_123",
file: file,
});
console.log("Image URL:", result.data.url);
Response Codes
| Code | Description |
|---|---|
| 201 | Image uploaded successfully |
| 400 | Invalid file type or size |
| 401 | Unauthorized |
| 404 | Product does not exist |
Delete Product Image
Remove the product image from S3 storage and clear the image references.
Endpoint
DELETE /products/image/delete/:productId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Example
await productsApi.deleteProductImage({
productId: "prod_123",
});
console.log("Image deleted");
Response Codes
| Code | Description |
|---|---|
| 200 | Image deleted successfully |
| 401 | Unauthorized |
| 404 | Product does not exist |
Get Product by ID
Retrieve detailed information about a specific product. This endpoint is public.
Endpoint
GET /products/:productId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Response
{
productId: string;
productReference: string;
appId: string;
developerId: string;
name: string;
description: string;
shortDescription: string;
productType: string;
category: string;
subCategory: string;
isActive: boolean;
isVisible: boolean;
availableFrom: string | null;
availableUntil: string | null;
pricing: {
amount: number;
currency: string;
displayPrice: string;
compareAtPrice: number | null;
taxInclusive: boolean;
};
imageUrl: string | null;
imageKey: string | null;
subscriptionConfig: {
interval: string;
intervalCount: number;
trialPeriodDays: number;
gracePeriodDays: number;
maxRetries: number;
} | null;
virtualCurrency: {
currencyToPay: number;
currencyToReceive: number;
bonusPercentage: number;
} | null;
stats: {
totalSales: number;
totalRevenue: number;
averageRating: number;
reviewCount: number;
lastPurchasedAt: string;
} | null;
tags: string[];
metadata: object;
createdAt: string;
updatedAt: string;
}
Example
const product = await productsApi.getProductById({
productId: "prod_123",
});
console.log("Name:", product.data.name);
console.log("Price:", product.data.pricing.displayPrice);
console.log("Type:", product.data.productType);
console.log("Total Sales:", product.data.stats?.totalSales || 0);
Response Codes
| Code | Description |
|---|---|
| 200 | Product retrieved |
| 404 | Product does not exist |
Get App Products
Retrieve a paginated list of products for a specific app with optional filters. This endpoint is public.
Endpoint
GET /products/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) |
| productType | string | No | Filter by product type |
| category | string | No | Filter by category |
| isActive | boolean | No | Filter by active status |
| isVisible | boolean | No | Filter by visibility status |
Response
{
items: Array<{
productId: string;
productReference: string;
name: string;
description: string;
productType: string;
category: string;
pricing: {
amount: number;
currency: string;
displayPrice: string;
};
imageUrl: string | null;
isActive: boolean;
isVisible: boolean;
}>;
pagination: {
total: number;
page: number;
limit: number;
totalPages: number;
hasNextPage: boolean;
hasPreviousPage: boolean;
}
}
Example
// Get all products
const products = await productsApi.getAppProducts({
appId: "app_123",
page: 1,
limit: 20,
});
console.log("Total products:", products.data.pagination.total);
// Get filtered products
const consumables = await productsApi.getAppProducts({
appId: "app_123",
productType: "CONSUMABLE",
category: "Currency",
isActive: true,
isVisible: true,
page: 1,
limit: 50,
});
console.log("Consumable products:", consumables.data.items);
Response Codes
| Code | Description |
|---|---|
| 200 | Products retrieved |
| 404 | App does not exist |
Get Developer Products
Retrieve all products created by a specific developer across all their apps.
Endpoint
GET /products/developer/:developerId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| developerId | string | Yes | The developer identifier |
| page | number | No | Page number (default: 1) |
| limit | number | No | Items per page (default: 20) |
Example
const developerProducts = await productsApi.getDeveloperProducts({
developerId: "dev_123",
page: 1,
limit: 20,
});
console.log("Total products:", developerProducts.data.pagination.total);
developerProducts.data.items.forEach((product) => {
console.log(`${product.name} (${product.appId})`);
});
Response Codes
| Code | Description |
|---|---|
| 200 | Products retrieved |
| 401 | Unauthorized |
| 404 | Developer does not exist |
Get Products by Category
Retrieve products filtered by category across all apps. This endpoint is public.
Endpoint
GET /products/category/:category
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| category | string | Yes | Category name |
| page | number | No | Page number (default: 1) |
| limit | number | No | Items per page (default: 20) |
Example
const currencyProducts = await productsApi.getProductsByCategory({
category: "Currency",
page: 1,
limit: 50,
});
console.log("Currency products:", currencyProducts.data.items);
Response Codes
| Code | Description |
|---|---|
| 200 | Products retrieved |
Get Product Analytics
Retrieve comprehensive analytics and performance metrics for a product including sales, revenue, and ratings.
Endpoint
GET /products/:productId/analytics
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Response
{
totalSales: number;
totalRevenue: number;
averageRating: number | null;
reviewCount: number;
lastPurchasedAt: string;
conversionMetrics: {
isPopular: boolean;
performanceRating: "LOW" | "MEDIUM" | "HIGH";
}
revenueByPeriod: {
today: number;
thisWeek: number;
thisMonth: number;
}
}
Example
const analytics = await productsApi.getProductAnalytics({
productId: "prod_123",
});
console.log("Total Sales:", analytics.data.totalSales);
console.log("Total Revenue:", `$${analytics.data.totalRevenue.toFixed(2)}`);
console.log("Average Rating:", analytics.data.averageRating);
console.log("Performance:", analytics.data.conversionMetrics.performanceRating);
console.log(
"This Month:",
`$${analytics.data.revenueByPeriod.thisMonth.toFixed(2)}`
);
Response Codes
| Code | Description |
|---|---|
| 200 | Analytics retrieved |
| 401 | Unauthorized |
| 404 | Product does not exist |
Delete Product
Permanently delete a product. This will not affect existing user purchases or subscriptions.
Endpoint
DELETE /products/:productId
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| productId | string | Yes | The unique product identifier |
Example
await productsApi.deleteProduct({
productId: "prod_123",
});
console.log("Product deleted successfully");
Response Codes
| Code | Description |
|---|---|
| 200 | Product deleted successfully |
| 401 | Unauthorized |
| 404 | Product does not exist |
Complete Example
Here's a complete workflow for setting up products:
import { Configuration, ProductsApi } from "@getjar-iap/sdk";
const configuration = new Configuration({
basePath: "https://sdk.getjar.com",
apiKey: "your-api-key",
});
const productsApi = new ProductsApi(configuration);
const appId = "app_123";
const developerId = "dev_123";
async function setupProducts() {
console.log("🏪 Setting up product catalog...\n");
// 1. Create consumable products
const healthPotion = await productsApi.createProduct({
createProductDto: {
appId,
developerId,
productReference: "HEALTH_POTION",
name: "Health Potion",
description: "Restore 50 HP instantly",
productType: "CONSUMABLE",
category: "Consumables",
subCategory: "Potions",
pricing: {
amount: 0.99,
currency: "USD",
displayPrice: "$0.99",
},
tags: ["consumable", "health"],
},
});
console.log("✓ Created:", healthPotion.data.name);
// 2. Create virtual currency packs
const currencyPacks = [
{ amount: 100, price: 0.99, bonus: 0 },
{ amount: 500, price: 4.99, bonus: 10 },
{ amount: 1000, price: 9.99, bonus: 20 },
{ amount: 5000, price: 49.99, bonus: 50 },
];
for (const pack of currencyPacks) {
const product = await productsApi.createProduct({
createProductDto: {
appId,
developerId,
productReference: `GOLD_PACK_${pack.amount}`,
name: `${pack.amount} Gold Coins${
pack.bonus > 0 ? ` (+${pack.bonus}% Bonus)` : ""
}`,
description: `A pack of ${pack.amount} gold coins for in-game purchases`,
productType: "VIRTUAL_CURRENCY",
category: "Currency",
subCategory: "Gold Packs",
pricing: {
amount: pack.price,
currency: "USD",
displayPrice: `$${pack.price}`,
},
virtualCurrency: {
currencyToPay: Math.round(pack.price * 100),
currencyToReceive: pack.amount,
bonusPercentage: pack.bonus,
},
tags: pack.bonus > 0 ? ["popular", "best-value"] : ["starter"],
},
});
console.log("✓ Created:", product.data.name);
}
// 3. Create non-consumable products
const premiumFeature = await productsApi.createProduct({
createProductDto: {
appId,
developerId,
productReference: "REMOVE_ADS",
name: "Remove Ads Forever",
description: "Enjoy an ad-free experience permanently",
productType: "NON_CONSUMABLE",
category: "Premium",
subCategory: "Features",
pricing: {
amount: 4.99,
currency: "USD",
displayPrice: "$4.99",
},
tags: ["premium", "no-ads"],
},
});
console.log("✓ Created:", premiumFeature.data.name);
// 4. Create subscription
const subscription = await productsApi.createProduct({
createProductDto: {
appId,
developerId,
productReference: "PREMIUM_MONTHLY",
name: "Premium Membership",
description: "Get exclusive content, bonuses, and no ads",
productType: "SUBSCRIPTION",
category: "Subscriptions",
pricing: {
amount: 9.99,
currency: "USD",
displayPrice: "$9.99/month",
},
subscriptionConfig: {
interval: "MONTH",
intervalCount: 1,
trialPeriodDays: 7,
gracePeriodDays: 3,
maxRetries: 3,
},
tags: ["subscription", "premium"],
},
});
console.log("✓ Created:", subscription.data.name);
// 5. Get all products
const allProducts = await productsApi.getAppProducts({
appId,
page: 1,
limit: 100,
});
console.log("\n📦 Product Catalog:");
console.log(`Total products: ${allProducts.data.pagination.total}`);
// Group by type
const byType = allProducts.data.items.reduce((acc, product) => {
acc[product.productType] = (acc[product.productType] || 0) + 1;
return acc;
}, {} as Record<string, number>);
console.log("\nBy Type:");
Object.entries(byType).forEach(([type, count]) => {
console.log(` ${type}: ${count}`);
});
// 6. Get analytics for a product
const analytics = await productsApi.getProductAnalytics({
productId: healthPotion.data.productId,
});
console.log("\n📊 Analytics for", healthPotion.data.name);
console.log(" Total Sales:", analytics.data.totalSales);
console.log(" Total Revenue:", `$${analytics.data.totalRevenue.toFixed(2)}`);
return allProducts;
}
// Run the setup
setupProducts()
.then(() => console.log("\n✅ Product setup complete!"))
.catch((error) => console.error("❌ Error:", error));
Product Catalog Management
Creating a Store with Categories
async function createGameStore() {
const categories = {
Currency: [
{ name: "Starter Pack", amount: 100, price: 0.99 },
{ name: "Popular Pack", amount: 500, price: 4.99, bonus: 10 },
{ name: "Best Value", amount: 1000, price: 9.99, bonus: 20 },
{ name: "Mega Pack", amount: 5000, price: 49.99, bonus: 50 },
],
Consumables: [
{ name: "Health Potion", price: 0.99, description: "Restore 50 HP" },
{ name: "Mana Potion", price: 0.99, description: "Restore 50 MP" },
{
name: "Experience Boost",
price: 1.99,
description: "2x XP for 1 hour",
},
],
Premium: [
{ name: "Remove Ads", price: 4.99, description: "No ads forever" },
{
name: "VIP Status",
price: 14.99,
description: "Lifetime VIP benefits",
},
],
};
for (const [category, products] of Object.entries(categories)) {
for (const product of products) {
await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
name: product.name,
description: product.description || `${product.name} pack`,
productType:
category === "Currency"
? "VIRTUAL_CURRENCY"
: category === "Premium"
? "NON_CONSUMABLE"
: "CONSUMABLE",
category,
pricing: {
amount: product.price,
currency: "USD",
displayPrice: `$${product.price}`,
},
...(category === "Currency" && {
virtualCurrency: {
currencyToPay: Math.round(product.price * 100),
currencyToReceive: product.amount,
bonusPercentage: product.bonus || 0,
},
}),
},
});
}
}
}
Managing Product Lifecycle
async function manageProductLifecycle(productId: string) {
// Launch product
await productsApi.activateProduct({ productId });
await productsApi.toggleProductVisibility({
productId,
toggleProductVisibilityRequest: { isVisible: true },
});
console.log("Product launched");
// Run a sale
await productsApi.updateProduct({
productId,
updateProductDto: {
pricing: {
amount: 2.99,
displayPrice: "$2.99",
compareAtPrice: 4.99,
},
tags: ["on-sale", "limited-time"],
},
});
console.log("Sale started");
// End sale
await productsApi.updateProduct({
productId,
updateProductDto: {
pricing: {
amount: 4.99,
displayPrice: "$4.99",
compareAtPrice: null,
},
tags: [],
},
});
console.log("Sale ended");
// Retire product
await productsApi.deactivateProduct({ productId });
await productsApi.toggleProductVisibility({
productId,
toggleProductVisibilityRequest: { isVisible: false },
});
console.log("Product retired");
}
Seasonal Products
async function createSeasonalProduct() {
const now = new Date();
const oneMonthLater = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
const seasonal = await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
name: "Holiday Special Pack",
description: "Limited time holiday bundle!",
productType: "CONSUMABLE",
category: "Limited Time",
pricing: {
amount: 9.99,
currency: "USD",
displayPrice: "$9.99",
compareAtPrice: 19.99,
},
availableFrom: now.toISOString(),
availableUntil: oneMonthLater.toISOString(),
tags: ["limited-time", "seasonal", "holiday"],
},
});
console.log("Seasonal product created:", seasonal.data.name);
console.log("Available until:", seasonal.data.availableUntil);
}
Best Practices
Pricing Strategy
-
Tiered Pricing: Offer multiple price points
const tiers = [
{ amount: 100, price: 0.99, value: 0.99 },
{ amount: 500, price: 4.99, value: 1.0 }, // 5% better value
{ amount: 1000, price: 9.99, value: 1.01 }, // 10% better value
{ amount: 5000, price: 49.99, value: 1.0 }, // 50% better value
]; -
Discount Display: Use
compareAtPricefor salespricing: {
amount: 3.99,
displayPrice: "$3.99",
compareAtPrice: 4.99 // Shows original price
} -
Currency Localization: Support multiple currencies
const prices = {
USD: { amount: 4.99, display: "$4.99" },
EUR: { amount: 4.49, display: "€4.49" },
GBP: { amount: 3.99, display: "£3.99" },
};
Product Organization
-
Use References: Always set meaningful
productReferencecodesproductReference: "GOLD_PACK_500"; // Clear and descriptive -
Categorize Effectively: Use clear categories and subcategories
category: "Currency",
subCategory: "Gold Packs" -
Tag Appropriately: Use tags for filtering and discovery
tags: ["popular", "best-value", "limited-time"]; -
Provide Clear Descriptions: Help users understand the value
name: "500 Gold Coins (+10% Bonus)",
description: "Get 500 gold coins plus 50 bonus coins",
shortDescription: "550 gold coins total"
Subscription Management
-
Offer Trials: Encourage subscriptions with free trials
subscriptionConfig: {
interval: "MONTH",
intervalCount: 1,
trialPeriodDays: 7 // 7-day free trial
} -
Grace Periods: Prevent accidental cancellations
subscriptionConfig: {
gracePeriodDays: 3,
maxRetries: 3
} -
Clear Pricing: Show recurring costs clearly
displayPrice: "$9.99/month"; // Not just "$9.99"
Image Management
-
Optimize Images: Use appropriate sizes and formats
- Recommended: 512x512px PNG or WEBP
- Max file size: 2MB
- Use transparent backgrounds for icons
-
Update Images: Keep product images current
// Replace old image
await uploadProductImage({ productId, file }); -
Clean Up: Remove unused images
await deleteProductImage({ productId });
Analytics & Optimization
-
Monitor Performance: Track sales and revenue
const analytics = await getProductAnalytics({ productId });
if (analytics.data.conversionMetrics.performanceRating === "LOW") {
// Consider adjusting pricing or visibility
} -
Test Pricing: A/B test different price points
// Version A: $4.99
// Version B: $3.99
// Compare analytics after 1 week -
Identify Best Sellers: Focus on what works
const products = await getAppProducts({ appId, limit: 100 });
const sorted = products.data.items.sort(
(a, b) => (b.stats?.totalSales || 0) - (a.stats?.totalSales || 0)
);
console.log("Top products:", sorted.slice(0, 5));
Common Patterns
Starter Pack Offer
async function createStarterPack() {
const starter = await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
name: "New Player Starter Pack",
description: "Everything you need to get started!",
productType: "CONSUMABLE",
category: "Bundles",
pricing: {
amount: 0.99,
currency: "USD",
displayPrice: "$0.99",
compareAtPrice: 4.99, // Show 80% discount
},
tags: ["starter", "limited-time", "best-value"],
metadata: {
isOneTimeOffer: true,
targetAudience: "new_players",
},
},
});
return starter;
}
Flash Sale Implementation
async function runFlashSale(productId: string, discountPercent: number) {
const product = await productsApi.getProductById({ productId });
const originalPrice = product.data.pricing.amount;
const salePrice = originalPrice * (1 - discountPercent / 100);
await productsApi.updateProduct({
productId,
updateProductDto: {
pricing: {
amount: salePrice,
currency: product.data.pricing.currency,
displayPrice: `$${salePrice.toFixed(2)}`,
compareAtPrice: originalPrice,
},
tags: [...(product.data.tags || []), "flash-sale"],
},
});
console.log(`Flash sale started: ${discountPercent}% off`);
// Revert after 24 hours
setTimeout(async () => {
await productsApi.updateProduct({
productId,
updateProductDto: {
pricing: {
amount: originalPrice,
currency: product.data.pricing.currency,
displayPrice: product.data.pricing.displayPrice,
compareAtPrice: null,
},
tags: product.data.tags?.filter((tag) => tag !== "flash-sale"),
},
});
console.log("Flash sale ended");
}, 24 * 60 * 60 * 1000);
}
Bundle Products
async function createBundle() {
const bundle = await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
name: "Ultimate Power Bundle",
description: "5 Health Potions + 5 Mana Potions + XP Boost",
productType: "CONSUMABLE",
category: "Bundles",
pricing: {
amount: 9.99,
currency: "USD",
displayPrice: "$9.99",
compareAtPrice: 14.99,
},
metadata: {
contents: [
{ item: "HEALTH_POTION", quantity: 5 },
{ item: "MANA_POTION", quantity: 5 },
{ item: "XP_BOOST_1H", quantity: 1 },
],
},
tags: ["bundle", "value-pack"],
},
});
return bundle;
}
Error Handling
async function safeProductOperation() {
try {
const product = await productsApi.createProduct({
createProductDto: {
/* ... */
},
});
return {
success: true,
data: product.data,
};
} catch (error) {
if (error.response) {
switch (error.response.status) {
case 400:
console.error("Invalid product data:", error.response.data.message);
break;
case 401:
console.error("Authentication required");
break;
case 404:
console.error("App or developer not found");
break;
default:
console.error("Unexpected error:", error.response.status);
}
}
return {
success: false,
error: error.message,
};
}
}
Migration Guide
From Manual Product Management
// Old system: Manual product tracking
const oldProducts = [
{ id: "old_1", name: "Gold Pack", price: 4.99 },
{ id: "old_2", name: "Health Potion", price: 0.99 },
];
// New system: Migrate to GetJar
for (const oldProduct of oldProducts) {
await productsApi.createProduct({
createProductDto: {
appId: "app_123",
developerId: "dev_123",
productReference: oldProduct.id,
name: oldProduct.name,
description: `Migrated from old system`,
productType: "CONSUMABLE",
category: "Legacy",
pricing: {
amount: oldProduct.price,
currency: "USD",
displayPrice: `$${oldProduct.price}`,
},
metadata: {
migratedFrom: "legacy_system",
originalId: oldProduct.id,
},
},
});
}
Support
For additional help or questions:
- Documentation: https://docs.getjar.com
- API Reference: https://sdk.getjar.com/api/docs
- Support: support@getjar.com