# Notificaciones de Amazon SP-API: deduplicar y conciliar

Source: https://ipvolt.com/es/guides/amazon-listing-notifications
Markdown: https://ipvolt.com/es/guides/amazon-listing-notifications.md
Language: es

[Inicio de ipvolt](https://ipvolt.com/es.md) / [Guías](https://ipvolt.com/es/guides.md) / Notificaciones de Amazon SP-API: deduplicar y conciliar

Integración
Revisado: 2026-09-16
Publicado: 2026-09-16
6 min de lectura
Por ipvolt

Gestiona eventos de listados de Amazon SP-API con una bandeja de entrada SQLite probada: deduplica entregas, recupera tras un reinicio y rechaza lecturas ya superadas.

Por ipvolt · Comprobado el 16 de septiembre de 2026

Persiste cada notificación de listado de Amazon validada **junto con el trabajo que genera, en una sola transacción**, antes de confirmar la entrega. Usa la notificación para programar una lectura del listado. Si otra notificación aceptada llega durante esa lectura, mantén el trabajo pendiente y vuelve a leer. Esto evita una condición de carrera local concreta: que un resultado en curso más antiguo borre una solicitud de actualización más reciente.

Esta guía es para desarrolladores con una aplicación SP-API autorizada y una canalización de entrega por EventBridge ya existente. La integración requiere tu propio adaptador de eventos validado y un adaptador autenticado de lectura de listados. El laboratorio SQLite descargable se ejecuta sin conexión con eventos sintéticos, un único worker de conciliación y la biblioteca estándar de Python; implementa las comprobaciones de persistencia y finalización entre esos adaptadores.

**Método:** ipvolt ejecutó la demo y 12 pruebas el 16 de septiembre de 2026 usando CPython 3.14.7 y SQLite 3.53.4. Python 3.11+ es el objetivo del código fuente; 3.11 no se ejercitó en esa ejecución registrada. No se probó ninguna cuenta de Amazon, petición a la API ni confirmación real de una cola.

## Ejecuta el laboratorio local

Descarga y extrae el [ZIP completo del laboratorio](https://ipvolt.com/downloads/amazon-listing-notifications/amazon-listing-notifications.zip). Abre una terminal en el directorio que contiene `consumer.py` y ejecuta:

```sh
python3 -B demo.py
python3 -B -m unittest -v test_consumer.py
```

No hay paquetes que instalar. Ambos comandos usan bases de datos temporales. La demo imprime un JSON determinista; compáralo con la [salida registrada](https://ipvolt.com/downloads/amazon-listing-notifications/example-output.json).

El [README](https://ipvolt.com/downloads/amazon-listing-notifications/README.md) documenta el contrato completo. Si lo prefieres, inspecciona individualmente [consumer.py](https://ipvolt.com/downloads/amazon-listing-notifications/consumer.py), [demo.py](https://ipvolt.com/downloads/amazon-listing-notifications/demo.py), la [suite de pruebas](https://ipvolt.com/downloads/amazon-listing-notifications/test_consumer.py) y el [fixture sintético](https://ipvolt.com/downloads/amazon-listing-notifications/fixtures/scenario.json).

## Normaliza un evento de confianza antes de almacenarlo

Las notificaciones de estado e incidencias de listados usan el **flujo de trabajo de EventBridge** de Amazon. Una cola SQS puede ser un destino de regla aguas abajo; eso es distinto de suscribirse mediante el flujo de trabajo SQS directo de SP-API. Sigue la [configuración de EventBridge](https://developer-docs.amazon/sp-api/docs/set-up-notifications-with-amazon-eventbridge) de Amazon para destinos, suscripciones y permisos de entrega.

Fija el tipo en bruto y la versión del payload en tu adaptador. Los nombres en minúsculas de abajo pertenecen a este laboratorio:

| Tipo documentado por Amazon | Versión del payload | Tipo normalizado del laboratorio |
| --- | --- | --- |
| `LISTINGS_ITEM_STATUS_CHANGE` | `1.0` | `listing_status_changed` |
| `LISTINGS_ITEM_ISSUES_CHANGE` | `2023-12-13` | `listing_issues_changed` |

Amazon indica a los usuarios de la versión `1.0` de incidencias que migren a `2023-12-13`. Los eventos de estado tratan de la creación, la eliminación y la disponibilidad para compra; los eventos de incidencias contienen resúmenes que pueden motivar una lectura más completa. No describen todos los problemas posibles de un listado. [Tipos de notificación de Amazon](https://developer-docs.amazon/sp-api/docs/notification-type-values).

Ambos payloads en bruto permiten que `MarketplaceId` esté ausente. Resuélvelo solo a través de configuración autorizada y de confianza; de lo contrario, retén el evento para investigarlo antes de crear un registro normalizado. Nunca suministres tu marketplace por defecto de forma silenciosa. El laboratorio exige vendedor, SKU y marketplace explícitos. Consulta el [esquema de estado](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemStatusChangeNotification.json) y el [esquema de incidencias](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemIssuesChangeNotification_2023-12-13.json) fijados.

También hay una inconsistencia de nombres: el enum de ese esquema de estado dice `LISTINGS_ITEM_STATUS_CHANGED`, mientras que su ejemplo y la documentación dicen `LISTINGS_ITEM_STATUS_CHANGE`. Mantén cualquier excepción de validación acotada, versionada y cubierta por las pruebas de tu adaptador. El laboratorio normalizado ni analiza ese sobre ni certifica su conformidad con el esquema.

Este es exactamente el primer registro sintético del fixture:

```json
{
  "schema_version": 1,
  "source": "fixture:eventbridge:bus-A",
  "subscription": "fixture-subscription-A",
  "notification_id": "notice-001",
  "seller_id": "seller-A",
  "sku": "SKU-RED",
  "marketplace_id": "market-A",
  "notification_type": "listing_status_changed",
  "event_time": "2026-09-16T10:00:00Z",
  "payload": {"hint": "synthetic status change"}
}
```

`Store.ingest()` acepta este objeto como texto JSON. El adaptador debe validar primero el origen, el contexto de aplicación/suscripción, la autorización del vendedor y el alcance. Conserva la identidad interna de la notificación por separado del ID de evento externo de EventBridge y de cualquier receipt handle de la cola. El [sobre de EventBridge](https://docs.aws.amazon.com/eventbridge/latest/ref/events-structure.html) y el [contrato de eliminación de SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html) describen esos valores de transporte distintos.

El laboratorio deduplica por `(source, subscription, notification_id)`. Esta clave compuesta es una política de la aplicación. Mantén los contadores de intentos de entrega, los receipt handles y las horas de recepción fuera del objeto normalizado: cambian entre entregas. El README enumera sus límites estrictos de validación de campos, tamaño y JSON.

## Confirma la aceptación y el trabajo pendiente juntos

EventBridge puede entregar duplicados y no ofrece ninguna garantía de orden. Una cola SQS estándar aguas abajo también permite duplicados y entregas fuera de orden. [Comparativa de entrega de AWS](https://docs.aws.amazon.com/decision-guides/latest/decision-guides/sns-or-sqs-or-eventbridge.html), [colas SQS estándar](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html).

El núcleo ejecutable gestiona esa incertidumbre en cuatro pasos:

1. Inicia una transacción SQLite. Para una identidad nueva, inserta el registro en la bandeja de entrada e incrementa la generación de trabajo de `(seller_id, sku, marketplace_id)` a la vez.
2. Para una identidad existente, compara el contenido normalizado canónico. Un contenido idéntico devuelve `duplicate` sin incrementar el trabajo. Un contenido distinto lanza `IdentityConflict` y conserva el estado original.
3. Devuelve `may_ack=True` solo después del commit. Es una decisión lógica para tu adaptador de transporte; la descarga no hace ninguna llamada de confirmación a la cola. Los errores de validación, conflicto y almacenamiento no producen esa decisión.
4. Recorre `dirty_keys()` tras un reinicio y entre ejecuciones. Una clave está sucia cuando `generation > applied_generation`. Captura su generación, realiza la lectura fuera de la transacción y guarda el resultado solo si la clave y la generación siguen coincidiendo.

Cada identidad recién aceptada avanza su clave, incluido un evento con un `event_time` más antiguo. El payload se conserva para la comparación de identidad y nunca se aplica como estado actual del listado. El [modelo de estado](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemStatusChangeNotification.json) inspeccionado define `EventTime` como una marca de tiempo, no como una revisión compartida del listado. Este diseño no descarta trabajo solo porque su marca de tiempo sea más antigua.

## Observa la carrera entre el reinicio y la lectura en curso

Esta traza compacta procede de la demo registrada para `seller-A / SKU-RED / market-A`:

| Caso | Generación | Generación aplicada | Sucia | Resultado observado |
| --- | --- | --- | --- | --- |
| El proceso termina tras el commit | 1 | 0 | true | Sobrevive una fila en la bandeja de entrada |
| Reentrega tras el reinicio | 1 | 0 | true | `duplicate`, `may_ack: true` |
| Lectura sintética inicial | 1 | 1 | false | `read-1` guardado |
| Llega un evento más antiguo | 2 | 1 | true | Se requiere una nueva actualización |
| Llega otro evento durante la lectura de la generación 2 | 3 | 1 | true | `completion_applied: false` |
| La lectura siguiente falla | 3 | 1 | true | Se conserva la instantánea anterior |
| Actualización posterior exitosa | 3 | 3 | false | `read-3` guardado |

El resultado de la generación 2 no puede limpiar la generación 3. Su documento `read-2` rechazado nunca reemplaza a `read-1`; el fallo posterior también deja el trabajo pendiente. La demo termina con cinco filas en la bandeja de entrada, tres claves limpias independientes y cero confirmaciones externas.

Las 12 pruebas registradas pasan. Incluyen una salida abrupta de un proceso hijo tras el commit, fallos de SQLite inyectados que revierten juntos la bandeja de entrada y el trabajo, identidades en conflicto, resultados con clave incorrecta y la carrera descrita arriba. Esto establece el comportamiento local ante reinicios del proceso, no la durabilidad ante cortes de energía o corrupción del sistema de archivos.

«Limpia» significa que se aceptó una lectura frente a la última **generación local persistida**. No puede demostrar que la respuesta de Amazon incluya el cambio que la desencadenó, que otra notificación no esté retrasada ni que la entrega haya sido completa. El contador no es una revisión de Amazon ni una garantía distribuida de exactamente una vez.

## Valida la lectura antes de limpiar el trabajo

Tu adaptador de lectura debe elegir explícitamente los datasets de `getListingsItem` y validar el estado HTTP, el contenido de la respuesta y el significado previsto de vendedor/SKU/marketplace antes de devolver `ReadResult`. El [tutorial de recuperación de listados](https://developer-docs.amazon/sp-api/docs/retrieve-details-about-a-listing) de Amazon explica qué datasets responden a qué preguntas. Ahora admite varios marketplaces de la misma región para vendedores; este laboratorio mantiene deliberadamente un marketplace por clave de trabajo.

**El núcleo no valida una respuesta real de Amazon.** Comprueba la clave declarada por el adaptador, los límites del JSON y la generación local. Incluso `{}` pasa su comprobación de forma de objeto. Si faltan datos obligatorios, la respuesta pertenece a otro sitio o la petición falla, tu adaptador debe lanzar una excepción en lugar de devolver un marcador con forma de éxito. `refresh_once()` entonces deja el trabajo sucio y la instantánea anterior intacta.

Para la decisión aparte sobre envíos aceptados, ofertas actuales, inventario y observaciones desconocidas, usa [Actualizaciones de listados de Amazon: aceptado no significa publicado](/es/blog/amazon-listing-update-reconciliation). Una operación de almacenamiento exitosa no puede dar sentido a una observación incompleta.

## Añade recuperación alrededor del núcleo

Usa un único worker de conciliación para este ejemplo. Sus tickets son comprobaciones de generación, no arrendamientos de worker. La base de datos conserva las identidades de la bandeja de entrada indefinidamente; eliminarlas cambia el horizonte de deduplicación. La programación, el backoff, los límites de peticiones, la retención y la propiedad por workers concurrentes requieren un diseño adicional.

Una canalización de producción también necesita un tratamiento duradero de los eventos malformados o en conflicto, recuperación ante fallos de entrega y conciliación periódica del alcance autorizado de listados. Amazon recomienda un [mecanismo de recuperación de respaldo](https://developer-docs.amazon/sp-api/docs/notifications-api); EventBridge deja de reintentar cuando se agota su política configurada y admite una [cola de mensajes fallidos (DLQ)](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rule-retry-policy.html). Un barrido y la recuperación desde la DLQ quedan fuera de este laboratorio. Cubren fallos que una bandeja de entrada no puede ver porque el evento nunca llegó a ella.

ipvolt está en desarrollo. [Únete a la lista de acceso anticipado](https://ipvolt.com/#waitlist-closing) para recibir un correo cuando se abra el acceso. Nada más.

## Fuentes y lecturas adicionales

- [Set up notifications using the Amazon EventBridge workflow](https://developer-docs.amazon/sp-api/docs/set-up-notifications-with-amazon-eventbridge)
- [Notification Type Values](https://developer-docs.amazon/sp-api/docs/notification-type-values)
- [Listings Item Status Change Notification schema](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemStatusChangeNotification.json)
- [Listings Item Issues Change Notification schema2023-12-13](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemIssuesChangeNotification_2023-12-13.json)
- [AWS service event metadata](https://docs.aws.amazon.com/eventbridge/latest/ref/events-structure.html)
- [DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html)
- [Amazon SQS, Amazon SNS, or Amazon EventBridge?](https://docs.aws.amazon.com/decision-guides/latest/decision-guides/sns-or-sqs-or-eventbridge.html)
- [Amazon SQS standard queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html)
- [Retrieve details about a listing for single or multiple Amazon stores](https://developer-docs.amazon/sp-api/docs/retrieve-details-about-a-listing)
- [Notifications API](https://developer-docs.amazon/sp-api/docs/notifications-api)
- [How EventBridge retries delivering events](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rule-retry-policy.html)

## Guías relacionadas

- [Proxy en Python Requests: diccionario proxies, auth, SOCKS5](https://ipvolt.com/es/guides/python-requests-proxy.md)
- [Diagnostica los timeouts de proxy etapa por etapa](https://ipvolt.com/es/guides/proxy-timeout-troubleshooting.md)
- [Usar un proxy con curl: -x, variables de entorno, SOCKS5 y auth](https://ipvolt.com/es/guides/curl-proxy-setup.md)

## Sobre ipvolt

Los ejemplos usan configuraciones de proxy genéricas, con enlaces a la documentación técnica original. El comportamiento específico de cada producto debe comprobarse con tu proveedor. ipvolt sigue en desarrollo.

[Leer el original en inglés](https://ipvolt.com/guides/amazon-listing-notifications.md)

## Entérate cuando se abra el acceso.

ipvolt · En desarrollo

Estamos construyendo infraestructura de proxies para desarrolladores y equipos de datos. Únete a la lista de interés para recibir un aviso cuando ipvolt esté listo.

Un correo cuando se abra el acceso. Nada más.

[Solicitar acceso anticipado](https://ipvolt.com/es/guides/amazon-listing-notifications#waitlist-closing)

[Privacidad](https://ipvolt.com/privacy)

