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 interna | Método | Endpoint de robo-api | Función |
|---|---|---|---|
/api/get-order | POST | /order/info | Busca el pedido por order + email (envía is_customer: true) y asigna un crypto.randomUUID() a cada línea |
/api/get-return-reasons | GET | /return-reason/info | Motivos de devolución; filtra enabled === true |
/api/get-return-methods | POST | /return-method/search | Métodos por país (countryCode obligatorio); filtra enabled === true |
/api/set-return | POST | /order/create-return | Crea la devolución; transforma el objeto Refund al payload de robo-api |
/api/get-return | POST | /return/info | Detalle de una devolución por return_name_id + email |
/api/get-return-status | POST | /return-status/info | Catálogo de estados de devolución con traducciones |
/api/get-return-line-status | POST | /return-line-status/info | Catálogo de estados de línea con traducciones |
/api/get-pdf-url | POST | — (local) | Firma y devuelve la URL de /doc/[data] |
/api/get-pdf-status-url | POST | — (local) | Firma y devuelve la URL de /status/[data] |
/api/trigger-journey | POST | — (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-orderyget-returnvalidan los campos obligatorios y devuelven mensajes ya traducidos usandogetTranslationsdenext-intlen servidor (Form.error.*,FormSearchOrder.*,FormRetrieveCase.*). El cliente solo tiene que mostrardata.erroren un toast. get-orderdistingue el 400 de robo-api (pedido existente pero no procesado todavía →FormSearchOrder.errorNotProcessed) del resto de errores (→FormSearchOrder.error).set-returnsolo reenvía de cada línea:sku,price,price_original,reason.id_return_reasonyreason.extra_info; másorder_id,return_method.{id_return_method, price}ysfsc_user_id.- Los helpers de
lib/returns/*(fetchReturn,fetchReturnStatus,fetchReturnLineStatus) lanzan errores con código, del tipoRETURN_FETCH_FAILED_<status>, reutilizables tanto desde/apicomo 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 aSCOPE_customeren suSecurityConfig, 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 cabeceraAuthorization: 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}congrant_type: client_credentials,client_id,client_secret. Cacheado en memoria con suexpires_in(sin buffer). - Petición:
marketingCloudRequest(endpoint, options)sobreMC_API_URLcon el bearer yContent-Type: application/json. LanzaMC 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