> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ycloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Gestionar llamadas de WhatsApp

> Configura WhatsApp Calling, gestiona la señalización de llamadas entrantes y salientes, procesa eventos de llamadas y descarga grabaciones o transcripciones.

## Qué es

La API WhatsApp Calling de YCloud gestiona la señalización de llamadas de voz entre un usuario de WhatsApp y un número de teléfono comercial. Tu aplicación intercambia SDP a través de YCloud, mientras que tu implementación de WebRTC se encarga de la conexión de audio.

Las llamadas pueden iniciarse en cualquiera de las dos direcciones:

* **Iniciadas por el usuario:** Un usuario de WhatsApp llama a tu empresa. Tu aplicación recibe una oferta y acepta o rechaza la llamada.
* **Iniciadas por la empresa:** Tu aplicación crea una oferta y solicita a YCloud que llame a un usuario de WhatsApp.

<Info>
  La Calling API gestiona la señalización de llamadas, no la pila de medios WebRTC. Tu aplicación es responsable de la configuración de la conexión peer, la captura y reproducción de audio, la generación de SDP y la liberación de recursos WebRTC.
</Info>

## Mapa de la API

Las Calling APIs y los eventos de webhook siguen el mismo ciclo de vida, pero no forman una única secuencia que se aplique a cada llamada. Completa la configuración compartida y luego sigue el flujo iniciado por el usuario o por la empresa. Utiliza el ID de llamada, `wacid`, para correlacionar cada operación y evento.

### Configuración compartida

| API | Cuándo usarla | Qué sucede después |
| - | - | - |
| [`GET settings`](/api-reference/whatsapp-phone-numbers/retrieve-phone-number-settings) o [`POST settings`](/api-reference/whatsapp-phone-numbers/save-phone-number-settings) | Antes de gestionar llamadas, o cuando cambie la configuración de Calling y captura. | Configura los webhooks y prepara tu implementación de WebRTC, luego sigue el flujo según la dirección de la llamada. |

### Llamadas iniciadas por el usuario

| Orden | API o evento | Qué sucede después |
| - | - | - |
| 1 | [`whatsapp.call.connect`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-connect-webhook-examples) | Recibe la oferta SDP, `phoneId` y `wacid`, luego crea una respuesta SDP. |
| 2 (opcional) | [`POST /whatsapp/calls/preAccept`](/api-reference/whatsapp-calling/pre-accept-a-call) | Si planeas aceptar la llamada, envía la respuesta SDP para preparar la ruta de medios. Esto no contesta la llamada. |
| 3 | [`POST /whatsapp/calls/accept`](/api-reference/whatsapp-calling/accept-a-call) o [`POST /whatsapp/calls/reject`](/api-reference/whatsapp-calling/reject-a-call) | Elige una opción: acepta la llamada con la respuesta SDP o recházala. |

### Llamadas iniciadas por la empresa

| Orden | API o evento | Qué sucede después |
| - | - | - |
| 1 | [`POST /whatsapp/calls/connect`](/api-reference/whatsapp-calling/connect-a-call) | Envía tu oferta SDP, inicia la llamada y guarda el `wacid` devuelto. |
| 2 | [`whatsapp.call.connect`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-connect-webhook-examples) | Recibe la respuesta SDP remota y aplícala a la misma conexión peer de WebRTC. |
| 3 | [`whatsapp.call.status.updated`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-status-update-webhook-examples) | Rastrea `RINGING`, `ACCEPTED` o `REJECTED`. Este evento puede llegar más de una vez a medida que el intento cambia de estado. |

### Finalización de llamadas compartida

| API o evento | Cuándo usarlo | Qué sucede después |
| - | - | - |
| [`POST /whatsapp/calls/terminate`](/api-reference/whatsapp-calling/terminate-a-call) | Opcional. Llámalo cuando tu aplicación necesite finalizar una llamada activa entrante o saliente. | Mantén abierto el registro de la llamada mientras esperas el evento final. |
| [`whatsapp.call.terminate`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-terminate-webhook-examples) | Recíbelo para obtener el resultado final de la llamada. | Registra el resultado final de `COMPLETED` o `FAILED` y la duración, luego libera los recursos restantes de la llamada. |

