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 Shop API Key (sk_…) y nunca expone esa key al frontend. Los tres flujos servidor-a-servidor son:

  1. Emitir Widget Token (POST /api/shops/{id}/widget-token) y cachearlo. El TTL es fijo de 24 h; rótalo a las 23 h.
  2. Sincronizar productos (POST /api/plugin/shops/{shopId}/products/sync) en lotes.
  3. Trackear conversiones (POST /api/plugin/shops/{shopId}/track/conversion) cuando el pedido se confirma.

Headers comunes

HeaderValorNotas
X-Shop-API-Keysk_…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.

Respuestas comunes

StatusSignificado
200 / 201OK.
204OK sin cuerpo (ej. 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).
429Rate limit. Retry-After (segundos) en el header.
5xxReintentar con backoff exponencial.

Ejemplo: emitir Widget Token

neuroon.js
import fetch from 'node-fetch';

const SHOP_ID = process.env.NEUROON_SHOP_ID;
const API_KEY = process.env.NEUROON_API_KEY;
const API_URL = process.env.NEUROON_API_URL ?? 'https://api.neuroon.ai';
const ROTATE_AFTER_MS = 23 * 60 * 60 * 1000; // TTL fijo 24 h

let cache = null; // { token, issuedAt: epoch ms }

export async function getWidgetToken() {
const now = Date.now();
if (cache && now - cache.issuedAt < ROTATE_AFTER_MS) return cache.token;

const res = await fetch(`${API_URL}/api/shops/${SHOP_ID}/widget-token`, {
  method: 'POST',
  headers: { 'X-Shop-API-Key': API_KEY, 'User-Agent': 'my-app/1.0' },
});
if (!res.ok) throw new Error(`Token issuance failed: ${res.status}`);
const body = await res.json();
cache = { token: body.token, issuedAt: now };
return cache.token;
}

Verificar el dominio (sin plugin)

Si tu integración es custom (no usas el plugin de WordPress), tienes que verificar el dominio una vez antes de poder emitir Widget Tokens. La verificación es lo que ata tu shop.url al dominio que servirá el widget.

Llama a POST /api/plugin/shops/{shopId}/verify con el dominio público del storefront en el body:

curl -X POST "$NEUROON_API_URL/api/plugin/shops/$NEUROON_SHOP_ID/verify" \
-H "X-Shop-API-Key: $NEUROON_API_KEY" \
-H "Content-Type: application/json" \
-H "Origin: https://mitienda.com" \
-d '{"domain":"https://mitienda.com"}'

El campo del body se llama domain (@NotBlank en ShopRequestDTO.java:60). Si envías url el backend responde 400.

El backend compara el domain enviado contra el shop.url registrado en el dashboard. Si coinciden, el dominio queda verificado y permite servir tokens. Si difieren:

  • 403 Forbidden con la envoltura estándar { timestamp, status, error, message, path } — edita el shop.url en el dashboard y reintenta.
  • 404 Not Found si el shopId no existe o no pertenece a tu API Key.
  • 409 Conflict si el dominio ya estaba verificado por otra tienda — abre un ticket.

Para inspeccionar el estado de verificación sin mutar nada:

curl "$NEUROON_API_URL/api/plugin/shops/$NEUROON_SHOP_ID/verification-data" \
-H "X-Shop-API-Key: $NEUROON_API_KEY"

Devuelve { verificationCode, instructions, verified } (VerificationDataDTO). El POST verify devuelve adicionalmente { shopId, verificationCode, domain, name } (PluginVerificationDataDTO).

En staging puedes verificar tantos dominios como necesites repitiendo el POST /verify con cada domain. En Production cada cambio de dominio requiere actualizar el shop.url en el dashboard.

Rotación de Widget Tokens

No existe un endpoint de "refresh" para Widget Tokens. Cada Widget Token vive 24 h (app.widget.token.ttl-hours = 24 en application.yml:271). Cuando necesites rotar:

  1. Llama otra vez a POST /api/shops/{shopId}/widget-token con tu Shop API Key.
  2. Empieza a usar el nuevo token. El anterior sigue siendo válido hasta que expire por TTL — no hay revocación instantánea.
  3. Implementa caché con margen ≤ 23 h en tu lado (ver patrón al inicio de esta página).

El endpoint POST /api/tokens/refresh que verás en la referencia OpenAPI no rota Widget Tokens: refresca tokens JWT de usuario del dashboard de Neuroon (TokenController.java:36). No lo uses para tu integración de widget.

Idempotencia y reintentos

EndpointIdempotente porReintentos seguros
widget-token(no)Sí: cada llamada genera un token nuevo (rota).
products/syncexternalId por productoSí: reenviar el mismo batch no duplica.
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 Shop 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.

Próximos pasos