Skip to main content

API routes e integraciones

1. Route handlers (app/api/*)

Todos los handlers viven en el servidor de Next.js, devuelven JSON y encapsulan la llamada a robo-api. Ninguno recibe credenciales del cliente: el token se obtiene en servidor.

Ruta internaMétodoEndpoint de robo-apiFunción
/api/get-orderPOST/order/infoBusca el pedido por order + email (envía is_customer: true) y asigna un crypto.randomUUID() a cada línea
/api/get-return-reasonsGET/return-reason/infoMotivos de devolución; filtra enabled === true
/api/get-return-methodsPOST/return-method/searchMétodos por país (countryCode obligatorio); filtra enabled === true
/api/set-returnPOST/order/create-returnCrea la devolución; transforma el objeto Refund al payload de robo-api
/api/get-returnPOST/return/infoDetalle de una devolución por return_name_id + email
/api/get-return-statusPOST/return-status/infoCatálogo de estados de devolución con traducciones
/api/get-return-line-statusPOST/return-line-status/infoCatálogo de estados de línea con traducciones
/api/get-pdf-urlPOST— (local)Firma y devuelve la URL de /doc/[data]
/api/get-pdf-status-urlPOST— (local)Firma y devuelve la URL de /status/[data]
/api/trigger-journeyPOST— (Marketing Cloud)Dispara el journey de confirmación de devolución

Además, las rutas de PDF (/doc/[data] y /status/[data]) llaman a robo-api directamente desde el servidor a través de lib/returns/fetchReturn, sin pasar por /api.

Detalles a tener en cuenta

  • Validación y traducción de errores: get-order y get-return validan los campos obligatorios y devuelven mensajes ya traducidos usando getTranslations de next-intl en servidor (Form.error.*, FormSearchOrder.*, FormRetrieveCase.*). El cliente solo tiene que mostrar data.error en un toast.
  • get-order distingue el 400 de robo-api (pedido existente pero no procesado todavía → FormSearchOrder.errorNotProcessed) del resto de errores (→ FormSearchOrder.error).
  • set-return solo reenvía de cada línea: sku, price, price_original, reason.id_return_reason y reason.extra_info; más order_id, return_method.{id_return_method, price} y sfsc_user_id.
  • Los helpers de lib/returns/* (fetchReturn, fetchReturnStatus, fetchReturnLineStatus) lanzan errores con código, del tipo RETURN_FETCH_FAILED_<status>, reutilizables tanto desde /api como desde las rutas de PDF.

2. Autenticación contra robo-api (Auth0)

app/lib/auth.tsx obtiene el token con el flujo Resource Owner Password de Auth0:

POST ${AUTH0_DOMAIN}/oauth/token
{
username, password, client_id, client_secret,
audience: AUTH0_AUDIENCE,
grant_type: 'password',
scope: 'customer'
}
  • El scope: 'customer' es el que robo-api mapea a SCOPE_customer en su SecurityConfig, lo que limita el portal a los endpoints permitidos al cliente final.
  • El token se cachea en memoria del proceso (variable de módulo) con la expiración devuelta por Auth0 menos un buffer de 10 s. No se persiste, así que cada pod/reinicio pide un token nuevo.
  • app/services/api.ts (fetchAuth) añade la cabecera Authorization: Bearer … a cada llamada. Es el único punto por el que se habla con robo-api.
  • Todas las peticiones usan las mismas credenciales de servicio para todos los clientes: la identidad del cliente final se verifica por la pareja número de pedido/devolución + email, no por sesión.

Modo de pruebas

Si API_TEST_HEADER y API_TEST_HEADER_VALUE están definidas y NODE_ENV !== 'production', fetchAuth añade esa cabecera (X-Test-Mode: true). En robo-api, el TestModeFilter la interpreta y redirige las escrituras a las tablas sombra (ReturnTest, ReturnLineTest, ReturnLogTest) en lugar de a las de producción. Es lo que permite crear devoluciones de prueba sin contaminar datos reales.

3. Integración con Salesforce Marketing Cloud

app/lib/marketingCloud.tsx implementa un cliente mínimo:

  • Token: POST ${MC_AUTH_URL} con grant_type: client_credentials, client_id, client_secret. Cacheado en memoria con su expires_in (sin buffer).
  • Petición: marketingCloudRequest(endpoint, options) sobre MC_API_URL con el bearer y Content-Type: application/json. Lanza MC API error: <status> - <texto> si la respuesta no es OK.

/api/trigger-journey publica un evento de entrada al journey:

POST ${MC_API_URL}/interaction/v1/events
{
ContactKey: data.EmailAddress,
EventDefinitionKey: MC_EVENT_KEY,
Data: { …payload de la devolución… }
}

:::info Protección en entornos no productivos Si NODE_ENV !== 'production', el handler sobrescribe data.EmailAddress con TEST_EMAIL antes de enviar el evento. Así, ninguna prueba en local o en un entorno de desarrollo puede enviar un email a un cliente real. Nótese que el ContactKey también pasa a ser ese email de prueba. :::

El payload que se envía lo construye ThankYouPage (ver Flujo de devolución); incluye pdfUrl como URL absoluta con el dominio de producción hardcodeado.

4. Diagrama de integraciones

sequenceDiagram
participant C as Cliente
participant N as Next.js (BFF)
participant A as Auth0
participant R as robo-api
participant M as Marketing Cloud

C->>N: POST /api/get-order {order, email}
N->>A: POST /oauth/token (password, scope customer)
A-->>N: access_token (cacheado)
N->>R: POST /order/info + Bearer
R-->>N: pedido
N-->>C: pedido (líneas con UUID)

C->>N: POST /api/set-return {refund}
N->>R: POST /order/create-return
R-->>N: return_name_id (HWRET…)
N-->>C: devolución creada

C->>N: POST /api/get-pdf-url
N-->>C: /doc/<base64url>.<hmac>
C->>N: POST /api/trigger-journey
N->>M: POST /interaction/v1/events
M-->>N: 200