# Webhook Collection Sync | Docs de AudioDN

> El webhook Collection Sync notifica a tu aplicación cada vez que se crea, actualiza o elimina una colección.

Source: https://audiodeliverynetwork.com/es/docs/webhooks/collection-sync/

---

# Webhook Collection Sync

El webhook Collection Sync permite que tu aplicación se mantenga sincronizada con tus colecciones de AudioDN. Cada vez que se crea, actualiza o elimina una colección, AudioDN envía una solicitud HTTP `POST` a la URL de webhook de colección configurada para tu organización. Esto es independiente del [webhook Track Processing](/docs/webhooks/track-processing), que cubre los cambios de estado de las pistas.

#### Se configura en el panel

La URL del webhook de colección se establece en el panel **Settings → Webhook** del dashboard, no vía la API. Una vez guardada una URL, cada create/update/delete de colección de tu organización se entrega a ella. Déjala en blanco para desactivar los webhooks de colección.

## Cuándo se dispara

Se entrega un webhook cada vez que una colección cambia de estado:

-   Se envía como un HTTP `POST` con `Content-Type: application/json`.
-   Incluye una cabecera `X-ADN-Event` con el nombre del evento (por ejemplo `collection.updated`).
-   La entrega es fire-and-forget / al menos una vez — diseña tu manejador para que sea idempotente.
-   No se garantiza el orden de eventos; usa el `event` y el campo `updated_at` de la colección en lugar de asumir el orden de llegada.
-   Las solicitudes actualmente no están firmadas. Trata la URL del webhook como un secreto y, si hace falta, verifica el `collection_id` contra la API.
-   Responde con prontitud con un código de estado `2xx` para acusar recibo.

## Eventos

| Evento | Significado |
| --- | --- |
| collection.created | Se creó una nueva colección. Se envía una vez, cuando se inserta por primera vez la fila de la colección. |
| collection.updated | Una colección existente cambió — por ejemplo su título, metadatos, portada o ajustes del player. |
| collection.deleted | Se eliminó una colección. Se envía cuando se quita la colección (sus pistas y archivos se eliminan con ella). |

## Esquema del payload

Cada evento entrega el mismo sobre. El objeto `collection` contiene los campos actuales de la colección; en un evento `collection.deleted` refleja la fila eliminada (con `deleted_at` establecido).

```
{
"event": "collection.created | collection.updated | collection.deleted",
"organization_id": "uuid",
"creator_id": "uuid | null",
"collection_id": "uuid",
"collection": {
  "id": "uuid",
  "organization_id": "uuid",
  "creator_id": "uuid | null",
  "title": "string | null",
  "organization_index": "string | null",
  "metadata": "object | null",
  "theme": "array | null",
  "player_color": "string | null",
  "player_color_light": "string | null",
  "player_color_dark": "string | null",
  "player_subtitle": "string | null",
  "is_cover_overridable": "boolean",
  "is_theme_overridable": "boolean",
  "cloudflare_image_id": "uuid | null",
  "cover_image": {
    "icon": { "type": "icon", "width": 80, "height": 80, "url": "string" },
    "small": { "type": "small", "width": 200, "height": 200, "url": "string" },
    "regular": { "type": "regular", "width": 400, "height": 400, "url": "string" },
    "large": { "type": "large", "width": 800, "height": 800, "url": "string" }
  },
  "created_at": "string",
  "updated_at": "string",
  "deleted_at": "string | null"
}
}
```

## Imágenes de portada

Cuando una colección tiene arte de portada, `collection.cover_image` proporciona URLs listas para usar en cada tamaño disponible (y `collection.cloudflare_image_id` almacena el ID de imagen si lo necesitas). Ambos son `null` cuando no hay portada. Prefiere las URLs ya preparadas; si solo tienes el ID de imagen, construye cualquier tamaño tú mismo con el patrón de abajo, donde `<variant>` es `icon` (80x80), `small` (200x200), `regular` (400x400) o `large` (800x800):

```
https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/{cloudflare_image_id}/{variant}
```

