← Arquitectura por épica

FT-PRD-10 · Catalogación por API del proveedor o seller

Arquitectura del Nuevo PIM por épica · corte del 18-oct-2026

Propuesta del TL: no sustituye la spec de cada épica

Actualizado el 18-oct-2026. Primera versión de la arquitectura de esta épica.

Qué responde. Cómo funciona por dentro FT-PRD-10: qué piezas participan, en qué orden hablan, qué APIs hay que construir con su request y su response, y qué le entrega a la épica siguiente.

Para quién. Los equipos que van a construir la épica, QA y arquitectura.

Estado. [Propuesta] del TL del Nuevo PIM, 18-oct-2026, construida sobre ADR-12. La spec de cada épica dice el qué; estas páginas, el cómo.

Fuente. docs/arquitectura/por-epica/epicas/FT-PRD-10.json, generada con generar.py; la ficha de la épica es trazabilidad/features/FT-PRD-10-catalogacion-por-api-del-proveedor.md.

En 30 segundos

Un proveedor o seller con integración puede mandar sus productos desde su propio sistema, sin capturarlos a mano. Entra por el gateway de terceros con credenciales propias y límite de llamadas, consulta el árbol y la plantilla en JSON, manda un producto o un lote y recibe avisos firmados de lo que pasa con cada uno. Por dentro es la misma API de producto y son las mismas reglas del portal.

  • Módulo dueño: MS-02 Producto. También participan: MS-13 Identidad y acceso, MS-01 Catálogo, MS-06 Evaluación, MS-11 Activos digitales, MS-14 Avisos y ayuda, MS-15 IA y enriquecimiento.
  • Etapa 0 · Entrada. Recibe «PE-C · Catálogo vigente» y entrega «PE-1 · Propuesta en Borrador».
  • APIs: construye 11 y usa 22 que construyen otras épicas.
  • Eventos: publica 3 y consume 7.

1. Dónde encaja

Recibe

DeQué
FT-USR-03 · Control de acceso por API para tercerosEl tercero registrado en MS-13 con sus credenciales de cliente, negocios, tiendas, alcances y límites; una suspensión vale desde la siguiente llamada.
FT-FLU-05 · Reglas de negocio en la carga masivaLas mismas reglas de lista negra, coincidencias y decisión por negocio de la carga masiva, para los lotes.
FT-FLU-04 · Carga masiva de productos por archivoEl trabajo de carga asíncrona con resultado por producto, que atiende los lotes.
FT-ARQ-01 · Núcleo headlessLa API única de producto, con el alta completa en un paso y el envío al confirmar.
PE-C · Catálogo vigenteEl árbol de plantillas y la vista efectiva por negocio que el gateway publica en JSON.

Entrega

AQué
PE-1 · Propuesta en BorradorLa propuesta nace en Borrador con origen PARTNER_API, su externalRef y su dueño, con la evaluación de MS-06 guardada; si está completa, se envía a revisión en la misma confirmación.
FT-INT-05 · Multioferta y stock outCuando ya existe: el SKU sobre el que puede ofertar el seller y la acción (multioferta o stock out), sin propuesta viva.
FT-IA-05 · Enriquecimiento continuo después de crear el SKU y después…Los valores que mandó el proveedor, marcados con origen PARTNER_API por campo, para que el enriquecimiento sólo busque los que faltan.

Cambios de estado que hace

TransiciónDe → aCuándo
T01Inicio → BorradorEl proveedor o seller guarda por primera vez (pantalla, archivo, plantilla en línea o API).
T03Borrador → En revisiónEnvía con los obligatorios completos.

Tareas que abre o cierra: Validación automática, Corrección.

2. Diagrama de contexto

Quién participa y cómo se conecta. Las pantallas llegan por el BFF del portal, que valida el token y compone; cada módulo vuelve a validar el token y decide sus permisos con los roles de MS-13.

🟩 Verde: nuevo, se construye · 🟦 Azul: ya existe y se queda, se reutiliza su código · 🟧 Naranja: temporal o se retira (se apaga en R3) · ⬜ Gris: sistema externo · ★ módulo dueño

Sistemas externos

Nuevo PIM · un solo sistema

Pantallas y sistemas

Pide un token con sus credenciales de…

Enviar un producto
Árbol de catalogación
y 5 más

Tercero de un cliente de API

Identificar un producto antes del alta
Armar la familia en la captura guiada
y 5 más

Evaluar una propuesta
Evaluar los renglones de una carga ma…

Vista efectiva de una plantilla por n…

PRODUCT_CREATED
STATUS_CHANGED

STATUS_CHANGED

Entrega el aviso firmado al webhook d…
Entrega batch.completed al webhook
y 1 más

Selector de plantillas
Vista efectiva de una plantilla por n…

Cambiar mis preferencias de avisos

Mandar un aviso explícito

permisos

Sistemas de proveedores y sellers

Gateway de terceros /partner/v1

MS-13 Identidad y acceso

★ MS-02 Producto

MS-01 Catálogo

MS-06 Evaluación

MS-14 Avisos y ayuda

Base pim

Eventos

Proveedor de identidad

Contexto de FT-PRD-10

3. Diagrama de flujo

El camino principal, paso por paso. Cuando una pantalla llama a un módulo se ven dos flechas: la pantalla al BFF y el BFF al módulo. Los eventos salen del outbox del módulo después de guardar; quien los consume ignora los repetidos.

