Skip to main content

Products & Pricing API

The Products & Pricing API allows you to manage your product catalog and pricing structures.

Product Methods

getProducts

Retrieve a list of all products with optional pagination and filtering.

const { getProducts } = useEasy();

// Get all products
const allProducts = await getProducts({
limit: 50,
offset: 0,
});

// Get specific products by ID
const result = await getProducts({
ids: ["prod_123", "prod_456"],
});

Parameters

  • params (optional)
    • ids (string[], optional): Filter by specific product IDs
    • limit (number): Maximum number of products to return (default: 10, max: 100)
    • offset (number): Number of products to skip for pagination

Returns

ApiResponse<ProductData[]>;

Example

import { useEasy } from "@easylabs/react";
import { useState, useEffect } from "react";

function ProductCatalog() {
const { getProducts } = useEasy();
const [products, setProducts] = useState([]);

useEffect(() => {
const fetchProducts = async () => {
try {
const result = await getProducts({ limit: 50 });
setProducts(result.data);
} catch (error) {
console.error("Failed to fetch products:", error);
}
};

fetchProducts();
}, [getProducts]);

return (
<div className="product-grid">
{products.map((product) => (
<div key={product.id} className="product-card">
<h3>{product.name}</h3>
<p>{product.description}</p>
</div>
))}
</div>
);
}

getProduct

Retrieve a specific product by ID.

const { getProduct } = useEasy();

const result = await getProduct("prod_123");
const product = result.data;

Parameters

  • productId (string, required): The ID of the product to retrieve

Returns

ApiResponse<ProductData>;

createProduct

Create a new product.

const { createProduct } = useEasy();

const result = await createProduct({
name: "Premium Plan",
description: "Access to all premium features",
active: true,
metadata: {
features: ["feature1", "feature2"],
},
});

Parameters

  • params (required)
    • name (string, required): Product name
    • description (string, optional): Product description
    • active (boolean, optional): Whether the product is active (default: true)
    • metadata (object, optional): Additional custom data

Returns

ApiResponse<ProductData>;

Example

import { useEasy } from "@easylabs/react";
import { useState } from "react";

function CreateProductForm() {
const { createProduct } = useEasy();
const [formData, setFormData] = useState({
name: "",
description: "",
active: true,
});

const handleSubmit = async (e) => {
e.preventDefault();

try {
const result = await createProduct(formData);
console.log("Product created:", result.data.id);
} catch (error) {
console.error("Failed to create product:", error);
}
};

return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Product Name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
required
/>
<textarea
placeholder="Description"
value={formData.description}
onChange={(e) =>
setFormData({ ...formData, description: e.target.value })
}
/>
<label>
<input
type="checkbox"
checked={formData.active}
onChange={(e) =>
setFormData({ ...formData, active: e.target.checked })
}
/>
Active
</label>
<button type="submit">Create Product</button>
</form>
);
}

updateProduct

Update an existing product.

const { updateProduct } = useEasy();

const result = await updateProduct("prod_123", {
name: "Updated Product Name",
active: false,
});

Parameters

  • productId (string, required): The ID of the product to update
  • params (required)
    • name (string, optional): New product name
    • description (string, optional): New description
    • active (boolean, optional): New active status
    • metadata (object, optional): Updated metadata

Returns

ApiResponse<ProductData>;

archiveProduct

Archive a product (soft delete).

const { archiveProduct } = useEasy();

const result = await archiveProduct("prod_123");

Parameters

  • productId (string, required): The ID of the product to archive

Returns

ApiResponse<ProductData>;
warning

Archiving a product will also deactivate all associated prices. Active subscriptions will continue, but no new subscriptions can be created with the archived product's prices.


Price Methods

getProductPrices

Retrieve a list of all prices with optional filtering.

const { getProductPrices } = useEasy();

// Get all prices
const allPrices = await getProductPrices({
limit: 50,
offset: 0,
});

// Get specific prices by ID
const result = await getProductPrices({
ids: ["price_123", "price_456"],
});

Parameters

  • params (optional)
    • ids (string[], optional): Filter by specific price IDs
    • limit (number): Maximum number of prices to return
    • offset (number): Number of prices to skip for pagination

Returns

ApiResponse<PriceData[]>;

Example

import { useEasy } from "@easylabs/react";
import { useState, useEffect } from "react";

function PricingOptions() {
const { getProductPrices } = useEasy();
const [prices, setPrices] = useState([]);

useEffect(() => {
const fetchPrices = async () => {
try {
const result = await getProductPrices({ limit: 50 });
setPrices(result.data);
} catch (error) {
console.error("Failed to fetch prices:", error);
}
};

fetchPrices();
}, [getProductPrices]);

return (
<div>
{prices.map((price) => (
<div key={price.id} className="price-option">
<h4>${(price.unit_amount / 100).toFixed(2)}</h4>
{price.recurring && <span>per {price.recurring.interval}</span>}
</div>
))}
</div>
);
}

