# API

Una llamada saliente desde su sistema: un evento de CRM, un formulario, una devolución de llamada perdida. Una lista en un horario es [Campaigns](../campaigns/), no este endpoint.

La configuración de [Outgoing](../outgoing/) del agent sigue aplicándose. Esta solicitud elige el número, el agent y el contexto adicional opcional para *esta* llamada.

## Antes de llamar

1. El plan incluye **Allow Outbound Calls**.
2. [Clave API](https://docs.voicelogica.ai/es/getting-started/api-keys/) con el grupo **Calls**.
3. Un trunk (o teléfono VoIP) desde el cual marcar - [Su propio operador](https://docs.voicelogica.ai/es/telephony/your-own-carrier/) / [Números de Voice Logica](https://docs.voicelogica.ai/es/telephony/voice-logica-numbers/).
4. El **agent id** - desde la URL del agent en **My Agents**, o **Copy** en una fila de campaña.

## Primera configuración - una llamada, luego Calls

```
POST https://api.voicelogica.ai/api/v1/phones/calls/initiate-call
```

```http
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

Resellers: opcional `x-company-id` para actuar sobre una subsidiaria. Sin él, se usa la propia empresa de la clave.

Envíe **`destinationNumber`** y **`agentId`**. Envíe **`sipTrunkId`** o **`voipPhoneId`** a menos que la empresa ya tenga una ruta saliente / trunk predeterminado que pueda llevar la llamada - si no se envía ninguno y no se puede resolver un trunk, la API devuelve que no se especificó un SIP trunk activo o teléfono VoIP.

**Trunk (usual):**

```bash
curl -X POST https://api.voicelogica.ai/api/v1/phones/calls/initiate-call \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sipTrunkId": "your_sip_trunk_id",
    "destinationNumber": "+14155552671",
    "agentId": "your_agent_id"
  }'
```

**VoIP phone id** aún funciona - el servidor lo resuelve a un trunk.

El éxito es `{ "callId": "..." }`. Si el destino está fuera del horario local 09:00–21:00, puede obtener `"scheduled": true` más `scheduleTime` y `reason`. Abra **Calls** y escuche.

`destinationNumber` en E.164 (`+14155552671`).

## Qué puede enviar

**Requerido para una llamada saliente de IA**

| Campo | Qué hace |
|-------|----------------|
| `destinationNumber` | Número a llamar. |
| `agentId` | Agent que habla. Requerido para llamadas salientes de IA; opcional solo para `isInternalCall`. |

**Origen de la llamada - envíe uno, o confíe en el predeterminado saliente de la empresa**

| Campo | Qué hace |
|-------|----------------|
| `sipTrunkId` | Trunk desde **Telephony → Trunks**. Prefiera esto. |
| `voipPhoneId` | ID de línea heredado. Se resuelve a un trunk. |
| `callerId` | E.164 o SIP URI mostrado al destinatario. Debe ser un número que el trunk pueda presentar. |

**Solo esta llamada**

| Campo | Qué hace |
|-------|----------------|
| `contextForAi` | Se agrega al prompt del sistema para esta llamada. |
| `dynamicVariables` | Pares clave/valor de cadena que el prompt puede usar (`{{customer_name}}`). |
| `superVariables` | Valores tipados: `{ placeholder, value, type }` - `text` / `number` / `boolean` / `date` / `time`. |
| `metadata` | Su seguimiento. Almacenado en la llamada. Las claves que comienzan con `scenario_` se eliminan. |
| `emailAddress` | Dónde enviar el resumen / grabación. |
| `welcomeMessageOverride` | Se habla en lugar del saludo del agent. |
| `isWelcomeMessageAIGenerated` | La IA escribe el saludo para esta llamada. |
| `scheduledAt` | Fecha ISO. Llamar más tarde en lugar de ahora. |
| `maxRetries` | 1–3 si ocupado / sin respuesta / buzón de voz. Predeterminado 3. |
| `retryDelayMinutes` | 30–1440. Predeterminado 30. |
| `additionalPhoneNumbers` | Números adicionales en la misma solicitud. |

No envíe `fromNumber`. El contrato público es `sipTrunkId` / `voipPhoneId`.

## Protecciones (solo salientes)

Las llamadas entrantes nunca están restringidas.

- **Hora** (activado) - 09:00–21:00 en la hora local del país de *destino*. Fuera de eso, la llamada se bloquea o programa. Omisión: `overrideTimeRestriction: true`.
- **Día** (activado) - los fines de semana / feriados pueden estar bloqueados por el país de destino. Omisión: `overrideDayRestriction: true`.
- **Anti-acoso** (desactivado a menos que envíe `useAntiHarassmentProtection: true`) - máximo 3 llamadas exitosas y 3 fallidas por número por día, 1 hora entre llamadas exitosas, máximo 5 exitosas por semana, sin llamada activa/programada duplicada. Los **Allowed test numbers** de la campaña omiten esto.

Omitir las reglas de hora o día puede violar la ley local. Active el anti-acoso para cualquier trabajo de contacto repetido.

## Si falla

El cuerpo es `{ "error": "<code>", "reason": "<message>" }`.

| Código | Significado |
|------|---------|
| `call_already_in_progress` | Ya existe una llamada en vivo o programada a este número. |
| `agent_not_found` / `voip_phone_not_found` | ID incorrecto. |
| `daily_call_limit_reached` | 3 llamadas exitosas a este número hoy (anti-acoso). |
| `failed_call_limit_reached` | 3 intentos fallidos hoy. |
| `cooldown_period_active` | Espere 1 hora después de una llamada exitosa a este número. |
| `weekly_call_limit_reached` | 5 llamadas exitosas esta semana. |
| `call_already_scheduled` / `failed_to_schedule_call` | Conflicto de horario. |
| `callee_opted_out` | Este número pidió no ser llamado nuevamente. |
| `insufficient_credits` / `no_seconds_available` / `no_channels_available` / `no_concurrent_calls_available` | Plan / créditos. |
| `maximum_authentication_attempts_exceeded` | Teléfono desactivado después de repetidos fallos de autenticación. |

402 es facturación. 400 es una solicitud incorrecta o una protección. 500 es el servidor de llamadas - reintente más tarde.

## Ejemplo

```typescript
const response = await fetch('https://api.voicelogica.ai/api/v1/phones/calls/initiate-call', {
  method: 'POST',
  headers: { 'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    destinationNumber: '+14155552671',
    agentId: 'your_agent_id',
    sipTrunkId: 'your_sip_trunk_id',
    contextForAi: 'Customer asked about order ORD123',
    dynamicVariables: { customer_name: 'Ada', order_id: 'ORD123' },
    useAntiHarassmentProtection: true,
  }),
});
const result = await response.json();
if (result.callId) console.log(result.callId);
else console.error(result.error, result.reason);
```

Programación + reintentos:

```json
{
  "destinationNumber": "+14155552671",
  "agentId": "your_agent_id",
  "sipTrunkId": "your_sip_trunk_id",
  "scheduledAt": "2026-09-16T14:30:00Z",
  "maxRetries": 2,
  "retryDelayMinutes": 120
}
```

`scheduledAt` se convierte a la zona del país de destino. Las protecciones siguen aplicándose a menos que las anule.

## Qué aspecto tiene "roto"

- 400 "no active SIP trunk" - envíe `sipTrunkId`, o agregue un trunk con números y un predeterminado saliente.
- `scheduled: true` cuando esperaba ahora - la hora local de destino está fuera de 09:00–21:00.
- El agent habla sobre "hola" - [Outgoing](../outgoing/) **Who speaks first**, no esta carga útil.
- Llamada faltante en **Calls** - empresa incorrecta (`x-company-id`), o la solicitud nunca devolvió un `callId`.

## Solución de problemas

**fromNumber solía funcionar**

El cuerpo público es `sipTrunkId` o `voipPhoneId`. Envíe el trunk id desde **Telephony → Trunks**.

**Publiqué ahora y obtuve scheduled: true**

Restricción de hora o día. Espere la ventana, o configure `overrideTimeRestriction` / `overrideDayRestriction` solo si tiene permitido hacerlo.

## ¿Está construyendo algo?

Escriba a [developers@voicelogica.ai](mailto:developers@voicelogica.ai) - créditos de prueba adicionales y ayuda con la integración.

- REFERENCIA API [api.voicelogica.ai/api-docs](https://api.voicelogica.ai/api-docs)
- DESARROLLADORES [developers@voicelogica.ai](mailto:developers@voicelogica.ai)
- SOPORTE [support@voicelogica.ai](mailto:support@voicelogica.ai)