MS-14 Avisos y ayudaEventosBase·pimMS-01 CatálogoMS-06 EvaluaciónMS-02 ProductoMS-13 Identidad y accesoProveedor de identidadSistemas de proveedores y sellersMS-14 Avisos y ayudaEventosBase·pimMS-01 CatálogoMS-06 EvaluaciónMS-02 ProductoMS-13 Identidad y accesoProveedor de identidadSistemas de proveedores y sellersGateway1. Pide un token con sus credenciales de cliente2. Manda el producto completo con su llave de idempotenciaPOST /partner/v1/proposals3. Revisa que el tercero esté activo y en su límiteGET /internal/identity/partners/by-client/{clientId}4. Pide identificar el producto antes del altaPOST /api/v2/products/identifications5. Pide la evaluación de lista negra y coincidenciasPOST /api/v2/evaluations6. Pide el alta completa con la evaluación y origen PARTNER_APIPOST /api/v2/products/guided/plans7. Valida contra la vista efectiva de la plantillaGET /api/v2/taxonomies/PRODUCT/nodes/{id}/effective8. Confirma con envío si está completaPOST /api/v2/product-plans/{planId}/apply9. Crea la propuesta y la envía a revisión10. Avisa la propuesta nueva con origen PARTNER_APIPRODUCT_CREATED11. Lee el recibo y responde 201 al terceroGET /api/v2/product-receipts/{requestId}12. Entrega el cambio de estado para avisarSTATUS_CHANGED13. Entrega el aviso firmado al webhook del terceroGateway
Flujo principal de FT-PRD-10
Los pasos en texto
PasoDeAQué haceAPI o evento
1Sistemas de proveedores y sellersProveedor de identidadPide un token con sus credenciales de cliente—
2Sistemas de proveedores y sellersGateway de terceros /partner/v1Manda el producto completo con su llave de idempotenciaAPI-GW-001
3Gateway de terceros /partner/v1MS-13 Identidad y accesoRevisa que el tercero esté activo y en su límiteAPI-13-012
4Gateway de terceros /partner/v1MS-02 ProductoPide identificar el producto antes del altaAPI-02-202
5MS-02 ProductoMS-06 EvaluaciónPide la evaluación de lista negra y coincidenciasAPI-06-001
6Gateway de terceros /partner/v1MS-02 ProductoPide el alta completa con la evaluación y origen PARTNER_APIAPI-02-006
7MS-02 ProductoMS-01 CatálogoValida contra la vista efectiva de la plantillaAPI-01-028
8Gateway de terceros /partner/v1MS-02 ProductoConfirma con envío si está completaAPI-02-057
9MS-02 ProductoBase pimCrea la propuesta y la envía a revisión—
10MS-02 ProductoEventosAvisa la propuesta nueva con origen PARTNER_APIcatalog.product.changed/PRODUCT_CREATED
11Gateway de terceros /partner/v1MS-02 ProductoLee el recibo y responde 201 al terceroAPI-02-025
12EventosMS-14 Avisos y ayudaEntrega el cambio de estado para avisarcatalog.product.changed/STATUS_CHANGED
13MS-14 Avisos y ayudaSistemas de proveedores y sellersEntrega el aviso firmado al webhook del tercero—

3.1 Prepara la integración: árbol, plantilla y avisos

MS-14 Avisos y ayudaMS-01 CatálogoSistemas de proveedores y sellersMS-14 Avisos y ayudaMS-01 CatálogoSistemas de proveedores y sellersGateway1. Busca la categoría «teclado» en el árbolGET /partner/v1/categories2. Busca hojas con su ruta legibleGET /api/v2/structures/{id}/leaves3. Pide la plantilla de la hoja en JSONGET /partner/v1/templates/{templateId}4. Lee la vista efectiva vigente para su negocioGET /api/v2/taxonomies/PRODUCT/nodes/{id}/effective5. Registra su webhook y los eventos que quierePOST /partner/v1/webhooks6. Guarda la suscripción como canal de avisosPUT /api/v2/notifications/preferencesGateway
Prepara la integración: árbol, plantilla y avisos

3.2 Lote de hasta 1,000 productos

MS-14 Avisos y ayudaBase·pimMS-06 EvaluaciónMS-02 ProductoSistemas de proveedores y sellersMS-14 Avisos y ayudaBase·pimMS-06 EvaluaciónMS-02 ProductoSistemas de proveedores y sellersGateway1. Manda un lote de un solo negocioPOST /partner/v1/batches2. Lo sube como carga con creación automáticaPOST /api/v2/product-imports3. Evalúa los productos del lote por bloquePOST /api/v2/evaluations/batches4. Crea y envía los válidos, uno por uno5. Pide avisar que el lote terminóPOST /internal/notifications/messages6. Entrega batch.completed al webhook7. Consulta el resultado por externalRefGET /partner/v1/batches/{batchId}/items8. Lee el resultado por renglónGET /api/v2/product-imports/{id}Gateway
Lote de hasta 1,000 productos

3.3 Corrige sólo el campo que falló

EventosMS-02 ProductoSistemas de proveedores y sellersMS-14 Avisos y ayudaEventosMS-02 ProductoSistemas de proveedores y sellersMS-14 Avisos y ayudaGateway1. Avisa «requiere corrección» con el motivo por campo2. Manda sólo el campo corregidoPATCH /partner/v1/proposals/{proposalId}3. Pide el plan del cambio con reenvíoPOST /api/v2/products/{id}/values/plans4. Confirma: cambia ese campo y conserva los demásPOST /api/v2/product-plans/{planId}/apply5. Avisa que volvió a En revisiónSTATUS_CHANGEDGateway
Corrige sólo el campo que falló

4. Si algo sale mal

  • El tercero está suspendido o no tiene límites configurados. El gateway responde 403 PARTNER_SUSPENDED o LIMITS_NOT_CONFIGURED desde la siguiente llamada, porque refresca su copia del registro con PARTNER_CHANGED; los demás terceros siguen sin cambio.
  • Pasa su límite por minuto o su tope diario. Responde 429 RATE_LIMITED o DAILY_QUOTA_EXCEEDED con Retry-After; el contador es por tercero, así que el PIM sigue atendiendo a los demás y al portal.
  • El producto ya existe o la marca está vetada. La identificación lo dice en línea antes de crear nada: 409 ALREADY_EXISTS con la acción y el enlace a offer-targets, o 422 BRAND_BLOCKED, que es final.
  • Falta un obligatorio o un valor no está en la lista. El plan lo rechaza antes de crear nada: 422 VALIDATION_ERROR con producto, variante, ruta y atributo. Se corrige y se reenvía con el mismo externalRef.
  • El webhook del tercero no responde. MS-14 reintenta con espera creciente, de 1 minuto a 24 horas; después la entrega queda fallida y el aviso sigue disponible en /partner/v1/events.

5. APIs

Las que construye esta épica (11)