### Procesamiento de medios opcional

| API o evento | Cuándo usarlo | Qué sucede después |
| - | - | - |
| [`whatsapp.call.recording.updated`](/es/api-reference/webhooks/test-webhooks) o [`whatsapp.call.transcription.updated`](/es/api-reference/webhooks/test-webhooks) | Cuando la captura esté habilitada y el procesamiento finalice. | Si el evento reporta `AVAILABLE`, lee su `mediaAssetId`. Un resultado `FAILED` es definitivo para ese activo. |
| [`GET /whatsapp/calls/media/{mediaAssetId}`](/api-reference/whatsapp-calling/download-call-media) | Solo después de que el evento correspondiente reporte `AVAILABLE`. | Descarga el archivo de grabación o transcripción. |

Estas tablas describen el flujo de trabajo de la aplicación. No garantizan que los webhooks se entreguen en el mismo orden que las filas. Correlaciona los eventos por `wacid` y gestiona las reentregas de forma idempotente.

## Antes de comenzar

Antes de realizar una solicitud de Calling, prepara lo siguiente:

1. Una clave de API de la cuenta de YCloud. Envíala en el encabezado `X-API-Key`. Consulta [Autenticación](/es/api-reference/guides/api-fundamentals/authentication).
2. Una cuenta de WhatsApp Business y un número de teléfono comercial registrado con YCloud.
3. Calling habilitado para ese número de teléfono.
4. Una implementación de audio WebRTC que pueda crear y aplicar ofertas y respuestas SDP.
5. Un endpoint de webhook de YCloud suscrito a los eventos de Calling utilizados por tu integración. Consulta [Configurar webhooks](/es/api-reference/guides/api-fundamentals/configure-webhooks).
6. Permiso de llamada del usuario cuando sea necesario para una llamada iniciada por la empresa.

Comunícate con tu representante de YCloud para habilitar el acceso a la Calling API. Para la elegibilidad de llamadas salientes, sigue los [requisitos actuales de Calling](/es/documentation/calling/overview#business-initiated-calls-outbound), incluido el nivel de mensajería para 2000 clientes de la cartera comercial y los países admitidos para números comerciales. El antiguo umbral de 1000 conversaciones queda sustituido por los requisitos actuales.

Los siguientes ejemplos utilizan estas variables de entorno:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
export YCLOUD_API_KEY="YOUR_API_KEY"
export WABA_ID="YOUR_WABA_ID"
export BUSINESS_PHONE_NUMBER="+16315551111"
```

Mantén la clave de API en tu servidor. No la incluyas en el código del navegador ni de aplicaciones móviles.

## Cómo funciona

Comienza configurando el número de teléfono comercial. Luego intercambia SDP según la dirección de la llamada. Las respuestas de la API confirman las operaciones de señalización individuales, mientras que los eventos de webhook notifican los cambios de estado y el resultado final. Si la captura está habilitada, eventos separados indican cuándo una grabación o transcripción está lista para descargarse.

## Solicitud

## Configura el número de teléfono comercial

La configuración de Calling y de captura pertenece a un número de teléfono comercial de WhatsApp específico. Configúralos antes de procesar llamadas.

### Consultar la configuración de Calling

Usa [`GET /whatsapp/phoneNumbers/{wabaId}/{phoneNumber}/settings`](/api-reference/whatsapp-phone-numbers/retrieve-phone-number-settings) para verificar si Calling está habilitado y si el ícono de Calling está visible:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request GET \
  "https://api.ycloud.com/v2/whatsapp/phoneNumbers/$WABA_ID/$BUSINESS_PHONE_NUMBER/settings?type=calling" \
  --header "X-API-Key: $YCLOUD_API_KEY"
```

Si omites `type`, YCloud devuelve la respuesta con la configuración de Calling.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "calling": {
    "id": "19213232132",
    "status": "ENABLED",
    "iconVisibility": "DEFAULT"
  }
}
```

| Campo | Valores | Descripción |
| - | - | - |
| `calling.id` | String | ID del número de teléfono comercial de WhatsApp. |
| `calling.status` | `ENABLED`, `DISABLED` | Si Calling está habilitado para el número de teléfono. |
| `calling.iconVisibility` | `DEFAULT`, `DISABLE_ALL` | Si WhatsApp utiliza su comportamiento predeterminado para el ícono de Calling o si oculta todos los íconos de Calling. |

### Habilitar Calling

Guarda la configuración de Calling con [`POST /whatsapp/phoneNumbers/{wabaId}/{phoneNumber}/settings`](/api-reference/whatsapp-phone-numbers/save-phone-number-settings) antes de comenzar a aceptar o realizar llamadas:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST \
  "https://api.ycloud.com/v2/whatsapp/phoneNumbers/$WABA_ID/$BUSINESS_PHONE_NUMBER/settings" \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "calling": {
      "status": "ENABLED",
      "iconVisibility": "DEFAULT"
    }
  }'
```