Consulta [Track Processing → Cover images](/docs/webhooks/track-processing#cover-images) para la referencia completa de variantes. El mismo esquema se usa en las respuestas `cover_image` de la API.

## Ejemplos de payload

### Creada

Se envía cuando se crea una nueva colección.

```
{
"event": "collection.created",
"organization_id": "11111111-1111-1111-1111-111111111111",
"creator_id": null,
"collection_id": "22222222-2222-2222-2222-222222222222",
"collection": {
  "id": "22222222-2222-2222-2222-222222222222",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "creator_id": null,
  "title": "Season 1",
  "organization_index": "your-collection-id-001",
  "metadata": null,
  "theme": null,
  "player_color": "#1DB954",
  "player_color_light": "#1BAA4D",
  "player_color_dark": "#1DB954",
  "player_subtitle": "Acme Media",
  "is_cover_overridable": true,
  "is_theme_overridable": true,
  "cloudflare_image_id": null,
  "cover_image": null,
  "created_at": "2026-07-02T10:00:00.000Z",
  "updated_at": "2026-07-02T10:00:00.000Z",
  "deleted_at": null
}
}
```

### Actualizada

Se envía cuando cambian los campos de una colección.

```
{
"event": "collection.updated",
"organization_id": "11111111-1111-1111-1111-111111111111",
"creator_id": null,
"collection_id": "22222222-2222-2222-2222-222222222222",
"collection": {
  "id": "22222222-2222-2222-2222-222222222222",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "creator_id": null,
  "title": "Season 1 (Remastered)",
  "organization_index": "your-collection-id-001",
  "metadata": { "genre": "podcast" },
  "theme": null,
  "player_color": "#1DB954",
  "player_color_light": "#1BAA4D",
  "player_color_dark": "#1DB954",
  "player_subtitle": "Acme Media",
  "is_cover_overridable": true,
  "is_theme_overridable": true,
  "cloudflare_image_id": "99999999-9999-9999-9999-999999999999",
  "cover_image": {
    "icon": { "type": "icon", "width": 80, "height": 80, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/icon" },
    "small": { "type": "small", "width": 200, "height": 200, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/small" },
    "regular": { "type": "regular", "width": 400, "height": 400, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/regular" },
    "large": { "type": "large", "width": 800, "height": 800, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/large" }
  },
  "created_at": "2026-07-02T10:00:00.000Z",
  "updated_at": "2026-07-02T12:30:00.000Z",
  "deleted_at": null
}
}
```

### Eliminada

Se envía cuando se elimina una colección. El campo `deleted_at` está poblado.

```
{
"event": "collection.deleted",
"organization_id": "11111111-1111-1111-1111-111111111111",
"creator_id": null,
"collection_id": "22222222-2222-2222-2222-222222222222",
"collection": {
  "id": "22222222-2222-2222-2222-222222222222",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "creator_id": null,
  "title": "Season 1 (Remastered)",
  "organization_index": "your-collection-id-001",
  "metadata": { "genre": "podcast" },
  "theme": null,
  "player_color": "#1DB954",
  "player_color_light": "#1BAA4D",
  "player_color_dark": "#1DB954",
  "player_subtitle": "Acme Media",
  "is_cover_overridable": true,
  "is_theme_overridable": true,
  "cloudflare_image_id": "99999999-9999-9999-9999-999999999999",
  "cover_image": {
    "icon": { "type": "icon", "width": 80, "height": 80, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/icon" },
    "small": { "type": "small", "width": 200, "height": 200, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/small" },
    "regular": { "type": "regular", "width": 400, "height": 400, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/regular" },
    "large": { "type": "large", "width": 800, "height": 800, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/99999999-9999-9999-9999-999999999999/large" }
  },
  "created_at": "2026-07-02T10:00:00.000Z",
  "updated_at": "2026-07-02T13:00:00.000Z",
  "deleted_at": "2026-07-02T13:00:00.000Z"
}
}
```

#### Verificar la entrega

Cada intento de entrega se registra en el lado de AudioDN, incluyendo el código de estado HTTP devuelto por tu endpoint. Si dejas de recibir eventos, confirma que tu endpoint responde con `2xx` rápidamente y que la URL del webhook de colección en Settings es correcta.

## Manejar webhooks

Un manejador mínimo lee el campo `event` y mantiene sincronizada tu copia local de la colección. Como la entrega es al menos una vez y sin orden garantizado, basa tu lógica en `collection_id` y el `updated_at` de la colección en lugar del orden de recepción.

```
app.post('/webhooks/audiodn/collections', (req, res) => {
// Acknowledge quickly, then process asynchronously.
res.sendStatus(200)

const { event, collection_id, collection } = req.body

switch (event) {
  case 'collection.created':
  case 'collection.updated':
    // Upsert your local copy of the collection.
    upsertCollection(collection_id, collection)
    break
  case 'collection.deleted':
    // Remove your local copy.
    removeCollection(collection_id)
    break
}
})
```