POST /partner/v1/proposals · Enviar un producto
CampoValor
APIAPI-GW-001 · Gateway de terceros /partner/v1
Para quéEl sistema de un proveedor o seller manda un producto completo con sus variantes. El gateway pide a MS-02 identificarlo (lista negra y «¿ya existe?»); si es nuevo, lo traduce a la misma alta completa de MS-02 (API-02-006 sin productId, con origen PARTNER_API, el evaluationId y envío al confirmar), lee el recibo y responde en línea: la propuesta quedó creada y enviada a revisión, o no se creó nada y la respuesta dice qué producto y qué campo fallaron.
En esta épicaEnviar un producto, en línea hasta la identificación
Quién la llamaSistemas de proveedores y sellers
PermisoTercero activo en el registro de MS-13, con el alcance proposals.write y el negocio entre los suyos
CabecerasAuthorization, X-Request-Id, Idempotency-Key
También la usanFT-ACT-03, FT-ARQ-01, FT-USR-03

Request

{
  "business": "MKP",
  "externalRef": "SEL-001-PB20",
  "templateId": "EU4-0412",
  "templateVersion": 7,
  "base": {
    "title": "Batería externa de 20,000 mAh con carga rápida USB-C",
    "brandCode": "MARCA01",
    "model": "PB-20",
    "description": "Batería portátil con dos salidas"
  },
  "attributes": [
    {
      "code": "CAPACIDAD",
      "value": 20000,
      "unit": "MAH"
    },
    {
      "code": "TIPO_CONECTOR",
      "values": [
        "USB_C",
        "USB_A"
      ]
    },
    {
      "code": "MATERIAL",
      "values": [
        "PLASTICO"
      ]
    }
  ],
  "variants": [
    {
      "externalRef": "SEL-001-PB20-NEG",
      "ean": "7501234567930",
      "axes": {
        "COLOR": "NEGRO"
      },
      "images": [
        {
          "url": "<URL pública de la imagen en el servidor del seller>",
          "type": "PRINCIPAL",
          "order": 1
        }
      ]
    },
    {
      "externalRef": "SEL-001-PB20-BLA",
      "ean": "7501234567947",
      "axes": {
        "COLOR": "BLANCO"
      },
      "images": [
        {
          "url": "<URL pública de la imagen en el servidor del seller>",
          "type": "PRINCIPAL",
          "order": 1
        }
      ]
    }
  ],
  "logistics": {
    "package": {
      "heightCm": 3,
      "widthCm": 8,
      "lengthCm": 15,
      "grossWeightKg": 0.45,
      "netWeightKg": 0.4
    }
  }
}

Response · 201

{
  "success": true,
  "data": {
    "proposalId": "PRD-0004890",
    "externalRef": "SEL-001-PB20",
    "business": "MKP",
    "status": "IN_APPROVAL",
    "correctionDueAt": null,
    "variants": [
      {
        "externalRef": "SEL-001-PB20-NEG",
        "variantId": "VAR-0004890-01"
      },
      {
        "externalRef": "SEL-001-PB20-BLA",
        "variantId": "VAR-0004890-02"
      }
    ],
    "links": {
      "self": "/partner/v1/proposals/PRD-0004890"
    }
  }
}

Errores

HTTPCódigoCuándo
409ALREADY_EXISTSLa identificación dice que el producto ya existe: no se crea nada; trae matchType, allowedAction, sku y el enlace a offer-targets
422BRAND_BLOCKEDLa marca está en la lista negra de ese negocio: no se crea nada y es final
422VALIDATION_ERROREl plan encuentra un obligatorio que falta o un valor fuera de lista; details trae itemRef, variantRef, path, attribute y code. No se crea nada
422TEMPLATE_VERSION_OUTDATEDMandó una versión vieja de la plantilla y la vigente pide algo que no trae
409EXTERNAL_REF_EXISTSYa tiene otra propuesta con ese externalRef
403PARTNER_SUSPENDEDEl tercero está suspendido o revocado en el registro de MS-13
429RATE_LIMITEDPasó su límite por minuto; trae Retry-After
429DAILY_QUOTA_EXCEEDEDPasó su tope diario de productos nuevos
GET /partner/v1/batches/{batchId}/items · Resultado de un lote por producto
CampoValor
APIAPI-GW-002 · Gateway de terceros /partner/v1
Para quéDice el avance de un lote y qué pasó con cada producto, correlacionado por su externalRef y nunca por posición: creado (CREATED), por corregir sin crear nada (CORRECTION_REQUIRED), rechazado (REJECTED) o ya existe (ALREADY_EXISTS) con la acción que le toca.
En esta épicaResultado de un lote por producto, por externalRef
Quién la llamaSistemas de proveedores y sellers
PermisoEl tercero dueño del lote, con el alcance proposals.write o catalog.read
CabecerasAuthorization, X-Request-Id
ParámetrosbatchId = imp-20261018-0043, result = None, page = 1, size = 200

Request

null

Response · 200

{
  "success": true,
  "data": {
    "batchId": "imp-20261018-0043",
    "status": "DONE_WITH_ERRORS",
    "summary": {
      "received": 3,
      "created": 1,
      "correctionRequired": 1,
      "rejected": 0,
      "alreadyExists": 1
    },
    "items": [
      {
        "externalRef": "SEL-001-PB20",
        "result": "CREATED",
        "proposalId": "PRD-0004891",
        "status": "IN_APPROVAL"
      },
      {
        "externalRef": "SEL-001-PB10",
        "result": "CORRECTION_REQUIRED",
        "errors": [
          {
            "variantRef": "SEL-001-PB10-NEG",
            "path": "/items/1/variants/0/ean",
            "code": "EAN_CHECK_DIGIT",
            "message": "El dígito verificador no corresponde a un EAN-13"
          }
        ]
      },
      {
        "externalRef": "SEL-001-CB01",
        "result": "ALREADY_EXISTS",
        "matchType": "EAN",
        "allowedAction": "MULTI_OFFER",
        "sku": "1000004812",
        "links": {
          "offerTarget": "/partner/v1/offer-targets/1000004812"
        }
      }
    ],
    "page": 1,
    "size": 200,
    "total": 3
  }
}