La respuesta contiene el objeto `calling` guardado. Antes de gestionar llamadas en vivo, termina de configurar tus webhooks y sesiones de WebRTC.

### Configurar la grabación y transcripción

La configuración de captura se aplica a las nuevas llamadas originadas mediante la API. Puedes habilitar la grabación, la transcripción o ambas.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST \
  "https://api.ycloud.com/v2/whatsapp/phoneNumbers/$WABA_ID/$BUSINESS_PHONE_NUMBER/settings" \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "capture": {
      "recordingEnabled": true,
      "transcriptionEnabled": true,
      "purpose": "quality_assurance",
      "announcementLanguage": "en_US"
    }
  }'
```

| Campo | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `capture.recordingEnabled` | Boolean | Sí | Habilita o deshabilita la captura de grabación. |
| `capture.transcriptionEnabled` | Boolean | Sí | Habilita o deshabilita la captura de transcripción. |
| `capture.purpose` | String | Condicional | Obligatorio cuando alguna de las opciones de captura está habilitada. Máximo de 250 caracteres. |
| `capture.announcementLanguage` | String | Condicional | Obligatorio cuando alguna de las opciones de captura está habilitada. Valores admitidos: `en`, `en_US`, `en_AU`, `en_CA`, `en_GB`, `en_IN`, `en_NZ`, `nl`, `fr`, `de`, `hi`, `it`, `kn`, `pt`, `es`, `es_ES`, `te`, `vi`. |

Para consultar la configuración de captura, usa `type=capture`:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request GET \
  "https://api.ycloud.com/v2/whatsapp/phoneNumbers/$WABA_ID/$BUSINESS_PHONE_NUMBER/settings?type=capture" \
  --header "X-API-Key: $YCLOUD_API_KEY"
```

Puedes incluir `calling` y `capture` en la misma solicitud `POST`. Tras validar el acceso al número de teléfono, YCloud intenta guardar cada sección por separado. Si alguna de ellas falla al guardarse, es posible que la otra sección ya haya quedado almacenada. Lee ambas configuraciones después de un error y, a continuación, vuelve a intentar solo la sección que aún requiera actualizarse.

## Gestionar una llamada iniciada por el usuario

