Saltar al contenido principal

Custom · Server-to-server

Este es el patrón base para cualquier integración custom: tu backend habla con Neuroon usando la API Key (Bearer token) y nunca expone esa key al frontend. Los flujos servidor-a-servidor son:

  1. Firmar Widget Token localmente con la API Key (HMAC) y cachearlo 24 h con margen de 5 min. Ver Recipe · Server-to-server token.
  2. Sincronizar productos (POST /api/integrations/v1/products/sync) en lotes.
  3. Borrar productos (DELETE /api/integrations/v1/products/by-external/{externalId}) cuando los retiras de tu catálogo.
  4. Verificar dominio (desde el Dashboard, con un registro DNS TXT) tras dar de alta una tienda — ver Verificación de dominio.
  5. Trackear conversiones (POST /api/integrations/v1/conversions) cuando el pedido se confirma.

Headers comunes​

HeaderValorNotas
AuthorizationBearer <api-key>Authn server-to-server. Nunca al frontend.
OriginURL de tu storefrontValidación adicional para verificación de dominio.
Content-Typeapplication/jsonPara POST/PUT/PATCH.
User-Agentyour-app/versionFacilita el filtrado en logs de Neuroon.
X-Idempotency-Keyhash estable del batchRecomendado en /products/sync: protege contra reintentos duplicados de cron. Ej.: md5(shopId:productIds:syncType).

Respuestas comunes​

StatusSignificado
200 / 201OK.
204OK sin cuerpo (ej. delete, unverify).
400Validación. Body: { "code": "...", "message": "...", "details": [...] }.
401API key inválida o ausente.
403API key válida pero no autorizada para el Origin o el shopId.
404Shop / producto no existe.
409Conflicto (ej. dominio ya verificado, drift detectado en sync).
429Rate limit. Retry-After (segundos) en el header.
5xxReintentar con backoff exponencial.

Sync de productos​

Semántica del payload​

Cuando construyas el body para POST /api/integrations/v1/products/sync, hay reglas que el contrato OpenAPI no hace evidentes pero que rompen la integración si las ignoras:

Schema completo del request en API Reference → POST /products/sync y PluginProductDTO. Esta sección sólo cubre los puntos no obvios del contrato.

  • Variantes después del padre. Si tu producto tiene variantes (talla/color), envía el padre primero en el array y cada variante con parentExternalId apuntando al padre. Variantes huérfanas (sin padre en el mismo batch o ya sincronizado) se descartan en silencio.
  • Precios con o sin impuestos — sé explícito. El backend toma el price que mandes tal cual; no infiere taxes. Si tu storefront muestra precios con IVA, manda price con IVA. Si los muestra sin, manda sin. Mantén la convención consistente con lo que el cliente final ve, o el dashboard reportará drift de precios.
  • description acepta hasta 5000 caracteres por contrato. Como guía operativa, descripciones muy largas (>2000 chars) suelen empeorar la calidad del ranking — usa la short description si la tienes o trunca a texto plano sin HTML.
  • categories[] (lista). Manda la jerarquía completa, de la categoría más específica a la raíz. El backend la usa para construir filtros guiados.
  • brands[] (lista). Si tu plataforma tiene un campo de marca dedicado, pásalo aquí. No lo derives del título.
  • syncType acepta INCREMENTAL o FULL. Usa INCREMENTAL en el 99 % de casos: es un upsert por externalId. Solo usa FULL durante una migración inicial o un reset deliberado — borra todo el catálogo en Neuroon antes de reinsertar el batch que mandes. Nunca lo dispares en cron: una FULL accidental vacía el índice mientras dura el sync.
  • Tamaño del batch: máx 500 productos por request, mín 1.

Detección de conflictos antes de sobrescribir​

Si tu integración comparte el catálogo con otra fuente (dashboard de Neuroon, otra integración, edición manual), lee antes de escribir:

async function syncProductSafely(local) {
const remote = await fetch(
`${API_URL}/api/integrations/v1/products/${local.externalId}`,
{ headers: { 'Authorization': API_KEY } },
).then(r => r.ok ? r.json() : null);

if (remote && hasDriftedFromLastKnown(local.lastSyncedSnapshot, remote)) {
// El producto cambió en Neuroon desde tu último sync — pide confirmación
// antes de sobrescribir, o registra el conflicto para revisión.
return { status: 'conflict', remote };
}

return postSync([local]);
}

Campos que tienen sentido diffear: name, price, salePrice, description, sku, stockQuantity, stockStatus. Sin esta verificación, ediciones hechas en el dashboard (ej. el usuario corrige un precio) se sobrescriben silenciosamente en el siguiente cron sync.

POST /products/sync no contempla deletions — productos que dejas de mandar se quedan en Neuroon. Para retirar un producto, llama explícitamente:

curl -X DELETE "https://api.neuroon.ai/api/integrations/v1/products/$EXTERNAL_ID" \
-H "Authorization: Bearer $API_KEY"

Patrón recomendado para integraciones que no tienen señal directa de "producto borrado":

// Job nocturno: detecta SKUs eliminados en tu BD que aún viven en Neuroon
async function reconcileDeletions() {
const localSkus = new Set((await db.query('SELECT external_id FROM products WHERE deleted = false')).map(r => r.external_id));

let cursor = null;
do {
const { products, nextCursor } = await fetch(
`${API_URL}/api/integrations/v1/products?cursor=${cursor ?? ''}`,
{ headers: { 'Authorization': API_KEY } },
).then(r => r.json());

for (const p of products) {
if (!localSkus.has(p.externalId)) {
await fetch(
`${API_URL}/api/integrations/v1/products/${p.externalId}`,
{ method: 'DELETE', headers: { 'Authorization': API_KEY } },
);
}
}
cursor = nextCursor;
} while (cursor);
}

Frecuencia recomendada: una vez al día. Sin esto, productos retirados de tu storefront siguen apareciendo en búsqueda.

Firma del Widget Token​

Tu servidor firma el token localmente con la API Key como secreto HMAC. No llamas a Neuroon para esto.

Código copy-paste con cache + rotación (Node, .NET, Python, PHP) en Recipe · Server-to-server token.

Idempotencia y reintentos​

EndpointIdempotente porReintentos seguros
Sign Widget Token (local)(firma local)Sí: re-firmar genera un token nuevo válido.
products/syncexternalId por producto + X-Idempotency-Key opcionalSí: reenviar el mismo batch no duplica.
products/{externalId} (DELETE)externalIdSí: borrar dos veces devuelve 204.
track/conversionorderIdSí: reenviar la misma conversión no duplica.
verifydominio + shopIdSí, idempotente.

Patrón de retry mínimo: 3 intentos con backoff exponencial sobre 429 y 5xx.

Buenas prácticas​

  • Nunca transmitas la API Key al frontend, ni siquiera vía process.env.NEXT_PUBLIC_*.
  • Cachea el Widget Token server-side y refresca con margen de 5 minutos.
  • Loguea con User-Agent específico para facilitar diagnóstico.
  • Maneja 429 respetando Retry-After.
  • No mezcles entornos: tokens de Development no funcionan contra api.neuroon.ai y viceversa.
  • Manda X-Idempotency-Key en sync batches: protege contra reintentos duplicados del cron tras un timeout.
  • Implementa el job de deletions: sin él, tu catálogo en Neuroon crece para siempre.
  • Diff antes de sobrescribir si el catálogo se edita desde más de una fuente.

Próximos pasos​