Errores

HTTPCódigoCuándo
404NOT_FOUNDEl lote no existe o no es del tercero
GET /partner/v1/offer-targets/{sku} · Sobre qué SKU ofertar
CampoValor
APIAPI-GW-003 · Gateway de terceros /partner/v1
Para quéCuando el producto ya existe, dice sobre qué SKU puede ofertar el seller, si ya tiene sus datos base y si el portal de ofertas ya lo acusó. Es la misma respuesta de API-02-404 en el contrato de terceros; no tiene efectos y la oferta se crea en Mirakl.
En esta épicaSobre qué SKU ofertar cuando ya existe
Quién la llamaSistemas de proveedores y sellers
PermisoSeller con el alcance catalog.read
CabecerasAuthorization, X-Request-Id
Parámetrossku = 1000004812
También la usanFT-INT-05

Request

null

Response · 200

{
  "success": true,
  "data": {
    "sku": "1000004812",
    "productName": "Batería externa de 20,000 mAh",
    "offerType": "MULTI_OFFER",
    "miraklStatus": "ACKNOWLEDGED",
    "acknowledgedAt": "2026-10-16T17:05:12Z"
  }
}

Errores

HTTPCódigoCuándo
404NOT_FOUNDEl SKU no existe
403BUSINESS_NOT_ALLOWEDEse SKU no admite oferta del seller (por ejemplo, sólo existe en Suburbia)
POST /partner/v1/batches · Enviar un lote
CampoValor
APIAPI-GW-004 · Gateway de terceros /partner/v1
Para quéManda hasta 1,000 productos de un mismo negocio en segundo plano: responde al momento con el ID del lote y el resultado por producto llega después; cada producto es su propia unidad, así que uno malo no tumba el lote.
En esta épicaEnviar un lote de hasta 1,000 productos
Quién la llamaSistemas de proveedores y sellers
PermisoTercero activo con el alcance proposals.write y el negocio entre los suyos
CabecerasAuthorization, X-Request-Id, Idempotency-Key

Request

{
  "business": "MKP",
  "items": [
    {
      "externalRef": "SEL-001-PB20",
      "templateId": "EU4-0412",
      "templateVersion": 7,
      "base": {
        "title": "Batería externa de 20,000 mAh con carga rápida USB-C",
        "brandCode": "MARCA01",
        "model": "PB-20"
      },
      "attributes": [
        {
          "code": "CAPACIDAD",
          "value": 20000,
          "unit": "MAH"
        }
      ],
      "variants": [
        {
          "externalRef": "SEL-001-PB20-NEG",
          "ean": "7501234567930",
          "axes": {
            "COLOR": "NEGRO"
          }
        }
      ]
    }
  ]
}

Response · 202

{
  "success": true,
  "data": {
    "batchId": "imp-20261018-0043",
    "received": 1,
    "status": "VALIDATING",
    "links": {
      "self": "/partner/v1/batches/imp-20261018-0043/items"
    }
  }
}

Errores

HTTPCódigoCuándo
400VALIDATION_ERROREl sobre no sirve: JSON mal formado o falta el negocio
413LIMIT_EXCEEDEDMás de 1,000 productos: se rechaza completo, nunca se trunca
429RATE_LIMITEDYa tiene dos lotes en proceso o pasó su límite por minuto
403PARTNER_SUSPENDEDEl tercero está suspendido o revocado
GET /partner/v1/categories · Árbol de catalogación
CampoValor
APIAPI-GW-005 · Gateway de terceros /partner/v1
Para quéDa el árbol para ubicar el producto y buscar por palabra: cada categoría con su ID, su nombre, su ruta completa y si es una hoja que admite productos (con su plantilla). No incluye las desligadas ni las retiradas.
En esta épicaÁrbol de catalogación con búsqueda por palabra
Quién la llamaSistemas de proveedores y sellers
PermisoTercero activo con el alcance catalog.read
CabecerasAuthorization, X-Request-Id
Parámetrosq = teclado, parentId = None, business = MKP, page = 1, size = 50

Request

null

Response · 200

{
  "success": true,
  "data": {
    "items": [
      {
        "categoryId": "EU4-0611",
        "name": "Teclados",
        "path": "Tecnología > Computación > Accesorios > Teclados",
        "level": 4,
        "isLeaf": true,
        "templateId": "EU4-0611"
      },
      {
        "categoryId": "EU4-0612",
        "name": "Teclados musicales",
        "path": "Entretenimiento > Instrumentos > Teclados musicales",
        "level": 3,
        "isLeaf": true,
        "templateId": "EU4-0612"
      }
    ],
    "page": 1,
    "size": 50,
    "total": 2
  }
}

Errores

HTTPCódigoCuándo
404NOT_FOUNDLa categoría padre no existe
GET /partner/v1/templates/{templateId} · Plantilla de una categoría en JSON
CampoValor
APIAPI-GW-006 · Gateway de terceros /partner/v1
Para quéDa la vista efectiva vigente de una plantilla para un negocio: cada atributo con su tipo, su lista de valores, si es obligatorio, recomendado u opcional y si sólo se acepta en el alta; los ejes de variante, las reglas de imagen y la versión.
En esta épicaPlantilla de una categoría en JSON, con los campos sólo de alta
Quién la llamaSistemas de proveedores y sellers
PermisoTercero activo con el alcance catalog.read y el negocio entre los suyos
CabecerasAuthorization, X-Request-Id
ParámetrostemplateId = EU4-0412, business = MKP

Request

null

Response · 200

