Saltar al contenido principal

API de integración

Esta API permite a un conector de tienda en línea leer el catálogo y el stock de Nadigit IMS, reservar stock para un carrito y registrar pedidos. A cambio, Nadigit IMS avisa al conector mediante webhooks firmados. Es la API que usa el conector Bagisto, y la que sirve para desarrollar un conector para otra plataforma.

Esta página solo documenta la API de integración: las demás API de Nadigit IMS están reservadas a la consola web.

Antes de empezar​

  • Plan Enterprise.
  • Una integración declarada y aprovisionada en Integraciones de e-commerce. El aprovisionamiento proporciona la configuración del conector. Vea Integración e-commerce.
Campo de la configuraciónUso
backendUrlDirección base de la API: las rutas siguientes se añaden a ella
keycloakTokenUrlDirección para obtener los tokens
keycloakClientId, keycloakClientSecretCredenciales del conector
webhookSecretSecreto para verificar los webhooks

Autenticación​

El conector obtiene un token de acceso con el flujo OAuth 2.0 client credentials y lo envía en la cabecera Authorization de cada llamada.

curl -s -X POST "$KEYCLOAK_TOKEN_URL" \
-d grant_type=client_credentials \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET"
GET /api/ecommerce/catalog HTTP/1.1
Authorization: Bearer <access_token>
  • El token es de corta duración (expires_in, en segundos): consérvelo y renuévelo justo antes de que caduque, en lugar de pedir uno en cada llamada.
  • Alcance. El conector solo accede a la API de integración, y solo para el almacén y la tienda vinculados a la integración. El almacén nunca es un parámetro de la petición: lo fija la identidad del conector.

Convenciones​

  • Intercambios en JSON, codificación UTF-8.
  • El SKU es la referencia del artículo en Nadigit IMS, única en el almacén.
  • Las cantidades se expresan en la unidad de venta del artículo, con decimales para los artículos vendidos por peso o medida (fractional).
  • Los importes están en la moneda de la organización.

Puntos de acceso​

MétodoRutaPapel
GET/api/ecommerce/catalogCatálogo publicable, paginado
GET/api/ecommerce/catalog/{sku}Un artículo
GET/api/ecommerce/stock?skus=…Stock de 200 artículos como máximo
PUT/api/ecommerce/reservations/{cartId}Reservar el stock de un carrito
POST/api/ecommerce/ordersRegistrar un pedido
POST/api/ecommerce/orders/{reference}/cancelAnular un pedido
GET /api/ecommerce/catalog?page=0&size=100
GET /api/ecommerce/catalog/ACC-POIG-BL

El catálogo contiene los artículos activos y físicos del almacén vinculado; los servicios quedan excluidos. La lista está paginada (page desde 0, size de 1 a 200, 100 por defecto) y ordenada por SKU. Un SKU desconocido, inactivo o de otro almacén devuelve 404.

{
"sku": "ACC-POIG-BL",
"name": "Poignée de fenêtre à crémone – blanc",
"description": "…",
"category": "Accessoires",
"categoryPath": ["Accessoires"],
"price": 45.0,
"taxRate": 20.0,
"taxClass": "…",
"taxInclusive": false,
"allocatable": 146.0,
"measureUnit": "Unité",
"fractional": false,
"quantityPrecision": 0,
"primaryImageUrl": "https://…",
"imageUrls": ["https://…"],
"barcodes": ["…"]
}

La lista devuelve estos objetos en una página (content, totalElements, totalPages, number, size). El catálogo aún no ofrece un filtro «modificado desde»: sincronícelo completo y apóyese en los webhooks para los cambios.

Stock​

GET /api/ecommerce/stock?skus=ACC-POIG-BL,SIL-NEU-280,DESCONOCIDO
[
{ "sku": "ACC-POIG-BL", "found": true, "sellable": 148.0, "reservedByOthers": 2.0, "allocatable": 146.0 },
{ "sku": "DESCONOCIDO", "found": false, "sellable": null, "reservedByOthers": null, "allocatable": null }
]
CampoSignificado
sellableStock vendible en el almacén
reservedByOthersCantidad reservada por otros carritos o ventas en curso
allocatableLo que aún puede venderse: la cantidad que mostrar
foundfalse para un SKU desconocido: retírelo de la venta

Hasta 200 SKU por llamada, separados por comas.

Reservas​

Reservar el stock de un carrito evita vender en línea un artículo que ya no está. Llame a este punto de acceso en cada cambio del carrito y justo antes del pago.

PUT /api/ecommerce/reservations/carrito-8841
Content-Type: application/json

{ "lines": [ { "sku": "ACC-POIG-BL", "quantity": 2 } ] }
  • 204: la reserva del carrito se sustituye por estas líneas.
  • 409: el pago debe bloquearse.
{
"code": "insufficient_stock",
"message": "…",
"lines": [ { "sku": "ACC-POIG-BL", "requested": 2, "allocatable": 1 } ]
}

code vale insufficient_stock (stock insuficiente, línea por línea) o reservations_disabled (las reservas flexibles están desactivadas en Nadigit IMS). Una reserva caduca por sí sola: un carrito abandonado libera su stock sin acción del conector.

