TL;DR
The Magento 2 (Adobe Commerce) API enables developers to integrate with e-commerce stores programmatically. It uses REST, SOAP, and GraphQL endpoints with OAuth 1.0a and token-based authentication, providing access to products, orders, customers, inventory, and more, with configurable rate limits. This guide covers authentication setup, CRUD operations, webhooks, custom endpoints, and production integration strategies.
Introduction
Adobe Commerce (Magento) powers over 250,000 e-commerce stores with $155+ billion in annual gross merchandise value. For developers building e-commerce integrations, ERP connectors, or mobile apps, Magento API integration isn’t optional—it’s essential for reaching this massive merchant base.
Here’s the reality: merchants managing multiple sales channels lose 20-30 hours weekly on manual data entry between Magento and other systems. A solid Magento API integration automates product synchronization, order processing, inventory updates, and customer data management.
This guide walks through the complete Magento 2 API integration process. You’ll learn OAuth 1.0a and token authentication, REST/SOAP/GraphQL endpoints, product and order management, webhooks, custom API development, and production deployment strategies. By the end, you’ll have a production-ready Magento integration.
What Is the Magento 2 API?
Magento 2 provides three API types for accessing e-commerce data:
- REST API: JSON-based for web and mobile applications
- SOAP API: XML-based for enterprise integrations
- GraphQL: Query-based for efficient frontend applications
The API handles:
- Products, categories, and inventory
- Orders, invoices, and shipments
- Customers and customer groups
- Shopping cart and checkout
- Promotions and pricing rules
- CMS pages and blocks
- Store configuration
Key Features
| Feature | Description |
|---|---|
| Multiple Protocols | REST, SOAP, GraphQL |
| OAuth 1.0a | Secure third-party access |
| Token Auth | Admin and integration tokens |
| Webhooks | Async operations via queues |
| Rate Limiting | Configurable per installation |
| Custom Endpoints | Extend with custom APIs |
| Multi-Store | Single API, multiple storeviews |
API Comparison
| API Type | Protocol | Use Case |
|---|---|---|
| REST | JSON | Mobile apps, integrations |
| SOAP | XML | Enterprise systems (SAP, Oracle) |
| GraphQL | GraphQL | Storefront, PWA |
Magento Versions
| Version | Status | End of Support |
|---|---|---|
| Magento 2.4.x | Current | Active |
| Adobe Commerce 2.4.x | Current | Active |
| Magento 1.x | EOL | June 2020 (Do not use) |
Getting Started: Authentication Setup
Step 1: Create Admin Account or Integration
Before accessing the API:
- Log in to Magento Admin Panel
- Navigate to System > Permissions > All Users
- Create admin user (for admin token) OR
- Navigate to System > Extensions > Integrations
- Create new integration (for OAuth)
Step 2: Choose Authentication Method
| Method | Best For | Token Lifetime |
|---|---|---|
| Admin Token | Internal integrations | Configurable (default: 4 hours) |
| Integration Token | Third-party apps | Until revoked |
| OAuth 1.0a | Public marketplace apps | Until revoked |
| Customer Token | Customer-facing apps | Configurable |
Step 3: Get Admin Token (Simplest Method)
Generate admin token for internal integrations:
const MAGENTO_BASE_URL = process.env.MAGENTO_BASE_URL;
const MAGENTO_ADMIN_USERNAME = process.env.MAGENTO_ADMIN_USERNAME;
const MAGENTO_ADMIN_PASSWORD = process.env.MAGENTO_ADMIN_PASSWORD;
const getAdminToken = async () => {
const response = await fetch(`${MAGENTO_BASE_URL}/rest/V1/integration/admin/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: MAGENTO_ADMIN_USERNAME,
password: MAGENTO_ADMIN_PASSWORD
})
});
if (!response.ok) {
throw new Error('Invalid admin credentials');
}
// Response is a plain string (the token), not JSON
const token = await response.text();
return token;
};
// Usage
const token = await getAdminToken();
console.log(`Admin token: ${token}`);
// Store securely - use for subsequent API calls
Security note: Store tokens securely:
# .env file
MAGENTO_BASE_URL="https://store.example.com"
MAGENTO_ADMIN_USERNAME="api_user"
MAGENTO_ADMIN_PASSWORD="secure_password_here"
MAGENTO_ACCESS_TOKEN="obtained_via_auth"
Step 4: Create Integration (Recommended for Third-Party)
Create integration via Admin Panel:
Go to System > Extensions > Integrations
Click Add New Integration
Fill in details:
- Name: “My Integration”
- Email: your-email@example.com
- Callback URL: (for OAuth)
- Identity Link URL: (for OAuth)
Set API Permissions:
- Resources: Select needed permissions
- Recommended: Products, Orders, Customers, Inventory
Click Save
Click Activate on the new integration
Copy the Access Token and Token Secret
Step 5: Get Customer Token
For customer-facing applications:
const getCustomerToken = async (email, password) => {
const response = await fetch(`${MAGENTO_BASE_URL}/rest/V1/integration/customer/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: email,
password: password
})
});
if (!response.ok) {
throw new Error('Invalid customer credentials');
}
const token = await response.text();
return token;
};
// Usage
const customerToken = await getCustomerToken('customer@example.com', 'password123');
Step 6: Make Authenticated API Calls
Create reusable API client:
const magentoRequest = async (endpoint, options = {}) => {
const token = await getAdminToken(); // Or retrieve stored token
const response = await fetch(`${MAGENTO_BASE_URL}/rest${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Magento API Error: ${error.message}`);
}
return response.json();
};
// Usage
const products = await magentoRequest('/V1/products');
console.log(`Found ${products.items.length} products`);
Product Management
Getting Products
Fetch products with filtering:
const getProducts = async (filters = {}) => {
const params = new URLSearchParams();
// Build search criteria
if (filters.search) {
params.append('searchCriteria[filterGroups][0][filters][0][field]', 'sku');
params.append('searchCriteria[filterGroups][0][filters][0][value]', `%${filters.search}%`);
params.append('searchCriteria[filterGroups][0][filters][0][conditionType]', 'like');
}
if (filters.priceFrom) {
params.append('searchCriteria[filterGroups][1][filters][0][field]', 'price');
params.append('searchCriteria[filterGroups][1][filters][0][value]', filters.priceFrom);
params.append('searchCriteria[filterGroups][1][filters][0][conditionType]', 'gteq');
}
params.append('searchCriteria[pageSize]', filters.limit || 20);
params.append('searchCriteria[currentPage]', filters.page || 1);
const response = await magentoRequest(`/V1/products?${params.toString()}`);
return response;
};
// Usage
const products = await getProducts({ search: 'shirt', priceFrom: 20, limit: 50 });
products.items.forEach(product => {
console.log(`${product.sku}: ${product.name} - $${product.price}`);
});
Getting Single Product
Fetch product by SKU:
const getProduct = async (sku) => {
const response = await magentoRequest(`/V1/products/${sku}`);
return response;
};
// Usage
const product = await getProduct('TSHIRT-001');
console.log(`Name: ${product.name}`);
console.log(`Price: $${product.price}`);
console.log(`Stock: ${product.extension_attributes?.stock_item?.qty}`);
Creating a Product
Create simple product:
const createProduct = async (productData) => {
const product = {
product: {
sku: productData.sku,
name: productData.name,
attribute_set_id: productData.attributeSetId || 4, // Default set
type_id: 'simple',
price: productData.price,
status: productData.status || 1, // 1=enabled, 2=disabled
visibility: productData.visibility || 4, // 4=Catalog & Search
weight: productData.weight || 1,
extension_attributes: {
stock_item: {
qty: productData.qty || 0,
is_in_stock: productData.qty > 0 ? true : false
}
},
custom_attributes: [
{
attribute_code: 'description',
value: productData.description
},
{
attribute_code: 'short_description',
value: productData.shortDescription
},
{
attribute_code: 'color',
value: productData.color
},
{
attribute_code: 'size',
value: productData.size
}
]
}
};
const response = await magentoRequest('/V1/products', {
method: 'POST',
body: JSON.stringify(product)
});
return response;
};
// Usage
const newProduct = await createProduct({
sku: 'TSHIRT-NEW-001',
name: 'Premium Cotton T-Shirt',
price: 29.99,
qty: 100,
description: 'High-quality cotton t-shirt',
shortDescription: 'Premium cotton tee',
color: 'Blue',
size: 'M'
});
console.log(`Product created: ${newProduct.id}`);
Updating a Product
Update product information:
const updateProduct = async (sku, updates) => {
const product = {
product: {
sku: sku,
...updates
}
};
const response = await magentoRequest(`/V1/products/${sku}`, {
method: 'PUT',
body: JSON.stringify(product)
});
return response;
};
// Usage - Update price and stock
await updateProduct('TSHIRT-001', {
price: 24.99,
extension_attributes: {
stock_item: {
qty: 150,
is_in_stock: true
}
}
});
Deleting a Product
Remove product:
const deleteProduct = async (sku) => {
await magentoRequest(`/V1/products/${sku}`, {
method: 'DELETE'
});
console.log(`Product ${sku} deleted`);
};
Product Types
| Type | Description | Use Case |
|---|---|---|
| Simple | Single SKU, no variations | Standard products |
| Configurable | Parent with child variations | Size/color options |
| Grouped | Collection of simple products | Product bundles |
| Virtual | Non-physical products | Services, downloads |
| Bundle | Customizable product bundles | Build-your-own kits |
| Downloadable | Digital products | E-books, software |
Order Management
Getting Orders
Fetch orders with filtering:
const getOrders = async (filters = {}) => {
const params = new URLSearchParams();
if (filters.status) {
params.append('searchCriteria[filterGroups][0][filters][0][field]', 'status');
params.append('searchCriteria[filterGroups][0][filters][0][value]', filters.status);
params.append('searchCriteria[filterGroups][0][filters][0][conditionType]', 'eq');
}
if (filters.dateFrom) {
params.append('searchCriteria[filterGroups][1][filters][0][field]', 'created_at');
params.append('searchCriteria[filterGroups][1][filters][0][value]', filters.dateFrom);
params.append('searchCriteria[filterGroups][1][filters][0][conditionType]', 'gteq');
}
params.append('searchCriteria[pageSize]', filters.limit || 20);
params.append('searchCriteria[currentPage]', filters.page || 1);
const response = await magentoRequest(`/V1/orders?${params.toString()}`);
return response;
};
// Usage - Get pending orders from last 7 days
const orders = await getOrders({
status: 'pending',
dateFrom: '2026-03-18 00:00:00',
limit: 50
});
orders.items.forEach(order => {
console.log(`Order #${order.increment_id}: ${order.customer_email} - $${order.grand_total}`);
});
Getting Single Order
Fetch order by ID:
const getOrder = async (orderId) => {
const response = await magentoRequest(`/V1/orders/${orderId}`);
return response;
};
// Usage
const order = await getOrder(12345);
console.log(`Order #${order.increment_id}`);
console.log(`Status: ${order.status}`);
console.log(`Total: $${order.grand_total}`);
console.log(`Items:`);
order.items.forEach(item => {
console.log(` - ${item.name} x ${item.qty_ordered}`);
});
Order Status Flow
pending → processing → complete
→ canceled
→ on_hold
→ payment_review
Updating Order Status
Change order status:
const updateOrderStatus = async (orderId, newStatus) => {
// Note: Direct status update requires custom endpoint
// Use order management workflow instead:
// For cancel:
await magentoRequest(`/V1/orders/${orderId}/cancel`, {
method: 'POST'
});
// For hold:
await magentoRequest(`/V1/orders/${orderId}/hold`, {
method: 'POST'
});
// For unhold:
await magentoRequest(`/V1/orders/${orderId}/unhold`, {
method: 'POST'
});
};
Creating Invoice
Generate invoice for order:
const createInvoice = async (orderId, items = [], notify = true, appendComment = false, comment = null) => {
const invoice = {
capture: true, // true = capture payment
last: true,
items: items // Array of {order_item_id, qty}
};
if (comment) {
invoice.comment = comment;
invoice.notify_customer = notify ? 1 : 0;
invoice.append_comment = appendComment ? 1 : 0;
}
const response = await magentoRequest(`/V1/order/${orderId}/invoice`, {
method: 'POST',
body: JSON.stringify(invoice)
});
return response;
};
// Usage - Invoice and capture full order
const invoiceId = await createInvoice(12345, [], true, false, 'Thank you for your order!');
console.log(`Invoice created: ${invoiceId}`);
Creating Shipment
Ship order:
const createShipment = async (orderId, items = [], notify = true, appendComment = false, comment = null, tracks = []) => {
const shipment = {
items: items, // Array of {order_item_id, qty}
notify: notify ? 1 : 0,
append_comment: appendComment ? 1 : 0,
comment: comment,
tracks: tracks // Array of {track_number, title, carrier_code}
};
const response = await magentoRequest(`/V1/order/${orderId}/ship`, {
method: 'POST',
body: JSON.stringify(shipment)
});
return response;
};
// Usage - Ship with tracking
const shipmentId = await createShipment(12345, [], true, false, 'Your order has shipped!', [
{
track_number: '1Z999AA10123456784',
title: 'Tracking Number',
carrier_code: 'ups'
}
]);
console.log(`Shipment created: ${shipmentId}`);
Customer Management
Getting Customers
Fetch customers:
const getCustomers = async (filters = {}) => {
const params = new URLSearchParams();
if (filters.email) {
params.append('searchCriteria[filterGroups][0][filters][0][field]', 'email');
params.append('searchCriteria[filterGroups][0][filters][0][value]', filters.email);
params.append('searchCriteria[filterGroups][0][filters][0][conditionType]', 'eq');
}
params.append('searchCriteria[pageSize]', filters.limit || 20);
const response = await magentoRequest(`/V1/customers/search?${params.toString()}`);
return response;
};
// Usage
const customers = await getCustomers({ email: 'customer@example.com' });
customers.items.forEach(customer => {
console.log(`${customer.firstname} ${customer.lastname} - ${customer.email}`);
});
Creating a Customer
Register new customer:
const createCustomer = async (customerData) => {
const customer = {
customer: {
websiteId: customerData.websiteId || 1,
email: customerData.email,
firstname: customerData.firstname,
lastname: customerData.lastname,
middlename: customerData.middlename || '',
gender: customerData.gender || 0,
store_id: customerData.storeId || 0,
extension_attributes: {
is_subscribed: customerData.subscribed || false
}
},
password: customerData.password
};
const response = await magentoRequest('/V1/customers', {
method: 'POST',
body: JSON.stringify(customer)
});
return response;
};
// Usage
const newCustomer = await createCustomer({
email: 'newcustomer@example.com',
firstname: 'John',
lastname: 'Doe',
password: 'SecurePass123!',
subscribed: true
});
console.log(`Customer created: ID ${newCustomer.id}`);
Inventory Management (MSI)
Getting Stock Status
Check product stock:
const getStockStatus = async (sku) => {
const response = await magentoRequest(`/V1/products/${sku}/stockItems/1`);
return response;
};
// Usage
const stock = await getStockStatus('TSHIRT-001');
console.log(`Qty: ${stock.qty}`);
console.log(`In Stock: ${stock.is_in_stock}`);
console.log(`Min Qty: ${stock.min_qty}`);
Updating Stock
Update product quantity:
const updateStock = async (sku, qty, isInStock = null) => {
const stockItem = {
stockItem: {
qty: qty,
is_in_stock: isInStock !== null ? isInStock : qty > 0
}
};
const response = await magentoRequest(`/V1/products/${sku}/stockItems/1`, {
method: 'PUT',
body: JSON.stringify(stockItem)
});
return response;
};
// Usage
await updateStock('TSHIRT-001', 100, true);
Webhooks and Async Operations
Setting Up Webhooks
Magento uses message queues for async notifications:
// Magento doesn't have native webhooks
// Use these approaches instead:
// 1. Poll orders endpoint periodically
const pollNewOrders = async (lastOrderId) => {
const orders = await getOrders({
dateFrom: new Date().toISOString()
});
const newOrders = orders.items.filter(o => o.id > lastOrderId);
return newOrders;
};
// 2. Use Adobe I/O Events (Adobe Commerce only)
// Configure events in Adobe Developer Console
// 3. Create custom webhook module
// See: https://devdocs.magento.com/guides/v2.4/extension-dev-guide/message-queues/message-queues.html
Rate Limiting
Understanding Rate Limits
Magento rate limits are configurable:
- Default: No limit (configure in Admin)
- Recommended: 100-1000 requests/minute
Configure in Admin: Stores > Configuration > Services > Web API > Security
Implementing Rate Limit Handling
const makeRateLimitedRequest = async (endpoint, options = {}, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await magentoRequest(endpoint, options);
return response;
} catch (error) {
if (error.message.includes('429') && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
};
Production Deployment Checklist
Before going live:
- [ ] Use integration tokens (not admin credentials) in production
- [ ] Store tokens securely (encrypted database)
- [ ] Implement rate limiting and request queuing
- [ ] Add comprehensive error handling
- [ ] Set up logging for all API calls
- [ ] Create webhook alternative (polling or Adobe I/O)
- [ ] Test with production data volume
- [ ] Implement retry logic for failed requests
Real-World Use Cases
ERP Integration
A manufacturer syncs inventory:
- Challenge: Manual stock updates between ERP and Magento
- Solution: Bi-directional API sync every 15 minutes
- Result: Real-time inventory, zero overselling
Mobile App
A retailer builds shopping app:
- Challenge: Native mobile experience needed
- Solution: GraphQL API for product browsing, REST for checkout
- Result: 40% mobile conversion increase
Conclusion
The Magento 2 API provides comprehensive e-commerce functionality. Key takeaways:
- REST, SOAP, and GraphQL APIs available
- Token-based authentication for integrations
- Full CRUD for products, orders, customers
- MSI for advanced inventory management
- Rate limits configurable per installation
- Apidog streamlines API testing and team collaboration
FAQ Section
How do I authenticate with Magento API?
Use admin token for internal integrations or create an Integration in System > Extensions for OAuth. Customer token for customer-facing apps.
What is the difference between REST and GraphQL in Magento?
REST provides full CRUD operations. GraphQL is optimized for frontend queries with efficient data fetching.
How do I create a product via API?
POST to /V1/products with product data including SKU, name, price, and stock_item in extension_attributes.
Can I get webhooks for new orders?
Magento doesn’t have native webhooks. Use polling, Adobe I/O Events (Adobe Commerce), or create custom module.
How do I update stock quantities?
PUT to /V1/products/{sku}/stockItems/1 with qty and is_in_stock values.



