Webhook de cambio de estado de publicación
BehaviorOS te avisa cuando una publicación cambia de estado en el marketplace — útil para invalidar tu cache local del catálogo
Cuando una publicación cambia de estado en BehaviorOS (se publica, se despublica manualmente o se pausa automáticamente por falta de stock), te enviamos un POST HTTP al endpoint que configures. Sirve para invalidar la cache local del catálogo sin tener que poolear constantemente la API.
Si no configurás este webhook, BehaviorOS no te avisa de los cambios de estado y vas a tener que consultarlos vía GET cuando los necesites.
Endpoints disponibles
GET /webhooks/publication-status ← consultar la configuración actual
PUT /webhooks/publication-status ← cargar / actualizar la configuración
POST /webhooks/publication-status/test ← disparar un evento de prueba
DELETE /webhooks/publication-status ← eliminar la configuración (detiene envíos)Todos están documentados en el Swagger. Requieren Authorization: Bearer <token> de tu client admin.
Configurarlo en el Control Center
- Entrá al Control Center → Webhooks → Cambio de estado de publicación.
- Completá:
- URL del webhook — endpoint público de tu sistema (
https://...). - Método HTTP — sólo
POST. - Autenticación — ver modos de autenticación.
- URL del webhook — endpoint público de tu sistema (
- Guardar configuración.
- Probar webhook — disparás un evento sintético para verificar conectividad y auth.
Cuándo se dispara
Hay cuatro situaciones que disparan el webhook. Las distinguís por los campos status y pauseReason del payload:
| Situación | Cuándo ocurre | Status / Pause reason |
|---|---|---|
| Publicación | Tu equipo (o un admin de UIN) publica una publicación que estaba en DRAFT | status: "PUBLISHED_ON_MARKETPLACE", pauseReason: "NONE" |
| Despublicación manual | Tu equipo (o un admin de UIN) despublica una publicación | status: "DRAFT", pauseReason: "MANUAL" |
| Pausa por agotamiento de stock de la publicación | Una compra deja el availableStock de la publicación en 0 | status: "DRAFT", pauseReason: "PUBLICATION_OUT_OF_STOCK" |
| Pausa por agotamiento del agreement subyacente | El agreement se queda sin stock y todas las publicaciones vinculadas se pausan a la vez | status: "DRAFT", pauseReason: "AGREEMENT_OUT_OF_STOCK" |
Un único endpoint de tu lado recibe los cuatro casos. No hace falta exponer cuatro URLs distintas.
Request
- Method:
POST. - URL: la que configuraste. Si elegiste auth por Query param, se agrega automáticamente.
- Headers:
Content-Type: application/json+ el header de auth si configurasteHEADER. El detalle exacto de qué llega según el modo de auth está en Modos de autenticación. - Body: objeto JSON único (no array — un evento por request).
Body — ejemplo
{
"publicationId": "c411df38-05b8-481c-9de2-aa27a16c6e55",
"productId": "ae8b9a3f-1234-5678-9abc-def012345678",
"clientId": "b8c7594e-8b91-4563-b460-8058343159f5",
"status": "PUBLISHED_ON_MARKETPLACE",
"pauseReason": "NONE",
"availableStock": 50,
"timestamp": "2026-06-11T17:00:00.000Z"
}Campos del payload
| Campo | Tipo | Descripción |
|---|---|---|
publicationId | UUID | Identificador de la publicación que cambió de estado. Usalo para invalidar / refrescar tu cache. |
productId | UUID | El producto al que pertenece la publicación. |
clientId | UUID | Tu UUID de cliente. Útil si tenés un único receptor que atiende varios clientes de UIN. |
status | "PUBLISHED_ON_MARKETPLACE" | "DRAFT" | Nuevo estado de la publicación. |
pauseReason | "NONE" | "MANUAL" | "PUBLICATION_OUT_OF_STOCK" | "AGREEMENT_OUT_OF_STOCK" | Razón del cambio. "NONE" viene en publicaciones; el resto identifica la causa de despublicación. |
availableStock | integer | Stock disponible al momento del cambio. Para pausa por stock=0 viene en 0; para pausa por agreement puede ser distinto de 0. |
timestamp | ISO-8601 | Momento del cambio de estado (no del envío HTTP). |
Eventos de prueba
Cuando disparás una prueba con POST /webhooks/publication-status/test (o desde el botón "Probar webhook" del Control Center), recibís el mismo shape de payload pero con un campo extra "test": true a nivel raíz:
{
"publicationId": "00000000-0000-0000-0000-000000000000",
"productId": "00000000-0000-0000-0000-000000000000",
"clientId": "<tu-clientId>",
"status": "PUBLISHED_ON_MARKETPLACE",
"pauseReason": "NONE",
"availableStock": 0,
"timestamp": "2026-06-12T18:00:00.000Z",
"test": true
}En tu endpoint: si el campo test del payload viene en true, no apliques efectos secundarios (no invalides cache, no escribas en DB). Los eventos reales no traen el campo test (está ausente, no llega en false). Ver conceptos comunes a todos los webhooks para el patrón completo.
Patrón recomendado en tu receptor
No confíes en los datos del payload como fuente de verdad — tratá el webhook como una señal de "algo cambió, volvé a consultar" y refrescá vía API usando publicationId. Esto te protege de reordenamientos, duplicados y race conditions:
Recibís webhook
│
├─ Extraés publicationId del body
│
├─ GET /marketplace/publications/{publicationId} ← fuente de verdad
│
└─ Actualizás tu cache con el estado actual devuelto por UINParticularidades de este webhook
Aparte de las garantías generales, tené en cuenta:
- Fan-out en pausa por agreement. Cuando un agreement se agota y eso pausa N publicaciones a la vez, recibís N webhooks en paralelo — uno por cada publicación afectada. Tu endpoint debería tolerar una ráfaga.
- El cambio puede haber ocurrido segundos antes. El campo
timestampregistra el momento del cambio de estado, no el del envío. Si necesitás ordenar eventos en tu sistema, usátimestamp. availableStockdescribe el estado al momento del cambio, no el estado actual. Si necesitás el stock actual, refrescá vía API.
Buenas prácticas
- Respondé rápido — idealmente menos de 5s, idealmente con
200o204. - Validá la auth antes de procesar el body.
- Idempotencia — usá
publicationId+timestamppara deduplicar. - No esperes reintentos — el envío es best-effort. Reconciliá periódicamente con
GET /marketplace/publicationssi necesitás cobertura total. - Loggeá los webhooks recibidos para debugging.
