TL;DR
The Magento 2 (Adobe Commerce) API lets you programmatically integrate with e-commerce stores using REST, SOAP, and GraphQL. Authentication is via OAuth 1.0a and token-based methods. You get access to products, orders, customers, inventory, and more—with configurable rate limits. This guide covers authentication, CRUD, webhooks, custom endpoints, and deployment strategies.
Introduction
Adobe Commerce (Magento) powers over 250,000 e-commerce stores and $155B+ in annual GMV. API integration is essential for developers building integrations, ERP connectors, or mobile apps.
Manual Magento data entry across sales channels can cost merchants 20–30 hours per week. A robust Magento API integration automates product sync, order processing, inventory updates, and customer management.
This guide is a practical walk-through of Magento 2 API integration: authentication (OAuth/token), REST/SOAP/GraphQL endpoints, product/order management, webhooks, custom APIs, and deployment. Follow these steps for a production-ready integration.
💡 Tip: Apidog simplifies API integration testing—test endpoints, validate auth flows, inspect responses, mock APIs, and share scenarios with your team.
What Is the Magento 2 API?
Magento 2 gives you three API types:
- REST API: JSON-based for web/mobile
- SOAP API: XML-based for enterprise systems
- GraphQL: Flexible queries for frontend/PWA
API coverage includes:
- Products, categories, inventory
- Orders, invoices, shipments
- Customers, groups
- Cart, checkout
- Promotions, pricing rules
- CMS content
- Store config
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 (SAP, Oracle, etc.) |
| 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
- Log in to Magento Admin Panel
- Go to System > Permissions > All Users — create admin user (for admin token)
- Or, go to System > Extensions > Integrations — create integration (for OAuth)
Step 2: Choose Authentication Method
| Method | Best For | Token Lifetime |
|---|---|---|
| Admin Token | Internal integrations | Configurable (default 4h) |
| Integration Token | Third-party apps | Until revoked |
| OAuth 1.0a | Public marketplace | Until revoked |
| Customer Token | Customer-facing apps | Configurable |
Step 3: Get Admin Token (Simplest Method)
Generate admin token for internal use:
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');
const token = await response.text();
return token;
};
// Usage
const token = await getAdminToken();
console.log(`Admin token: ${token}`);
// Store securely for API calls
Security best practice: Store credentials in environment variables:
# .env
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)
- Go to System > Extensions > Integrations
- Click Add New Integration
- Fill details (name, email, callback/identity URLs for OAuth)
- Set API Permissions (Products, Orders, Customers, Inventory recommended)
- Click Save and Activate
- Copy Access Token and Token Secret
Step 5: Get Customer Token
For customer-facing apps:
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
Reusable API client example:
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 filters:
const getProducts = async (filters = {}) => {
const params = new URLSearchParams();
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 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 a simple product:
const createProduct = async (productData) => {
const product = {
product: {
sku: productData.sku,
name: productData.name,
attribute_set_id: productData.attributeSetId || 4,
type_id: 'simple',
price: productData.price,
status: productData.status || 1,
visibility: productData.visibility || 4,
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 by SKU:
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
await updateProduct('TSHIRT-001', {
price: 24.99,
extension_attributes: {
stock_item: { qty: 150, is_in_stock: true }
}
});
Deleting a 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 w/ variations | Size/color options |
| Grouped | Set of simple products | Bundles |
| Virtual | Non-physical | Services, downloads |
| Bundle | Customizable bundles | Build-your-own kits |
| Downloadable | Digital | E-books, software |
Order Management
Getting Orders
Fetch orders with filters:
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
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
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}`);
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
Update order status via workflow endpoints:
const updateOrderStatus = async (orderId, newStatus) => {
// Cancel
await magentoRequest(`/V1/orders/${orderId}/cancel`, { method: 'POST' });
// Hold
await magentoRequest(`/V1/orders/${orderId}/hold`, { method: 'POST' });
// Unhold
await magentoRequest(`/V1/orders/${orderId}/unhold`, { method: 'POST' });
};
Creating Invoice
const createInvoice = async (orderId, items = [], notify = true, appendComment = false, comment = null) => {
const invoice = {
capture: true,
last: true,
items: items
};
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
const invoiceId = await createInvoice(12345, [], true, false, 'Thank you for your order!');
console.log(`Invoice created: ${invoiceId}`);
Creating Shipment
const createShipment = async (orderId, items = [], notify = true, appendComment = false, comment = null, tracks = []) => {
const shipment = {
items: items,
notify: notify ? 1 : 0,
append_comment: appendComment ? 1 : 0,
comment: comment,
tracks: tracks
};
const response = await magentoRequest(`/V1/order/${orderId}/ship`, {
method: 'POST',
body: JSON.stringify(shipment)
});
return response;
};
// Usage
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
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
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
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
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 does not have built-in webhooks. Use these approaches:
// 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
- Default: No limit (set in Admin)
- Recommended: 100–1000 requests/minute
Configure: Stores > Configuration > Services > Web API > Security
Implementing Rate Limit Handling
Example exponential backoff:
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, ensure:
- [ ] Use integration tokens (avoid admin creds in prod)
- [ ] Store tokens securely (encrypted storage)
- [ ] Implement rate limiting and request queues
- [ ] Add robust error handling
- [ ] Enable logging for all API calls
- [ ] Use webhook alternative (polling/Adobe I/O)
- [ ] Test with production data/volume
- [ ] Add retry logic for failures
Real-World Use Cases
ERP Integration
- Challenge: Manual stock sync between ERP and Magento
- Solution: Bi-directional API sync every 15 min
- Result: Real-time inventory, no overselling
Mobile App
- Challenge: Need high-performance mobile experience
- Solution: GraphQL for product browsing; REST for checkout
- Result: +40% mobile conversion rate
Conclusion
Magento 2 API enables robust e-commerce integrations:
- REST, SOAP, and GraphQL APIs
- Token-based authentication
- Full CRUD for products, orders, customers
- MSI for advanced inventory
- Configurable rate limits
- 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 for OAuth. Use customer token for customer-facing apps.
What is the difference between REST and GraphQL in Magento?
REST covers full CRUD. GraphQL is optimized for frontend queries and efficient data fetches.
How do I create a product via API?
POST to /V1/products with product data (SKU, name, price, stock_item in extension_attributes).
Can I get webhooks for new orders?
Magento lacks native webhooks. Use polling, Adobe I/O Events (Adobe Commerce), or a custom module.
How do I update stock quantities?
PUT to /V1/products/{sku}/stockItems/1 with qty and is_in_stock values.
Top comments (0)