![Secuencia de Calling iniciada por el usuario](https://files.readme.io/65fa96a2414cfde54dbf36c30af6e6392ca36093d478674c23547879a14f9c4c-image.png)

En una llamada iniciada por el usuario, WhatsApp envía la oferta SDP. Tu aplicación responde a esa oferta y luego acepta o rechaza la llamada.

### 1. Recibir el evento de conexión

Suscríbete a [`whatsapp.call.connect`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-connect-webhook-examples). Un evento iniciado por el usuario tiene `direction` establecido en `USER_INITIATED` e incluye un SDP `offer`.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "evt_call_connect_123",
  "type": "whatsapp.call.connect",
  "apiVersion": "v2",
  "createTime": "2024-01-01T12:00:00.000Z",
  "callingConnect": {
    "id": "6757b723960b25543b9ecc66",
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABIYIEF",
    "phoneId": "461269257068832",
    "from": "+6281361905133",
    "to": "+6283138205150",
    "direction": "USER_INITIATED",
    "dialTime": 1733826430000,
    "sdpType": "offer",
    "sdp": "SDP_OFFER"
  }
}
```

Almacena `callingConnect.wacid` y `callingConnect.phoneId` juntos. Aplica la oferta SDP recibida a tu conexión de pares WebRTC y genera una respuesta SDP.

### 2. Preaceptar la llamada

Llama a la operación de preaceptación después de crear una respuesta SDP, pero antes de que el agente acepte la llamada. Esto prepara la ruta de medios y puede reducir los cortes de audio cuando se responde a la llamada.

**Endpoint:** [`POST /whatsapp/calls/preAccept`](/api-reference/whatsapp-calling/pre-accept-a-call)

| Campo | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `phoneId` | String | Sí | ID del número de teléfono comercial proveniente del evento de conexión. |
| `wacid` | String | Sí | ID de la llamada de WhatsApp proveniente del evento de conexión. |
| `sdpType` | String | Sí | Debe ser `answer`. |
| `sdp` | String | Sí | Respuesta SDP generada por tu implementación de WebRTC. |

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.ycloud.com/v2/whatsapp/calls/preAccept \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "phoneId": "461269257068832",
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABIYIEF",
    "sdpType": "answer",
    "sdp": "SDP_ANSWER"
  }'
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABIYIEF",
  "success": true
}
```

Una vez que la preaceptación se complete con éxito, mantén la llamada en estado de repique o lista. La preaceptación no contesta la llamada por el usuario.

### 3. Aceptar la llamada

Cuando el agente conteste, envía el mismo `phoneId`, `wacid`, tipo de SDP y respuesta SDP al endpoint de aceptación.

**Endpoint:** [`POST /whatsapp/calls/accept`](/api-reference/whatsapp-calling/accept-a-call)

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.ycloud.com/v2/whatsapp/calls/accept \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "phoneId": "461269257068832",
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABIYIEF",
    "sdpType": "answer",
    "sdp": "SDP_ANSWER"
  }'
```

Los campos de la solicitud y la estructura de la respuesta son los mismos que en la preaceptación. Tras una respuesta exitosa, utiliza el estado de la conexión WebRTC para la preparación del contenido multimedia y espera a `whatsapp.call.terminate` para obtener el resultado final de la llamada.

La ventana documentada para la aceptación entrante es de aproximadamente 30 a 60 segundos después
del webhook de conexión. Acepta con prontitud; una llamada no contestada finaliza del lado
del usuario con una notificación de **Not Answered** y un webhook de terminación.

Incluso si la conexión WebRTC ya está establecida, inicia el audio únicamente después
de que la solicitud de aceptación devuelva HTTP `200`. Comenzar antes puede recortar las primeras
palabras; comenzar demasiado tarde produce silencio.

### Rechazar en lugar de aceptar

Si el agente no puede atender la llamada entrante, recházala en lugar de crear una sesión activa.

**Endpoint:** [`POST /whatsapp/calls/reject`](/api-reference/whatsapp-calling/reject-a-call)

| Campo | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `phoneId` | String | Sí | ID del número de teléfono comercial proveniente del evento de conexión. |
| `wacid` | String | Sí | ID de la llamada de WhatsApp proveniente del evento de conexión. |

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.ycloud.com/v2/whatsapp/calls/reject \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "phoneId": "461269257068832",
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABIYIEF"
  }'
```

La respuesta utiliza la respuesta estándar de llamadas. Libera la conexión de pares local tras la solicitud y aun así acepta un evento de terminación posterior para este `wacid` si llega a recibirse.

## Iniciar una llamada originada por la empresa

En una llamada originada por la empresa, tu aplicación crea la oferta SDP y la envía a YCloud.

### Obtener permiso para llamar

