# Webhooks
> Avisos de HILLS Music a tus endpoints: lanzamientos, entregas, DDEX, liquidaciones, pagos, solicitudes y soporte en vivo. Firmados y con reintentos.
Avisos de HILLS Music a tus endpoints: lanzamientos, entregas, DDEX, liquidaciones, pagos, solicitudes y soporte en vivo. Firmados y con reintentos.
URL base `https://api.hillsmusic.com/v1`. Cada solicitud envía una clave de API: `Authorization: Bearer hm_live_…`.
- Listar los tipos de evento de webhook
- Listar los endpoints de webhook
- Crear un endpoint de webhook
- Obtener un endpoint de webhook
- Actualizar un endpoint de webhook
- Eliminar un endpoint de webhook
- Renovar el secreto de un webhook
- Enviar un evento de prueba
- Listar las entregas de un endpoint
- Reintentar una entrega
## Listar los tipos de evento de webhook
`GET /v1/webhooks/events` · Ámbito: `webhooks:read` o `webhooks:write`
Todos los tipos de evento a los que puede suscribirse un endpoint, con su significado. Los payloads se documentan en Webhooks, dentro de esta referencia.
### Ejemplo de solicitud
```bash
curl "https://api.hillsmusic.com/v1/webhooks/events" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `200`
```json
{
"data": [
{
"type": "release.approved",
"label": "Release approved",
"description": "A release was approved and is queued for its stores."
}
]
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Listar los endpoints de webhook
`GET /v1/webhooks` · Ámbito: `webhooks:read` o `webhooks:write`
Tus endpoints de webhook (20 como máximo), del más antiguo al más reciente. El secreto nunca aparece en la lista.
### Ejemplo de solicitud
```bash
curl "https://api.hillsmusic.com/v1/webhooks" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `200`
```json
{
"data": [
{
"id": 7,
"url": "https://example.com/hills/webhooks",
"description": "Order system",
"events": [
"release.approved",
"delivery.store_status_changed"
],
"enabled": true,
"secret_prefix": "whsec_3f9a1c",
"created_at": "2026-10-13T09:00:00Z",
"updated_at": "2026-10-13T09:00:00Z",
"last_success_at": null,
"last_failure_at": null,
"failure_count": 0,
"disabled_at": null,
"disabled_reason": null
}
]
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Crear un endpoint de webhook
`POST /v1/webhooks` · Ámbito: `webhooks:write`
Registra una URL https para los eventos que elijas. La respuesta incluye el secreto de firma, una sola vez. La URL debe ser pública: se rechazan las direcciones privadas, locales y de metadatos.
### Cuerpo de la solicitud
JSON.
| Campo | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `url` | string | Sí | Adónde enviar los eventos por POST: una URL https:// pública en el puerto 443. |
| `description` | string | No | Una nota para ti, por ejemplo, el sistema que los recibe. |
| `events` | array | Sí | Los tipos de evento que se envían (consulta Webhooks en esta referencia). |
| `enabled` | boolean | No | Valor predeterminado: true. |
### Ejemplo de solicitud
```bash
curl -X POST "https://api.hillsmusic.com/v1/webhooks" \
-H "Authorization: Bearer $HILLS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/hills/webhooks","description":"Order system","events":["release.approved","delivery.store_status_changed"]}'
```
### Respuesta `201`
```json
{
"endpoint": {
"id": 7,
"url": "https://example.com/hills/webhooks",
"description": "Order system",
"events": [
"release.approved",
"delivery.store_status_changed"
],
"enabled": true,
"secret_prefix": "whsec_3f9a1c",
"created_at": "2026-10-13T09:00:00Z",
"updated_at": "2026-10-13T09:00:00Z",
"last_success_at": null,
"last_failure_at": null,
"failure_count": 0,
"disabled_at": null,
"disabled_reason": null
},
"secret": "whsec_3f9a1c0d5e7b2a4c6e8f0a1b3c5d7e9f1a2b3c4d5e6f7a8b"
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 400 | invalid: un parámetro es incorrecto; field indica cuál. invalid_url: no es una URL https pública en el puerto 443. |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 409 | too_many: ya hay 20 endpoints. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Obtener un endpoint de webhook
`GET /v1/webhooks/{id}` · Ámbito: `webhooks:read` o `webhooks:write`
Un endpoint con su estado de salud: último éxito y último fallo, intentos fallidos consecutivos y por qué está desactivado.
### Parámetros
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Sí | El id del endpoint. |
### Ejemplo de solicitud
```bash
curl "https://api.hillsmusic.com/v1/webhooks/7" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `200`
```json
{
"data": {
"id": 7,
"url": "https://example.com/hills/webhooks",
"description": "Order system",
"events": [
"release.approved",
"delivery.store_status_changed"
],
"enabled": true,
"secret_prefix": "whsec_3f9a1c",
"created_at": "2026-10-13T09:00:00Z",
"updated_at": "2026-10-13T09:00:00Z",
"last_success_at": null,
"last_failure_at": null,
"failure_count": 0,
"disabled_at": null,
"disabled_reason": null
}
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 404 | not_found: no existe o no es tuyo. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Actualizar un endpoint de webhook
`PATCH /v1/webhooks/{id}` · Ámbito: `webhooks:write`
Cambia su URL, su descripción o sus eventos, o lo desactiva y lo reactiva (enabled). Al reactivarlo se pone a cero su contador de fallos; las entregas abandonadas mientras estaba desactivado pueden volver a enviarse con retry.
### Parámetros
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Sí | El id del endpoint. |
### Cuerpo de la solicitud
JSON.
| Campo | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `url` | string | No | Adónde enviar los eventos por POST: una URL https:// pública en el puerto 443. |
| `description` | string | No | Una nota para ti, por ejemplo, el sistema que los recibe. |
| `events` | array | No | Los tipos de evento que se envían (consulta Webhooks en esta referencia). |
| `enabled` | boolean | No | false lo desactiva; true lo reactiva. |
### Ejemplo de solicitud
```bash
curl -X PATCH "https://api.hillsmusic.com/v1/webhooks/7" \
-H "Authorization: Bearer $HILLS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'
```
### Respuesta `200`
```json
{
"data": {
"id": 7,
"url": "https://example.com/hills/webhooks",
"description": "Order system",
"events": [
"release.approved",
"delivery.store_status_changed"
],
"enabled": true,
"secret_prefix": "whsec_3f9a1c",
"created_at": "2026-10-13T09:00:00Z",
"updated_at": "2026-10-13T09:00:00Z",
"last_success_at": null,
"last_failure_at": null,
"failure_count": 0,
"disabled_at": null,
"disabled_reason": null
}
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 400 | invalid: un parámetro es incorrecto; field indica cuál. invalid_url: no es una URL https pública en el puerto 443. |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 404 | not_found: no existe o no es tuyo. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Eliminar un endpoint de webhook
`DELETE /v1/webhooks/{id}` · Ámbito: `webhooks:write`
Elimina el endpoint y su registro de entregas. No se le envía nada más.
### Parámetros
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Sí | El id del endpoint. |
### Ejemplo de solicitud
```bash
curl -X DELETE "https://api.hillsmusic.com/v1/webhooks/7" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `200`
```json
{
"ok": true
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 404 | not_found: no existe o no es tuyo. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Renovar el secreto de un webhook
`POST /v1/webhooks/{id}/roll-secret` · Ámbito: `webhooks:write`
Genera un nuevo secreto de firma; el anterior deja de funcionar al instante. El nuevo secreto solo aparece en esta respuesta.
### Parámetros
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Sí | El id del endpoint. |
### Ejemplo de solicitud
```bash
curl -X POST "https://api.hillsmusic.com/v1/webhooks/7/roll-secret" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `200`
```json
{
"endpoint": {
"id": 7,
"url": "https://example.com/hills/webhooks",
"description": "Order system",
"events": [
"release.approved",
"delivery.store_status_changed"
],
"enabled": true,
"secret_prefix": "whsec_3f9a1c",
"created_at": "2026-10-13T09:00:00Z",
"updated_at": "2026-10-13T09:00:00Z",
"last_success_at": null,
"last_failure_at": null,
"failure_count": 0,
"disabled_at": null,
"disabled_reason": null
},
"secret": "whsec_3f9a1c0d5e7b2a4c6e8f0a1b3c5d7e9f1a2b3c4d5e6f7a8b"
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 404 | not_found: no existe o no es tuyo. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Enviar un evento de prueba
`POST /v1/webhooks/{id}/test` · Ámbito: `webhooks:write`
Pone en cola un evento webhook.test para este endpoint, tenga los eventos que tenga, firmado como cualquier otro. Su resultado aparece en las entregas.
### Parámetros
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Sí | El id del endpoint. |
### Ejemplo de solicitud
```bash
curl -X POST "https://api.hillsmusic.com/v1/webhooks/7/test" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `202`
```json
{
"delivery": {
"id": 1042,
"endpoint_id": 7,
"event": "webhook.test",
"event_id": "5d0c2b7e-8a43-4c4e-9f1e-2f0b9a6c1d33",
"attempt": 0,
"status": "pending",
"response_status": null,
"response_ms": null,
"next_attempt_at": "2026-10-13T09:05:00Z",
"error": null,
"created_at": "2026-10-13T09:05:00Z",
"delivered_at": null,
"payload": {
"id": "5d0c2b7e-8a43-4c4e-9f1e-2f0b9a6c1d33",
"type": "release.approved",
"api_version": "v1",
"occurred_at": "2026-10-13T09:05:00Z",
"account_id": 12,
"data": {
"release": {
"id": 812,
"title": "Midnight Run"
}
}
}
}
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 404 | not_found: no existe o no es tuyo. |
| 409 | endpoint_disabled: el endpoint está desactivado. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Listar las entregas de un endpoint
`GET /v1/webhooks/{id}/deliveries` · Ámbito: `webhooks:read` o `webhooks:write`
Lo que se envió al endpoint en los últimos 30 días, de lo más reciente a lo más antiguo: el payload, los intentos, el último estado HTTP con su hora y el error.
### Parámetros
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Sí | El id del endpoint. |
| `status` | query | `pending` \| `succeeded` \| `failed` | No | Solo estas. |
| `event` | query | string | No | Solo este tipo de evento. |
| `limit` | query | number | No | 1–100; predeterminado: 50. |
| `before` | query | number | No | Entregas anteriores a este id de entrega (la página siguiente). |
### Ejemplo de solicitud
```bash
curl "https://api.hillsmusic.com/v1/webhooks/7/deliveries?status=failed" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `200`
```json
{
"data": [
{
"id": 1042,
"endpoint_id": 7,
"event": "release.approved",
"event_id": "5d0c2b7e-8a43-4c4e-9f1e-2f0b9a6c1d33",
"attempt": 1,
"status": "succeeded",
"response_status": 200,
"response_ms": 184,
"next_attempt_at": "2026-10-13T09:05:00Z",
"error": null,
"created_at": "2026-10-13T09:05:00Z",
"delivered_at": "2026-10-13T09:05:01Z",
"payload": {
"id": "5d0c2b7e-8a43-4c4e-9f1e-2f0b9a6c1d33",
"type": "release.approved",
"api_version": "v1",
"occurred_at": "2026-10-13T09:05:00Z",
"account_id": 12,
"data": {
"release": {
"id": 812,
"title": "Midnight Run"
}
}
}
}
],
"has_more": false
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 400 | invalid: un parámetro es incorrecto; field indica cuál. |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 404 | not_found: no existe o no es tuyo. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
## Reintentar una entrega
`POST /v1/webhooks/{id}/deliveries/{delivery_id}/retry` · Ámbito: `webhooks:write`
Vuelve a enviar ahora el mismo evento (mismo id y mismo payload) al endpoint.
### Parámetros
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Sí | El id del endpoint. |
| `delivery_id` | path | integer | Sí | El id de la entrega. |
### Ejemplo de solicitud
```bash
curl -X POST "https://api.hillsmusic.com/v1/webhooks/7/deliveries/1042/retry" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Respuesta `202`
```json
{
"delivery": {
"id": 1042,
"endpoint_id": 7,
"event": "release.approved",
"event_id": "5d0c2b7e-8a43-4c4e-9f1e-2f0b9a6c1d33",
"attempt": 1,
"status": "pending",
"response_status": 200,
"response_ms": 184,
"next_attempt_at": "2026-10-13T09:05:00Z",
"error": null,
"created_at": "2026-10-13T09:05:00Z",
"delivered_at": "2026-10-13T09:05:01Z",
"payload": {
"id": "5d0c2b7e-8a43-4c4e-9f1e-2f0b9a6c1d33",
"type": "release.approved",
"api_version": "v1",
"occurred_at": "2026-10-13T09:05:00Z",
"account_id": 12,
"data": {
"release": {
"id": 812,
"title": "Midnight Run"
}
}
}
}
}
```
### Errores
| Estado | Cuándo |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. |
| 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. |
| 404 | not_found: no existe o no es tuyo. |
| 409 | endpoint_disabled: el endpoint está desactivado. |
| 429 | rate_limited: espera los segundos que indique Retry-After. |
Fuente: https://developer.hillsmusic.com/es/reference/webhooks/