{
  "success": true,
  "data": {
    "templateId": "EU4-0412",
    "name": "Baterías portátiles",
    "version": 7,
    "effectiveFrom": "2026-10-01T00:00:00Z",
    "business": "MKP",
    "attributes": [
      {
        "code": "CAPACIDAD",
        "name": "Capacidad",
        "type": "NUMBER",
        "unit": "MAH",
        "level": "REQUIRED",
        "acceptedOnlyAtCreation": false,
        "variantLevel": false
      },
      {
        "code": "TIPO_CONECTOR",
        "name": "Tipo de conector",
        "type": "LIST",
        "multivalued": true,
        "level": "REQUIRED",
        "acceptedOnlyAtCreation": false,
        "values": [
          {
            "code": "USB_C",
            "label": "USB-C"
          },
          {
            "code": "USB_A",
            "label": "USB-A"
          }
        ]
      },
      {
        "code": "MARCA",
        "name": "Marca",
        "type": "LIST",
        "level": "REQUIRED",
        "acceptedOnlyAtCreation": true
      },
      {
        "code": "MATERIAL",
        "name": "Material",
        "type": "LIST",
        "level": "RECOMMENDED",
        "acceptedOnlyAtCreation": false,
        "values": [
          {
            "code": "PLASTICO",
            "label": "Plástico"
          },
          {
            "code": "ALUMINIO",
            "label": "Aluminio"
          }
        ]
      }
    ],
    "variantAxes": [
      "COLOR"
    ],
    "imageRules": {
      "min": 1,
      "max": 20,
      "principal": {
        "background": "BLANCO",
        "minSidePx": 1000
      }
    },
    "calculatedFields": [
      "TITULO_WEB"
    ]
  }
}

Errores

HTTPCódigoCuándo
404NOT_FOUNDLa plantilla no existe o está retirada
422VALIDATION_ERRORLa categoría no es una hoja: no admite productos
403BUSINESS_NOT_ALLOWEDEl negocio no es del tercero
POST /partner/v1/products/lookup · ¿Ya existe?
CampoValor
APIAPI-GW-007 · Gateway de terceros /partner/v1
Para quéAntes de mandar, dice por EAN o por marca y modelo si el producto ya existe y qué acción le toca al seller: crear propuesta, multioferta, oferta con stock out o nada. No dice qué seller es dueño.
En esta épica¿Ya existe? por EAN o por marca y modelo, antes de mandar
Quién la llamaSistemas de proveedores y sellers
PermisoTercero activo con el alcance catalog.read
CabecerasAuthorization, X-Request-Id

Request

{
  "business": "MKP",
  "eans": [
    "7501234567893"
  ],
  "items": [
    {
      "brandCode": "MARCA01",
      "model": "PB-20"
    }
  ]
}

Response · 200

{
  "success": true,
  "data": {
    "results": [
      {
        "key": "7501234567893",
        "exists": true,
        "matchType": "EAN",
        "catalog": "LIVERPOOL",
        "sku": "1000004812",
        "ownedByYou": false,
        "allowedAction": "STOCK_OUT_OFFER",
        "links": {
          "offerTarget": "/partner/v1/offer-targets/1000004812"
        }
      },
      {
        "key": "MARCA01|PB-20",
        "exists": false,
        "allowedAction": "CREATE_PROPOSAL"
      }
    ]
  }
}

Errores

HTTPCódigoCuándo
400VALIDATION_ERRORUn EAN no tiene de 8 a 14 dígitos o su dígito verificador no corresponde; más de 100 llaves
PATCH /partner/v1/proposals/{proposalId} · Corregir sólo lo que falló
CampoValor
APIAPI-GW-008 · Gateway de terceros /partner/v1
Para quéEl tercero manda sólo los campos que corrige y el PIM conserva los demás; si la propuesta tenía una corrección pendiente, se reenvía a revisión en la misma confirmación. Un campo que sólo se acepta en el alta se rechaza con el campo y el motivo.
En esta épicaCorregir sólo los campos que fallaron
Quién la llamaSistemas de proveedores y sellers
PermisoEl tercero dueño de la propuesta, con el alcance proposals.write
CabecerasAuthorization, X-Request-Id, Idempotency-Key, If-Match
ParámetrosproposalId = PRD-0004890

Request

{
  "attributes": [
    {
      "code": "TIPO_CONECTOR",
      "values": [
        "USB_C"
      ]
    }
  ],
  "resubmit": true
}

Response · 202

{
  "success": true,
  "data": {
    "proposalId": "PRD-0004890",
    "requestId": "req-3c80f1",
    "status": "ACCEPTED",
    "links": {
      "proposal": "/partner/v1/proposals/PRD-0004890"
    }
  }
}

Errores

HTTPCódigoCuándo
422READ_ONLY_FIELDEl campo sólo se acepta en el alta, o es SKU, EAN o negocio
409VERSION_CONFLICTLa propuesta cambió desde la versión que trae If-Match
409NOT_EDITABLE_IN_STATUSLa propuesta ya no se puede corregir por API en su estado
423LOCKEDLiverpool la está revisando en ese momento
403NOT_CONTENT_OWNEREl producto no es del tercero
GET /partner/v1/proposals/{proposalId} · Estado de una propuesta
CampoValor
APIAPI-GW-009 · Gateway de terceros /partner/v1
Para quéDa el estado que ve el tercero, los motivos por campo, hasta cuándo puede corregir, el SKU de cada variante cuando ya lo tiene y el estado de entrega en los canales de venta.
En esta épicaEstado de una propuesta con motivos y canales
Quién la llamaSistemas de proveedores y sellers
PermisoEl tercero dueño de la propuesta, con el alcance catalog.read
CabecerasAuthorization, X-Request-Id
ParámetrosproposalId = PRD-0004890

Request

null

Response · 200

{
  "success": true,
  "data": {
    "proposalId": "PRD-0004890",
    "externalRef": "SEL-001-PB20",
    "business": "MKP",
    "status": "CORRECTION_REQUIRED",
    "version": 4,
    "correctionDueAt": "2026-12-17T15:04:05Z",
    "reasons": [
      {
        "attribute": "TIPO_CONECTOR",
        "code": "VALUE_NOT_IN_LIST",
        "area": "VALIDACION_AUTOMATICA",
        "message": "Manda el código de la lista"
      }
    ],
    "requiredActions": [
      "FIX_FIELDS"
    ],
    "variants": [
      {
        "externalRef": "SEL-001-PB20-NEG",
        "variantId": "VAR-0004890-01",
        "sku": null,
        "ean": "7501234567930"
      }
    ],
    "channels": [
      {
        "channel": "TIENDA",
        "state": "PENDING"
      },
      {
        "channel": "MARKETPLACE",
        "state": "PENDING"
      }
    ]
  }
}