Antes de iniciar una llamada, obtén el permiso de llamada del usuario. Se puede enviar una solicitud
de permiso interactiva dentro de una ventana de servicio al cliente válida:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "from": "+16315551111",
  "to": "+16315552222",
  "type": "interactive",
  "interactive": {
    "type": "call_permission_request",
    "action": { "name": "call_permission_request" },
    "body": { "text": "May we call you to help with your order?" }
  }
}
```

Envía este cuerpo a `POST /v2/whatsapp/messages/sendDirectly` o ponlo en cola con
`POST /v2/whatsapp/messages`.

También puedes crear una plantilla de permiso de llamada. Por ejemplo, envía este cuerpo
a `POST /v2/whatsapp/templates`, luego espera la aprobación:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "wabaId": "WABA_ID",
  "name": "call_permission_request_template",
  "language": "en_US",
  "category": "UTILITY",
  "components": [
    {
      "type": "BODY",
      "text": "May we call you about order {{1}}?",
      "example": { "body_text": [["ORDER_123"]] }
    },
    { "type": "call_permission_request" }
  ]
}
```

Envía la plantilla aprobada con su parámetro en el cuerpo:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "from": "+16315551111",
  "to": "+16315552222",
  "type": "template",
  "template": {
    "name": "call_permission_request_template",
    "language": { "code": "en_US", "policy": "deterministic" },
    "components": [
      { "type": "body", "parameters": [{ "type": "text", "text": "ORDER_123" }] }
    ]
  }
}
```

Cuando `callback_permission_status` está habilitado en la configuración de llamadas
del número de teléfono, una llamada iniciada por el usuario puede otorgar permiso para devolver la llamada. Un usuario también puede
otorgar permiso permanente de llamada desde el perfil comercial.

Las respuestas de permiso llegan como eventos `whatsapp.inbound_message.received`. Inspecciona
el objeto `interactive.call_permission_reply`, no solo si se entregó el mensaje de
solicitud de permiso:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "type": "whatsapp.inbound_message.received",
  "whatsappInboundMessage": {
    "from": "+16315552222",
    "to": "+16315551111",
    "type": "interactive",
    "interactive": {
      "type": "call_permission_reply",
      "call_permission_reply": {
        "response": "accept",
        "is_permanent": true,
        "response_source": "user_action"
      }
    }
  }
}
```

| Campo | Significado |
| - | - |
| `response` | El usuario aceptó o rechazó la solicitud de permiso. |
| `is_permanent` | Indica si la concesión es permanente en lugar de limitada en el tiempo. |
| `expiration_timestamp` | Vencimiento de un permiso temporal, cuando se proporcione. |
| `response_source` | Indica si la respuesta provino de una acción del usuario o de forma automática. |

No inicies la llamada tras un rechazo o un permiso vencido. El error de Meta
`138006` significa que el número comercial no cuenta con el permiso de llamada requerido.
Para ver detalles de errores del proveedor, consulta [los errores de llamadas de Meta](https://developers.facebook.com/documentation/business-messaging/whatsapp/calling/reference/errors).

### 1. Crear una oferta SDP

Crea una conexión de pares WebRTC local y vincula la pista de audio. Genera la oferta SDP, establécela como la descripción local y espera a que esa operación finalice antes de enviar la oferta a YCloud.

### 2. Conectar la llamada

**Endpoint:** [`POST /whatsapp/calls/connect`](/api-reference/whatsapp-calling/connect-a-call)

| Campo | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `from` | String | Sí | Número de teléfono comercial registrado en formato E.164. |
| `to` | String | Condicional | Número de teléfono del usuario en formato E.164. Obligatorio si no se incluye `recipient`. |
| `recipient` | String | Condicional | BSUID del usuario o BSUID principal. Obligatorio si no se incluye `to`. |
| `sdpType` | String | Sí | Debe ser `offer`. |
| `sdp` | String | Sí | Oferta SDP creada por tu implementación de WebRTC. |

Proporciona al menos uno de entre `to` o `recipient`. Si envías ambos, YCloud usa `to` e ignora `recipient`.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.ycloud.com/v2/whatsapp/calls/connect \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "from": "+16315551111",
    "to": "+16315552222",
    "sdpType": "offer",
    "sdp": "SDP_OFFER"
  }'
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABE",
  "success": true
}
```

Almacena inmediatamente el valor de `wacid` devuelto. `success: true` significa que la operación de conexión fue aceptada; no significa que el usuario haya contestado.

### 3. Aplicar la respuesta y rastrear el intento

YCloud envía [`whatsapp.call.connect`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-connect-webhook-examples) para la llamada. Para una llamada iniciada por el negocio, el evento tiene `direction: BUSINESS_INITIATED` y transporta el SDP remoto `answer`. Aplica esa respuesta como la descripción remota para la misma conexión de pares.

Suscríbete a [`whatsapp.call.status.updated`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-status-update-webhook-examples) para rastrear el intento:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "evt_676e5ab57a9cb742d02d7646",
  "type": "whatsapp.call.status.updated",
  "apiVersion": "v2",
  "createTime": "2024-12-27T07:41:28.422Z",
  "callingStatusUpdated": {
    "wabaId": "188234691048809",
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABE",
    "phoneId": "461269257068832",
    "status": "RINGING",
    "recipientPhone": "+16315552222"
  }
}
```