Pedidos​

POST /api/ecommerce/orders
Content-Type: application/json

{
"reference": "WEB-1000231",
"cartId": "carrito-8841",
"orderDate": "2026-09-24T18:40:00",
"customer": { "email": "cliente@ejemplo.ma", "firstName": "Salma", "lastName": "Idrissi", "phone": "+212600000000" },
"lines": [ { "sku": "ACC-POIG-BL", "quantity": 2, "unitPrice": 45.0 } ],
"declaredTotal": 108.0,
"paymentMethod": "card",
"paymentReference": "ch_3Q…"
}
CampoObligatorioNota
referenceSíReferencia del pedido en la tienda, 64 caracteres como máximo. Sirve de clave de unicidad
cartIdNoEl carrito cuya reserva se consume
customerNoCliente encontrado por correo, o creado
linesSíSKU y cantidades. unitPrice es indicativo
shipping, declaredTotalNoIndicativos, comparados con el total recalculado
paymentMethodNoVea más abajo
paymentReferenceNoReferencia de la transacción, guardada en el pago

Comportamiento:

  • Nadigit IMS recalcula precios e impuestos. Si declaredTotal difiere, el pedido se acepta y priceMismatch vale true.
  • El pedido descuenta el stock del almacén y se vincula a la tienda.
  • Idempotencia: reenviar la misma reference devuelve el pedido existente (alreadyExisted: true), sin crear un duplicado. Un conector puede repetir un pedido con total seguridad.
  • paymentMethod: card, wallet, stripe, paypal, online, transfer o cash registran un pago: el pedido queda pagado. cod (contra reembolso), un valor vacío o desconocido no registran nada: el pedido queda impagado.
{
"reference": "WEB-1000231",
"status": "Processing",
"paymentStatus": "PAID",
"totalAmount": 108.0,
"dutyFreeAmount": 90.0,
"taxAmount": 18.0,
"alreadyExisted": false,
"priceMismatch": false,
"declaredTotal": 108.0
}

Anulación​

POST /api/ecommerce/orders/WEB-1000231/cancel

Anula el pedido y devuelve su stock al almacén. Un pedido ya anulado devuelve éxito con alreadyExisted: true; una referencia desconocida en el almacén devuelve 404. El reembolso eventual no es automático.

Webhooks​

Nadigit IMS llama al conector en la URL de la tienda + Ruta del webhook declaradas en la integración, con POST, tras cada cambio registrado.

Eventos​

product.updated: un artículo ha cambiado (stock, precio, estado).

{ "event": "product.updated", "action": "upsert", "sku": "ACC-POIG-BL", "occurredAt": "2026-09-24T18:41:07Z" }
  • action: "upsert": vuelva a leer el artículo con GET /api/ecommerce/catalog/{sku} y aplíquelo.
  • action: "unpublish": retire el artículo de la venta (desactivado, agotado o ausente del almacén).

order.status: un pedido web ha cambiado de estado.

{ "event": "order.status", "reference": "WEB-1000231", "status": "Delivered", "paymentStatus": "PAID", "occurredAt": "2026-09-25T10:02:13Z" }
statusSignificado
ProcessingEn preparación (estado al registrarse)
Delivered, CompletedEntregado, terminado
CanceledAnulado
Return_Pending, Returned, Partial_ReturnDevolución en curso, devuelto, devuelto parcialmente

paymentStatus vale UNPAID, PARTIALLY_PAID o PAID.

Verificar la firma​

Cada webhook lleva dos cabeceras:

  • X-Timestamp: la hora de envío, en segundos desde el 1 de enero de 1970;
  • X-Signature: HMAC-SHA256(webhookSecret, X-Timestamp + "." + cuerpo), en hexadecimal en minúsculas.

Recalcule la firma sobre el cuerpo bruto recibido, compárela en tiempo constante y rechace una marca de tiempo demasiado antigua (por ejemplo, más de cinco minutos).

$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $ts . '.' . $body, $webhookSecret);
if (!hash_equals($expected, $sig) || abs(time() - (int) $ts) > 300) {
http_response_code(401);
exit;
}
const crypto = require('crypto');
function isValid(rawBody, ts, sig, secret) {
const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
return sig.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
&& Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
}

Respuesta y reintentos​

Responda 2xx rápidamente y procese después el webhook. En caso de fallo o sin respuesta, Nadigit IMS reintenta varias veces espaciando los intentos. Cada intento queda registrado en Nadigit IMS. Procese los webhooks de forma idempotente: el mismo evento puede llegar dos veces.

Códigos de error​

CódigoCausa
400Petición no válida (campo que falta o mal formado); el cuerpo detalla los campos
401Token ausente, caducado o no válido: renueve el token
403Acceso denegado, o función no incluida en el plan de la instalación
404SKU o pedido desconocido en el almacén vinculado
409Stock insuficiente o reservas desactivadas (vea Reservas)
503Instalación sin licencia activa

Los errores distintos de 409 devuelven un cuerpo de esta forma:

{ "timestamp": "…", "status": 403, "error": "Forbidden", "message": "…", "path": "/api/ecommerce/catalog", "errorCode": "…" }

Ver también​