Errores

HTTPCódigoCuándo
404NOT_FOUNDLa propuesta no existe o no es del tercero
POST /partner/v1/webhooks · Suscribirse a los avisos
CampoValor
APIAPI-GW-010 · Gateway de terceros /partner/v1
Para quéEl tercero registra el punto de su sistema donde quiere recibir avisos firmados y qué eventos le interesan. La suscripción la guarda MS-14 como un canal más de avisos; el secreto para validar la firma se muestra una sola vez.
En esta épicaSuscribirse a los avisos por webhook
Quién la llamaSistemas de proveedores y sellers
PermisoTercero activo con el alcance webhooks.manage
CabecerasAuthorization, X-Request-Id, Idempotency-Key

Request

{
  "endpoint": "<dirección HTTPS del sistema del seller>",
  "events": [
    "proposal.created",
    "proposal.correction_required",
    "proposal.rejected",
    "proposal.accepted",
    "product.sku_created",
    "product.published",
    "batch.completed"
  ],
  "description": "Orquestador de catálogo"
}

Response · 201

{
  "success": true,
  "data": {
    "webhookId": "whk-31a0",
    "status": "ACTIVE",
    "events": [
      "proposal.created",
      "proposal.correction_required",
      "proposal.rejected",
      "proposal.accepted",
      "product.sku_created",
      "product.published",
      "batch.completed"
    ],
    "secret": "(se muestra una sola vez)"
  }
}

Errores

HTTPCódigoCuándo
400VALIDATION_ERRORLa dirección no es HTTPS o un evento no existe
403SCOPE_MISSINGEl token no trae el alcance webhooks.manage
GET /partner/v1/events · Avisos por consulta
CampoValor
APIAPI-GW-011 · Gateway de terceros /partner/v1
Para quéLos mismos avisos que salen por webhook, en orden y por cursor, de los últimos 30 días: es el respaldo para quien no recibe webhooks o perdió alguno.
En esta épicaAvisos por consulta, de respaldo del webhook
Quién la llamaSistemas de proveedores y sellers
PermisoTercero activo con el alcance catalog.read
CabecerasAuthorization, X-Request-Id
Parámetrossince = 2026-10-18T00:00:00Z, types = proposal.correction_required,proposal.accepted, cursor = c-00A7

Request

null

Response · 200

{
  "success": true,
  "data": {
    "items": [
      {
        "eventId": "evt-01JA7Q4M2K",
        "type": "proposal.correction_required",
        "occurredAt": "2026-10-18T17:05:12Z",
        "business": "MKP",
        "proposalId": "PRD-0004890",
        "externalRef": "SEL-001-PB20",
        "status": "CORRECTION_REQUIRED",
        "version": 4,
        "reasons": [
          {
            "attribute": "TIPO_CONECTOR",
            "code": "VALUE_NOT_IN_LIST"
          }
        ]
      }
    ],
    "nextCursor": "c-00A8"
  }
}

Errores

HTTPCódigoCuándo
400VALIDATION_ERROREl cursor no es válido o pide más de 30 días

Las que usa y construye otra épica (22)

Su request y su response están en la página de la épica que la construye.

APIMétodo y rutaPara qué, aquíLa construye
API-13-012GET /internal/identity/partners/by-client/{clientId}El tercero de un cliente de API, con su estado y sus límitesFT-USR-03 · Control de acceso por API para terceros
API-02-006POST /api/v2/products/guided/plansAlta completa en un paso con origen PARTNER_API y envío al confirmarFT-PRD-07 · Captura guiada por pasos con los mínimos primero
API-01-028GET /api/v2/taxonomies/PRODUCT/nodes/{id}/effectiveVista efectiva de la plantilla por negocioFT-PLT-06 · Configuración de atributos por plantilla y por negocio…
API-01-022GET /api/v2/structures/{id}/leavesHojas del árbol con su ruta legibleFT-PLT-05 · Taxonomía de plantillas por familia, metadatos de…
API-02-057POST /api/v2/product-plans/{planId}/applyConfirmar el planFT-FLU-01 · Motor de estados configurable con dos carreteras y reglas…
API-06-001POST /api/v2/evaluationsEvaluación de lista negra, coincidencias y decisión por negocioFT-REF-02 · Blacklist de Marketplace por marca, negocio y grupo de…
API-02-025GET /api/v2/product-receipts/{requestId}Recibo de la confirmación, para responder en líneaFT-FLU-01 · Motor de estados configurable con dos carreteras y reglas…
API-02-046POST /api/v2/product-importsCarga asíncrona de los lotes (source PARTNER_BATCH)FT-FLU-04 · Carga masiva de productos por archivo
API-06-002POST /api/v2/evaluations/batchesEvaluar los productos del lote por bloqueFT-FLU-05 · Reglas de negocio en la carga masiva
API-02-048GET /api/v2/product-imports/{id}Resultado del lote por renglónFT-FLU-04 · Carga masiva de productos por archivo
API-02-012POST /api/v2/products/{id}/values/plansCambiar sólo los valores corregidos, con reenvíoFT-RAC-01 · Motor de validación en línea y candados de datos…
API-02-011POST /api/v2/products/{id}/root/plansCambiar datos generales; SKU, EAN y negocio son de sólo lecturaFT-PRD-01 · Modelo canónico de producto
API-02-042GET /api/v2/delivery-status?productId=&sku=Estado de entrega por canal, para el estado de la propuesta (API-GW-009)FT-CAT-05 · Sitios, enrutamiento y visibilidad por negocio
API-02-002GET /api/v2/products/{id}Ficha de la propuesta para el estado que ve el terceroFT-PRD-01 · Modelo canónico de producto
API-02-029GET /api/v2/workflow/comments?productIds=Motivos de rechazo por campoFT-PRD-04 · Propuesta del proveedor de Mercaderías
API-14-004PUT /api/v2/notifications/preferencesGuardar la suscripción de webhook como preferencia de canalFT-RAC-05 · Estatus del producto y motivos visibles para seller y…
API-14-005POST /internal/notifications/messagesAvisar que terminó un loteFT-RAC-05 · Estatus del producto y motivos visibles para seller y…
API-14-001GET /api/v2/notifications?unread=Los avisos del tercero, para el feed de respaldoFT-RAC-05 · Estatus del producto y motivos visibles para seller y…
API-11-006POST /api/v2/assets/from-urlRegistrar cada imagen por URL que mandó el proveedor, hasta 20 por colorFT-ACT-03 · Imágenes del seller por URL con validación y corrección…
API-15-004POST /api/v2/ai/enrichmentsEnriquecer después sólo los atributos vacíos (FT-IA-05)FT-IA-05 · Enriquecimiento continuo después de crear el SKU y después…
API-02-202POST /api/v2/products/identificationsIdentificación previa al alta, también para el «¿ya existe?» (API-GW-007)FT-FLU-02 · Alta individual de Marketplace
API-02-404GET /api/v2/offer-targets/{sku}Sobre qué SKU ofertar, detrás de offer-targets (API-GW-003)FT-INT-05 · Multioferta y stock out