| Estado | Significado | Acción recomendada |
| - | - | - |
| `RINGING` | La llamada está sonando para el usuario. | Mantén el intento abierto y continúa esperando. |
| `ACCEPTED` | El usuario aceptó la llamada. | Utiliza el estado de la conexión WebRTC para confirmar la preparación del contenido multimedia. |
| `REJECTED` | El usuario rechazó la llamada. | Detén el intento y libera los recursos locales de WebRTC. |

Haz que el procesamiento de eventos sea idempotente para que una reentrega no repita acciones del agente, cobros o tareas de limpieza.

## Finalizar una llamada activa

Llama al endpoint de terminación cuando tu aplicación necesite finalizar una llamada activa entrante o saliente.

**Endpoint:** [`POST /whatsapp/calls/terminate`](/api-reference/whatsapp-calling/terminate-a-call)

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.ycloud.com/v2/whatsapp/calls/terminate \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "phoneId": "461269257068832",
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABE"
  }'
```

Los campos de la solicitud coinciden con los de la solicitud de rechazo. Una respuesta exitosa confirma que YCloud procesó la operación de terminación. Mantén abierto el registro de la llamada hasta que recibas el evento de terminación final o tu propia política de recuperación lo cierre.

## Respuesta

Los cinco endpoints de señalización devuelven la misma estructura de respuesta:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABE",
  "success": true
}
```

`wacid` identifica la llamada asociada a la operación. `success: true` confirma que la operación de señalización fue exitosa; no confirma que el otro participante haya respondido o que la llamada haya finalizado. Utiliza el estado de WebRTC y los eventos del webhook de Calling para conocer esos resultados.

## Procesar el evento final de la llamada

