TL;DR
La API de Magento 2 (Adobe Commerce) permite a los desarrolladores integrarse con tiendas de comercio electrónico de forma programática. Utiliza puntos finales REST, SOAP y GraphQL con autenticación OAuth 1.0a y basada en tokens, proporcionando acceso a productos, pedidos, clientes, inventario y más, con límites de velocidad configurables. Esta guía cubre la configuración de autenticación, operaciones CRUD, webhooks, puntos finales personalizados y estrategias de integración en producción.
Introducción
Adobe Commerce (Magento) impulsa más de 250.000 tiendas de comercio electrónico con más de 155 mil millones de dólares en valor bruto de mercancía anual. Para los desarrolladores que crean integraciones de comercio electrónico, conectores ERP o aplicaciones móviles, la integración de la API de Magento no es opcional, es esencial para llegar a esta masiva base de comerciantes.
Esta es la realidad: los comerciantes que gestionan múltiples canales de venta pierden entre 20 y 30 horas semanales en la entrada manual de datos entre Magento y otros sistemas. Una sólida integración de la API de Magento automatiza la sincronización de productos, el procesamiento de pedidos, las actualizaciones de inventario y la gestión de datos de clientes.
Esta guía recorre el proceso completo de integración de la API de Magento 2. Aprenderás sobre OAuth 1.0a y la autenticación por token, los puntos finales REST/SOAP/GraphQL, la gestión de productos y pedidos, los webhooks, el desarrollo de API personalizadas y las estrategias de despliegue en producción. Al final, tendrás una integración de Magento lista para producción.
¿Qué es la API de Magento 2?
Magento 2 proporciona tres tipos de API para acceder a los datos de comercio electrónico:
- API REST: Basada en JSON para aplicaciones web y móviles
- API SOAP: Basada en XML para integraciones empresariales
- GraphQL: Basada en consultas para aplicaciones frontend eficientes
La API maneja:
- Productos, categorías e inventario
- Pedidos, facturas y envíos
- Clientes y grupos de clientes
- Cesta de compra y pago
- Promociones y reglas de precios
- Páginas y bloques CMS
- Configuración de la tienda
Características Clave
| Característica | Descripción |
|---|---|
| Múltiples Protocolos | REST, SOAP, GraphQL |
| OAuth 1.0a | Acceso seguro de terceros |
| Autenticación por Token | Tokens de administrador e integración |
| Webhooks | Operaciones asíncronas vía colas |
| Límite de Velocidad | Configurable por instalación |
| Puntos Finales Personalizados | Extensible con APIs personalizadas |
| Multitienda | Una única API, múltiples vistas de tienda |
Comparación de APIs
| Tipo de API | Protocolo | Caso de Uso |
|---|---|---|
| REST | JSON | Aplicaciones móviles, integraciones |
| SOAP | XML | Sistemas empresariales (SAP, Oracle) |
| GraphQL | GraphQL | Escaparate, PWA |
Versiones de Magento
| Versión | Estado | Fin de Soporte |
|---|---|---|
| Magento 2.4.x | Actual | Activo |
| Adobe Commerce 2.4.x | Actual | Activo |
| Magento 1.x | Fin de Vida (EOL) | Junio de 2020 (No usar) |
Primeros Pasos: Configuración de la Autenticación
Paso 1: Crear una Cuenta de Administrador o Integración
Antes de acceder a la API:
- Inicia sesión en el Panel de Administración de Magento
- Navega a Sistema > Permisos > Todos los Usuarios
- Crea un usuario administrador (para token de administrador) O
- Navega a Sistema > Extensiones > Integraciones
- Crea una nueva integración (para OAuth)
Paso 2: Elegir Método de Autenticación
| Método | Mejor para | Vida Útil del Token |
|---|---|---|
| Token de Administrador | Integraciones internas | Configurable (predeterminado: 4 horas) |
| Token de Integración | Aplicaciones de terceros | Hasta que se revoque |
| OAuth 1.0a | Aplicaciones de mercado públicas | Hasta que se revoque |
| Token de Cliente | Aplicaciones orientadas al cliente | Configurable |
Paso 3: Obtener Token de Administrador (Método más Simple)
Genera un token de administrador para integraciones internas:
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');
}
// La respuesta es una cadena simple (el token), no JSON
const token = await response.text();
return token;
};
// Uso
const token = await getAdminToken();
console.log(`Admin token: ${token}`);
// Almacenar de forma segura - usar para llamadas posteriores a la API
Nota de seguridad: Almacena los tokens de forma segura:
# Archivo .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"
Paso 4: Crear Integración (Recomendado para Terceros)
Crea una integración a través del Panel de Administración:
Ve a Sistema > Extensiones > Integraciones
Haz clic en Añadir Nueva Integración
Rellena los detalles:
- Nombre: “Mi Integración”
- Correo electrónico: tu-correo@example.com
- URL de Retorno: (para OAuth)
- URL de Enlace de Identidad: (para OAuth)
Establece los Permisos de API:
- Recursos: Selecciona los permisos necesarios
- Recomendado: Productos, Pedidos, Clientes, Inventario
Haz clic en Guardar
Haz clic en Activar en la nueva integración
Copia el Token de Acceso y el Secreto del Token
Paso 5: Obtener Token de Cliente
Para aplicaciones orientadas al cliente:
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;
};
// Uso
const customerToken = await getCustomerToken('customer@example.com', 'password123');
Paso 6: Realizar Llamadas a la API Autenticadas
Crea un cliente API reutilizable:
const magentoRequest = async (endpoint, options = {}) => {
const token = await getAdminToken(); // O recuperar el token almacenado
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();
};
// Uso
const products = await magentoRequest('/V1/products');
console.log(`Se encontraron ${products.items.length} productos`);
Gestión de Productos
Obtener Productos
Buscar productos con filtros:
const getProducts = async (filters = {}) => {
const params = new URLSearchParams();
// Construir criterios de búsqueda
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;
};
// Uso
const products = await getProducts({ search: 'camiseta', priceFrom: 20, limit: 50 });
products.items.forEach(product => {
console.log(`${product.sku}: ${product.name} - $${product.price}`);
});
Obtener un Solo Producto
Buscar producto por SKU:
const getProduct = async (sku) => {
const response = await magentoRequest(`/V1/products/${sku}`);
return response;
};
// Uso
const product = await getProduct('TSHIRT-001');
console.log(`Nombre: ${product.name}`);
console.log(`Precio: $${product.price}`);
console.log(`Stock: ${product.extension_attributes?.stock_item?.qty}`);
Crear un Producto
Crear producto simple:
const createProduct = async (productData) => {
const product = {
product: {
sku: productData.sku,
name: productData.name,
attribute_set_id: productData.attributeSetId || 4, // Conjunto predeterminado
type_id: 'simple',
price: productData.price,
status: productData.status || 1, // 1=habilitado, 2=deshabilitado
visibility: productData.visibility || 4, // 4=Catálogo y Búsqueda
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;
};
// Uso
const newProduct = await createProduct({
sku: 'TSHIRT-NEW-001',
name: 'Camiseta de Algodón Premium',
price: 29.99,
qty: 100,
description: 'Camiseta de algodón de alta calidad',
shortDescription: 'Camiseta de algodón premium',
color: 'Azul',
size: 'M'
});
console.log(`Producto creado: ${newProduct.id}`);
Actualizar un Producto
Actualizar información del producto:
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;
};
// Uso - Actualizar precio y stock
await updateProduct('TSHIRT-001', {
price: 24.99,
extension_attributes: {
stock_item: {
qty: 150,
is_in_stock: true
}
}
});
Eliminar un Producto
Eliminar producto:
const deleteProduct = async (sku) => {
await magentoRequest(`/V1/products/${sku}`, {
method: 'DELETE'
});
console.log(`Producto ${sku} eliminado`);
};
Tipos de Productos
| Tipo | Descripción | Caso de Uso |
|---|---|---|
| Simple | Un solo SKU, sin variaciones | Productos estándar |
| Configurable | Padre con variaciones de hijo | Opciones de talla/color |
| Agrupado | Colección de productos simples | Paquetes de productos |
| Virtual | Productos no físicos | Servicios, descargas |
| Paquete | Paquetes de productos personalizables | Kits "constrúyelo tú mismo" |
| Descargable | Productos digitales | Libros electrónicos, software |
Gestión de Pedidos
Obtener Pedidos
Buscar pedidos con filtros:
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;
};
// Uso - Obtener pedidos pendientes de los últimos 7 días
const orders = await getOrders({
status: 'pending',
dateFrom: '2026-03-18 00:00:00',
limit: 50
});
orders.items.forEach(order => {
console.log(`Pedido #${order.increment_id}: ${order.customer_email} - $${order.grand_total}`);
});
Obtener un Solo Pedido
Buscar pedido por ID:
const getOrder = async (orderId) => {
const response = await magentoRequest(`/V1/orders/${orderId}`);
return response;
};
// Uso
const order = await getOrder(12345);
console.log(`Pedido #${order.increment_id}`);
console.log(`Estado: ${order.status}`);
console.log(`Total: $${order.grand_total}`);
console.log(`Artículos:`);
order.items.forEach(item => {
console.log(` - ${item.name} x ${item.qty_ordered}`);
});
Flujo de Estado de Pedido
pendiente → en_proceso → completado
→ cancelado
→ en_espera
→ revisión_de_pago
Actualizar el Estado del Pedido
Cambiar el estado del pedido:
const updateOrderStatus = async (orderId, newStatus) => {
// Nota: La actualización directa del estado requiere un punto final personalizado
// Usar el flujo de gestión de pedidos en su lugar:
// Para cancelar:
await magentoRequest(`/V1/orders/${orderId}/cancel`, {
method: 'POST'
});
// Para poner en espera:
await magentoRequest(`/V1/orders/${orderId}/hold`, {
method: 'POST'
});
// Para quitar de espera:
await magentoRequest(`/V1/orders/${orderId}/unhold`, {
method: 'POST'
});
};
Crear Factura
Generar factura para el pedido:
const createInvoice = async (orderId, items = [], notify = true, appendComment = false, comment = null) => {
const invoice = {
capture: true, // true = capturar pago
last: true,
items: items // Array de {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;
};
// Uso - Facturar y capturar el pedido completo
const invoiceId = await createInvoice(12345, [], true, false, '¡Gracias por tu pedido!');
console.log(`Factura creada: ${invoiceId}`);
Crear Envío
Enviar pedido:
const createShipment = async (orderId, items = [], notify = true, appendComment = false, comment = null, tracks = []) => {
const shipment = {
items: items, // Array de {order_item_id, qty}
notify: notify ? 1 : 0,
append_comment: appendComment ? 1 : 0,
comment: comment,
tracks: tracks // Array de {track_number, title, carrier_code}
};
const response = await magentoRequest(`/V1/order/${orderId}/ship`, {
method: 'POST',
body: JSON.stringify(shipment)
});
return response;
};
// Uso - Enviar con seguimiento
const shipmentId = await createShipment(12345, [], true, false, '¡Tu pedido ha sido enviado!', [
{
track_number: '1Z999AA10123456784',
title: 'Número de Seguimiento',
carrier_code: 'ups'
}
]);
console.log(`Envío creado: ${shipmentId}`);
Gestión de Clientes
Obtener Clientes
Buscar clientes:
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;
};
// Uso
const customers = await getCustomers({ email: 'customer@example.com' });
customers.items.forEach(customer => {
console.log(`${customer.firstname} ${customer.lastname} - ${customer.email}`);
});
Crear un Cliente
Registrar nuevo cliente:
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;
};
// Uso
const newCustomer = await createCustomer({
email: 'newcustomer@example.com',
firstname: 'Juan',
lastname: 'Pérez',
password: 'ContraseñaSegura123!',
subscribed: true
});
console.log(`Cliente creado: ID ${newCustomer.id}`);
Gestión de Inventario (MSI)
Obtener Estado de Stock
Verificar stock del producto:
const getStockStatus = async (sku) => {
const response = await magentoRequest(`/V1/products/${sku}/stockItems/1`);
return response;
};
// Uso
const stock = await getStockStatus('TSHIRT-001');
console.log(`Cantidad: ${stock.qty}`);
console.log(`En Stock: ${stock.is_in_stock}`);
console.log(`Cantidad Mínima: ${stock.min_qty}`);
Actualizar Stock
Actualizar cantidad de producto:
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;
};
// Uso
await updateStock('TSHIRT-001', 100, true);
Webhooks y Operaciones Asíncronas
Configurar Webhooks
Magento utiliza colas de mensajes para notificaciones asíncronas:
// Magento no tiene webhooks nativos
// Usa estos enfoques en su lugar:
// 1. Sondear el punto final de pedidos periódicamente
const pollNewOrders = async (lastOrderId) => {
const orders = await getOrders({
dateFrom: new Date().toISOString()
});
const newOrders = orders.items.filter(o => o.id > lastOrderId);
return newOrders;
};
// 2. Usar Eventos de Adobe I/O (solo Adobe Commerce)
// Configurar eventos en la Consola de Desarrolladores de Adobe
// 3. Crear un módulo de webhook personalizado
// Ver: https://devdocs.magento.com/guides/v2.4/extension-dev-guide/message-queues/message-queues.html
Límite de Velocidad
Comprender los Límites de Velocidad
Los límites de velocidad de Magento son configurables:
- Predeterminado: Sin límite (configurar en el Administrador)
- Recomendado: 100-1000 solicitudes/minuto
Configurar en el Administrador: Tiendas > Configuración > Servicios > API Web > Seguridad
Implementación del Manejo de Límites de Velocidad
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;
}
}
}
};
Lista de Verificación de Despliegue en Producción
Antes de salir a producción:
- [ ] Usar tokens de integración (no credenciales de administrador) en producción
- [ ] Almacenar tokens de forma segura (base de datos cifrada)
- [ ] Implementar limitación de velocidad y colas de solicitudes
- [ ] Añadir un manejo de errores completo
- [ ] Configurar el registro para todas las llamadas a la API
- [ ] Crear una alternativa de webhook (sondeo o Adobe I/O)
- [ ] Probar con el volumen de datos de producción
- [ ] Implementar lógica de reintentos para solicitudes fallidas
Casos de Uso del Mundo Real
Integración ERP
Un fabricante sincroniza el inventario:
- Reto: Actualizaciones manuales de stock entre ERP y Magento
- Solución: Sincronización API bidireccional cada 15 minutos
- Resultado: Inventario en tiempo real, cero ventas excesivas
Aplicación Móvil
Un minorista construye una aplicación de compras:
- Reto: Necesidad de una experiencia móvil nativa
- Solución: API GraphQL para la navegación de productos, REST para el pago
- Resultado: Aumento del 40% en la conversión móvil
Conclusión
La API de Magento 2 proporciona una funcionalidad completa de comercio electrónico. Puntos clave:
- APIs REST, SOAP y GraphQL disponibles
- Autenticación basada en tokens para integraciones
- CRUD completo para productos, pedidos, clientes
- MSI para una gestión avanzada de inventario
- Límites de velocidad configurables por instalación
- Apidog agiliza las pruebas de API y la colaboración en equipo
Sección de Preguntas Frecuentes
¿Cómo me autentico con la API de Magento?
Usa un token de administrador para integraciones internas o crea una Integración en Sistema > Extensiones para OAuth. Token de cliente para aplicaciones orientadas al cliente.
¿Cuál es la diferencia entre REST y GraphQL en Magento?
REST proporciona operaciones CRUD completas. GraphQL está optimizado para consultas frontend con una recuperación de datos eficiente.
¿Cómo creo un producto a través de la API?
POST a /V1/products con datos del producto incluyendo SKU, nombre, precio y stock_item en extension_attributes.
¿Puedo obtener webhooks para nuevos pedidos?
Magento no tiene webhooks nativos. Usa sondeo, Eventos de Adobe I/O (Adobe Commerce) o crea un módulo personalizado.
¿Cómo actualizo las cantidades de stock?
PUT a /V1/products/{sku}/stockItems/1 con valores de qty y is_in_stock.