6. Eventos

Publica

EventoCuándoQuién lo consume
catalog.product.changed/PRODUCT_CREATEDSe confirma una propuesta del terceroFT-ARQ-01
catalog.product.changed/STATUS_CHANGEDLa propuesta completa pasa a En revisiónFT-ACT-05, FT-ARQ-02, FT-CAT-05, FT-FLU-01, FT-IA-04, FT-PRD-02, FT-PRD-04, FT-PRD-06, FT-RAC-03, FT-RAC-05, FT-RAC-06
catalog.product.changed/PRODUCT_UPDATEDEl tercero corrige un campoFT-ACT-05, FT-ARQ-02, FT-IA-01, FT-PLT-07, FT-PRD-05, FT-RAC-06

Consume

EventoPara quéQuién lo publica
catalog.product.changed/STATUS_CHANGEDMS-14 avisa al tercero por webhook: creada, requiere corrección, aceptada o canceladaesta misma épica
catalog.product.changed/REJECTION_ADDEDMS-14 manda al tercero el motivo por campoFT-FLU-01, FT-INT-07, FT-PRD-02, FT-PRD-04, FT-PRD-05, FT-RAC-01, FT-RAC-03, FT-RAC-05
catalog.product.changed/SKU_ASSIGNEDMS-14 avisa product.sku_created con el SKU de cada varianteFT-INT-03, FT-PRD-02
catalog.delivery.result/DELIVERY_RESULTMS-14 avisa «publicado» o «falló» por canal de ventaFT-CAT-02, FT-CAT-05, FT-INT-01, FT-INT-02, FT-INT-05, FT-INT-07, FT-PRD-02
catalog.identity.changed/PARTNER_CHANGEDEl gateway refresca su copia del tercero: una suspensión vale en la siguiente llamadaFT-USR-03
catalog.validation.result/EVALUATION_DONEMS-02 sigue con el lote cuando MS-06 terminó de evaluar un bloqueFT-FLU-03, FT-FLU-05, FT-REF-03
catalog.asset.changed/ASSET_VALIDATEDMS-02 liga a su variante la URL de trabajo de cada imagen que mandó el terceroFT-ACT-01, FT-ACT-02, FT-ACT-03

7. Datos

Cada colección tiene un solo dueño, el único que escribe en ella.

ColecciónDueñoQué guardaEsta épica
productsMS-02La familia del producto con sus variantes, valores, imágenes (URL), clasificaciones, estado, tareas abiertas y rechazos.escribe
identifier_registryMS-02Unicidad de SKU y de EAN por negocio.escribe
tasksMS-02Todo el trabajo asignado: visto bueno, corrección, Gobierno de Datos, foto, secciones, QA, revisión del cambio y repoblamiento.escribe
product_versionsMS-02Foto numerada del producto en cada versión.escribe
product_jobsMS-02Trabajos asíncronos: cargas masivas de productos, edición masiva y publicación.escribe
product_receiptsMS-02El recibo de cada escritura confirmada en el producto (antes operation_receipts).escribe
product_outboxMS-02Los cambios del producto que esperan salir como evento (antes outbox).escribe
partnersMS-13El registro de terceros: proveedores y sellers que llaman por API, con su tipo, negocios, tiendas, alcances, límites y clientes (catalogación por API §3.1).lee
template_viewsMS-01La vista efectiva ya resuelta por plantilla y negocio: qué atributos pide y cuáles son obligatorios.lee
validation_resultsMS-06El resultado de cada evaluación: lista negra, coincidencias con su confianza y score.lee
notificationsMS-14Cada aviso a un usuario, proveedor o seller: canal, texto, si ya lo leyó.lee

8. Historias que cubre

HistoriaPrioridadCómo la cubre
FT-PRD-10·H1 · Alta por API con las reglas del portalP1pasos 2, 3, 4, 5, 6, 7, 8, 9, 11; flujo «Lote de hasta 1,000 productos»; API-GW-001, API-GW-004, API-GW-002, API-GW-007, API-GW-003
FT-PRD-10·H2 · Más que los mínimosP1pasos 6, 8; API-11-006, API-GW-001
FT-PRD-10·H3 · Alertas en tiempo realP2pasos 12, 13; flujo «Prepara la integración: árbol, plantilla y avisos», «Lote de hasta 1,000 productos»; API-GW-010, API-GW-011, API-GW-009
FT-PRD-10·H4 · El enriquecimiento completa lo que faltaP2API-15-004. Fuera: El enriquecimiento posterior lo hace FT-IA-05; aquí se deja el origen PARTNER_API en cada valor para que sólo busque lo vacío (D-PRD-10-5).
FT-PRD-10·H5 · Campos de alta y modificación por APIP2flujo «Corrige sólo el campo que falló», «Prepara la integración: árbol, plantilla y avisos»; API-GW-008, API-GW-006
FT-PRD-10·H6 · Consultar por API la plantilla de una categoríaP1flujo «Prepara la integración: árbol, plantilla y avisos»; API-GW-006
FT-PRD-10·H7 · Consultar por API el árbol de categoríasP2flujo «Prepara la integración: árbol, plantilla y avisos»; API-GW-005

9. Decisiones de esta épica