[`whatsapp.call.terminate`](/es/api-reference/guides/examples/webhook-examples/whatsapp-calling-terminate-webhook-examples) es el evento terminal del ciclo de vida de una llamada.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "evt_6757b889a5a42d369ef48481",
  "type": "whatsapp.call.terminate",
  "apiVersion": "v2",
  "createTime": "2024-12-10T03:42:01.822Z",
  "callingTerminate": {
    "id": "6757b889960b25543b9ecc67",
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABIYIEFENjB",
    "phoneId": "461269257068832",
    "from": "+6281361905133",
    "to": "+6283138205150",
    "direction": "USER_INITIATED",
    "startTime": 1733734738000,
    "endTime": 1733734771000,
    "duration": 33,
    "status": "COMPLETED"
  }
}
```

| Campo | Descripción |
| - | - |
| `wacid` | ID de la llamada utilizado para hacer coincidir el evento con tu registro de llamada. |
| `direction` | `USER_INITIATED` o `BUSINESS_INITIATED`. |
| `startTime`, `endTime` | Marcas de tiempo Unix en milisegundos. |
| `duration` | Duración de la llamada en segundos. |
| `status` | Resultado final: `COMPLETED` o `FAILED`. |
| `errorCode` | Código de error numérico representado como una cadena cuando la llamada falló. |

Cuando recibas este evento, finaliza el registro de la llamada y libera los recursos restantes de WebRTC. Una respuesta anterior de la API no confirma que la llamada se haya completado.

## Recibir grabaciones y transcripciones

Cuando la captura está habilitada, el procesamiento del contenido multimedia continúa después del ciclo de vida de la llamada. La grabación y la transcripción tienen eventos terminales independientes:

| Evento | Propiedad de la carga útil | Resultado |
| - | - | - |
| [`whatsapp.call.recording.updated`](/es/api-reference/webhooks/test-webhooks) | `callingRecording` | La grabación está `AVAILABLE` o ha fallado definitivamente (`FAILED`). |
| [`whatsapp.call.transcription.updated`](/es/api-reference/webhooks/test-webhooks) | `callingTranscription` | La transcripción está `AVAILABLE` o ha fallado definitivamente (`FAILED`). |

El siguiente ejemplo muestra una grabación disponible:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "evt_call_recording_01JZ8K4V7H3P6Q9R2T5W8X1Y4Z",
  "type": "whatsapp.call.recording.updated",
  "apiVersion": "v2",
  "createTime": "2026-08-04T08:00:00.000Z",
  "callingRecording": {
    "wacid": "wacid.HBgNNjI4MTM2MTkwNTEzMxUCABE",
    "phoneId": "461269257068832",
    "mediaAssetId": "66b1f0c2e4b05c2d8f1a3b47",
    "status": "AVAILABLE"
  }
}
```

Ambas propiedades de la carga útil utilizan los mismos campos:

| Campo | Descripción |
| - | - |
| `wacid` | ID de la llamada asociado con el recurso multimedia. |
| `phoneId` | ID del número de teléfono comercial asociado con la llamada. |
| `mediaAssetId` | ID del recurso de YCloud utilizado por la API de descarga de medios. |
| `status` | `AVAILABLE` o `FAILED`. |
| `error.code` | Código estable de error de procesamiento. Presente cuando `status` es `FAILED`. |
| `error.retryable` | Indica si reintentar la operación de medios ascendente puede tener éxito. Presente cuando `status` es `FAILED`. |

### Descargar un recurso disponible

Llama al endpoint de medios solo después de que el evento correspondiente reporte `AVAILABLE`.

**Endpoint:** [`GET /whatsapp/calls/media/{mediaAssetId}`](/api-reference/whatsapp-calling/download-call-media)

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request GET \
  "https://api.ycloud.com/v2/whatsapp/calls/media/66b1f0c2e4b05c2d8f1a3b47" \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --output calling-media.ogg
```

El endpoint devuelve el archivo completo como archivo adjunto y no admite descargas por rango de bytes. Las grabaciones usan `.ogg`; las transcripciones usan `.json`.

Solo el tenant propietario de YCloud puede descargar un recurso. Un recurso permanece disponible durante 30 días a partir de su fecha de creación. Los recursos faltantes, no disponibles, vencidos o que no sean de tu propiedad devuelven HTTP 404.

## Crear un receptor de webhook confiable

Suscribe tu endpoint a los eventos que tu integración requiera:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "enabledEvents": [
    "whatsapp.call.connect",
    "whatsapp.call.status.updated",
    "whatsapp.call.terminate",
    "whatsapp.call.recording.updated",
    "whatsapp.call.transcription.updated"
  ]
}
```

Para cada solicitud:

1. Conserva el cuerpo sin procesar de la solicitud y verifica `YCloud-Signature` antes de confiar en el evento.
2. Guarda el evento o pon en cola el trabajo duradero.
3. Devuelve una respuesta `2xx` exitosa con prontitud.
4. Deduplica mediante el evento de nivel superior `id`.
5. Correlacione los datos de la llamada mediante `wacid`; conserve `phoneId` junto con este para operaciones posteriores.
6. Gestione los eventos relacionados que lleguen muy seguidos y tolere reenvíos.