getProductPrice

Retrieve a specific price by ID.

const { getProductPrice } = useEasy();

const result = await getProductPrice("price_123");
const price = result.data;

Parameters

  • priceId (string, required): The ID of the price to retrieve

Returns

ApiResponse<PriceData>;

createProductPrice

Create a new price for a product.

const { createProductPrice } = useEasy();

const result = await createProductPrice({
product_id: "prod_123",
currency: "USD",
unit_amount: 2999, // $29.99
recurring: {
interval: "month",
interval_count: 1,
},
});

Parameters

  • params (required)
    • product_id (string, required): Product ID
    • currency (string, required): Three-letter ISO currency code
    • unit_amount (number, required): Price in cents
    • recurring (object, optional): Recurring billing configuration
      • interval ('day' | 'week' | 'month' | 'year'): Billing interval
      • interval_count (number): Number of intervals between billings
    • active (boolean, optional): Whether the price is active (default: true)
    • metadata (object, optional): Additional custom data

Returns

ApiResponse<PriceData>;

Example

import { useEasy } from "@easylabs/react";
import { useState } from "react";

function CreatePriceForm({ productId }) {
const { createProductPrice } = useEasy();
const [amount, setAmount] = useState("");
const [interval, setInterval] = useState("month");
const [isRecurring, setIsRecurring] = useState(false);

const handleSubmit = async (e) => {
e.preventDefault();

try {
const priceData = {
product_id: productId,
currency: "USD",
unit_amount: Math.round(parseFloat(amount) * 100),
};

if (isRecurring) {
priceData.recurring = {
interval: interval,
interval_count: 1,
};
}

const result = await createProductPrice(priceData);
console.log("Price created:", result.data.id);
} catch (error) {
console.error("Failed to create price:", error);
}
};

return (
<form onSubmit={handleSubmit}>
<input
type="number"
placeholder="Price (USD)"
value={amount}
onChange={(e) => setAmount(e.target.value)}
step="0.01"
min="0"
required
/>
<label>
<input
type="checkbox"
checked={isRecurring}
onChange={(e) => setIsRecurring(e.target.checked)}
/>
Recurring
</label>
{isRecurring && (
<select value={interval} onChange={(e) => setInterval(e.target.value)}>
<option value="day">Daily</option>
<option value="week">Weekly</option>
<option value="month">Monthly</option>
<option value="year">Yearly</option>
</select>
)}
<button type="submit">Create Price</button>
</form>
);
}

updateProductPrice

Update a price's metadata, description, or active status.

const { updateProductPrice } = useEasy();

const result = await updateProductPrice("price_123", {
active: false,
metadata: {
deprecated: true,
},
});

Parameters

  • priceId (string, required): The ID of the price to update
  • params (required)
    • active (boolean, optional): New active status
    • description (string, optional): New description
    • metadata (object, optional): Updated metadata

Returns

ApiResponse<PriceData>;
info

You cannot change the amount or billing interval of an existing price. To change pricing, create a new price and deactivate the old one.


archiveProductPrice

Archive a price (soft delete).

const { archiveProductPrice } = useEasy();

const result = await archiveProductPrice("price_123");

Parameters

  • priceId (string, required): The ID of the price to archive

Returns

ApiResponse<PriceData>;

Type Definitions

Product

interface Product {
id: string;
name: string;
description?: string;
active: boolean;
metadata?: Record<string, unknown>;
created_at: string;
updated_at: string;
}

Price

interface Price {
id: string;
product_id: string;
active: boolean;
currency: string;
unit_amount: number;
recurring?: {
interval: "day" | "week" | "month" | "year";
interval_count: number;
};
metadata?: Record<string, unknown>;
created_at: string;
updated_at: string;
}

Pricing Patterns

One-Time Payments

await createProductPrice({
product_id: "prod_123",
currency: "USD",
unit_amount: 4999, // $49.99 one-time
});

Monthly Subscription

await createProductPrice({
product_id: "prod_123",
currency: "USD",
unit_amount: 2999, // $29.99/month
recurring: {
interval: "month",
interval_count: 1,
},
});

Annual Subscription

await createProductPrice({
product_id: "prod_123",
currency: "USD",
unit_amount: 29999, // $299.99/year
recurring: {
interval: "year",
interval_count: 1,
},
});

Quarterly Billing

await createProductPrice({
product_id: "prod_123",
currency: "USD",
unit_amount: 7999, // $79.99 every 3 months
recurring: {
interval: "month",
interval_count: 3,
},
});

Best Practices

  1. Create multiple prices: Offer monthly/annual options for subscriptions
  2. Use descriptive metadata: Track pricing tiers and features
  3. Don't delete prices: Archive them instead to preserve history
  4. Version your pricing: Create new prices for price changes
  5. Test with cents: Always test pricing calculations with cent amounts

Next Steps