Las tomó el TL como arquitecto; quedan como [Propuesta] hasta que el equipo de la épica las revise.

  • D-PRD-10-1. El gateway no guarda nada: valida el token, aplica el límite por tercero con la copia en memoria del registro de MS-13 (API-13-012, refrescada con PARTNER_CHANGED) y traduce cada ruta /partner/v1 a la API v2 de los servicios, con las mismas reglas. Los lotes viven en product_jobs de MS-02; las suscripciones y las entregas de avisos, en MS-14. Por qué: Con ADR-12 cada dato tiene un dueño y el borde no tiene base. Se aparta de la propuesta de catalogación por API (T-6), que guardaba lotes, suscripciones y entregas en la API de terceros. Se apoya en ADR-12, PD-26, PD-05, RN-GEN-08.
  • D-PRD-10-2. Envío individual en línea hasta la identificación: el gateway pide a MS-02 identificar el producto (API-02-202); si es nuevo, pide el alta completa con origen PARTNER_API, el evaluationId y envío al confirmar, lee el recibo y responde 201 con la propuesta en revisión; si no, 409 ALREADY_EXISTS o 422 BRAND_BLOCKED o VALIDATION_ERROR, sin crear nada. Los lotes van en segundo plano (202) sobre la misma carga de FT-FLU-04, con un negocio por lote y hasta 1,000 productos. Por qué: Es la opción que recomienda DUD-38: el tercero sabe al momento si su producto entró, y los volúmenes grandes no cargan en línea a MS-02 ni a MS-06. Se apoya en DUD-38, RF-MAS-05, RF-ALT-14.
  • D-PRD-10-3. Si la identificación dice que ya existe o que la marca está vetada, o el plan encuentra errores de plantilla, no se crea nada: el tercero corrige y reenvía con el mismo externalRef, que es único por tercero. Si una propuesta ya creada resulta repetida al enviarla, se cierra como convertida en oferta (FT-INT-05). Por qué: Es el contrato de catalogación por API (no se guardan propuestas que no existen) y la misma identificación previa que usa Evaluación; los cuatro resultados de lote son CREATED, CORRECTION_REQUIRED, REJECTED y ALREADY_EXISTS. Se apoya en RF-MAT-15, PEN-23, DUD-38.
  • D-PRD-10-4. Avisos en tiempo real por webhook firmado (HMAC con el secreto de la suscripción) que entrega MS-14 como un canal más, con reintentos de 1 minuto a 24 horas; de respaldo, el feed /partner/v1/events con los mismos avisos de los últimos 30 días. Para los dos negocios. Sin correo para sistemas. Por qué: RF-ALT-14 y S20-RF-16 piden alertas en tiempo real para ambos negocios (DUD-40); que las entregue MS-14 evita un segundo dueño de los avisos. Se apoya en RF-ALT-14, S20-RF-16, DUD-40, PD-26.
  • D-PRD-10-5. Lo que manda el dueño del contenido gana: cada valor guarda su origen PARTNER_API; el enriquecimiento con IA sólo llena atributos vacíos o propone, y sobrescribir un valor del dueño pide la aprobación de un rol con permiso sobre ese campo. Se aceptan atributos opcionales y hasta 20 imágenes por color. Por qué: Lo que el proveedor entrega por API entra en la catalogación inicial y no se le vuelve a pedir (RN-ENR-13); resuelve la parte de PEN-167 que toca a esta épica. Se apoya en RN-ENR-13, PEN-167, DEC-123.
  • D-PRD-10-6. La plantilla en JSON es la vista efectiva vigente de MS-01 por plantilla y negocio, con acceptedOnlyAtCreation por atributo; un PATCH a uno de esos campos responde 422 READ_ONLY_FIELD, y SKU, EAN y negocio nunca cambian por API. La categoría web la asigna Liverpool y el tercero sólo la lee. Por qué: Cubre H5 y H6 y separa la plantilla de la categoría web, como propone S20-RF-20. Se apoya en S34-RF-03, S37-RF-03, S20-RF-20, DUD-22.
  • D-PRD-10-7. La API productiva abre en R4 (Fase 2), después del corte de producto; antes sólo hay contrato y sandbox, donde toda escritura responde WRITE_DISABLED. Nunca escribe en P360. Por qué: Abrir después del corte evita la doble escritura durante la convivencia y sigue PD-02 en la opción A. Se apoya en PD-02, DEC-ARQ-05, DUD-39.
  • D-PRD-10-8. Las imágenes por URL las descarga y valida MS-11 (API-11-006) después de crear la propuesta, ligadas a su variante y posición; la ficha guarda sólo la URL. Una imagen rechazada no tumba la propuesta: llega como aviso. Por qué: Cada archivo tiene un solo dueño, MS-11, y el gateway no descarga nada. Se apoya en ADR-12, RF-IMG-12.

Qué falta decidir

IDQué falta
PD-26Arquitectura con Seguridad: el proveedor de identidad para tokens de cliente al volumen de sellers y los límites por puerta en la entrada del clúster.
DUD-38La prueba de carga confirma si el envío individual puede responder en línea; si no, también pasa a 202.
DUD-40Producto con Marketplace ratifica que las alertas son para los dos negocios.
PD-02Dirección, PM y Marketplace confirman la opción A: la API productiva va en R4.

También siguen abiertos: PEN-23, Marketplace ratifica que el PIM no crea ofertas: sólo dice sobre qué SKU ofertar.

Fuentes

  1. [D] trazabilidad/features/FT-PRD-10-catalogacion-por-api-del-proveedor.md: la ficha de la épica, con sus historias, reglas y bloqueos.
  2. [D] ADR-12 · Un solo sistema: backend compartido y una sola base (sección 3.4).
  3. [D] docs/arquitectura/por-epica/base/: piezas, colecciones, eventos y el hilo de punta a punta.
  4. [D] docs/arquitectura/omega-a-pim-headless/contratos-api.md: convenciones y endpoints de partida.
  5. [D] docs/arquitectura/maquina-de-estados-to-be/propuesta-maquina-de-estados.md §7: estados, tareas y canales.
  6. [I] Las decisiones de la sección 9 son del TL sobre esas fuentes.