Consulte [Configurar webhooks](/es/api-reference/guides/api-fundamentals/configure-webhooks) para ver la creación de endpoints, validación de firmas y el comportamiento de entrega. La página [Ejemplos de carga útil de Webhook](/es/api-reference/guides/examples/webhook-examples/webhook-payload-examples) contiene los ejemplos completos generados.

## Gestión de errores y recuperación

Los endpoints de llamadas utilizan la respuesta estándar de error de la API de YCloud. Consulte [Gestionar errores](/es/api-reference/guides/api-fundamentals/handle-errors) para ver la estructura de respuesta y las pautas de reintento.

Use estas comprobaciones para fallos comunes de llamadas:

| Situación | Qué comprobar | Recuperación |
| - | - | - |
| Falla la validación de la solicitud | ID requeridos, formato E.164, tipo de SDP, contenido de SDP o campos de captura. | Corrija la solicitud. No reintente con los mismos datos sin modificar. |
| El destino de conexión no es válido | Se requiere al menos uno de `to` o `recipient`. Si ambos están presentes, `to` tiene prioridad. | Envíe un número de teléfono E.164 o BSUID válido. |
| El servicio de llamadas no está disponible | Titularidad del número de teléfono, registro, configuración de llamadas, permisos y destino admitido. | Corrija la configuración o los permisos antes de reintentar. |
| Meta rechaza la señalización | Inspeccione los detalles del error devuelto, incluido `whatsappApiError` cuando esté presente. | Siga la posibilidad de reintento del error y corrija la causa previa. |
| Falla el guardado combinado de ajustes | Es posible que uno de `calling` o `capture` ya se haya guardado. | Lea ambos ajustes y, luego, reintente solo la parte que aún requiera una actualización. |
| La descarga de medios devuelve 400 | Se envió un encabezado `Range` no vacío. | Solicite el recurso completo sin `Range`. |
| La descarga de medios devuelve 404 | El recurso no existe, aún no está disponible, ha caducado o pertenece a otro inquilino. | Confirme el estado del evento, el inquilino, el ID del recurso y el periodo de 30 días. |
| El webhook está duplicado | El mismo evento se entregó de nuevo. | Devuelva `2xx` y omita el procesamiento comercial repetido por el `id` del evento. |

Un tiempo de espera agotado en la solicitud no demuestra que la acción de señalización haya fallado. Antes de reintentar, coteje la solicitud con los eventos de webhook y el estado local actual de la llamada. Es posible que la acción ya haya llegado a WhatsApp.

## Lista de verificación para la integración

* Habilite las llamadas en el número de teléfono comercial correcto.
* Configure y pruebe todas las suscripciones de webhook de llamadas requeridas.
* Verifique las firmas de webhook y deduplique los eventos.
* Almacene `wacid`, `phoneId`, la dirección y el estado actual juntos.
* Considere el `success` de la API como la aceptación de la operación, no como el resultado final de la llamada.
* Use `preAccept` solo como preparación; llame a `accept` para responder.
* Finalice las llamadas a partir de `whatsapp.call.terminate`.
* Descargue los medios capturados solo después de un evento `AVAILABLE` y dentro del plazo de 30 días.
* Libere los recursos de WebRTC en caso de rechazo, finalización, fallo y tiempo de espera local agotado.
* Evite registrar claves de API, SDP completo o identificadores de participantes en los registros generales de la aplicación.

<CardGroup cols={2}>
  <Card title="Referencia de la API de llamadas" icon="phone" href="/api-reference/whatsapp-calling/connect-a-call">
    Revise los esquemas exactos de solicitud y respuesta para cada endpoint de llamadas.
  </Card>

  <Card title="Ejemplos de carga útil de Webhook" icon="webhook" href="/es/api-reference/guides/examples/webhook-examples/webhook-payload-examples">
    Inspeccione los ejemplos completos de eventos de llamadas generados a partir de la especificación de webhooks.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.