Haz una campaña de calificación de leads con IA con Wixzel Voice
Al final habrás subido una lista de leads, un agente que tú escribiste habrá llamado a cada uno por tu propia troncal SIP con tus preguntas de calificación, y habrás leído el estado y la transcripción de cada llamada. La implementación lleva unos 30 minutos en Node.js con el SDK wixzel-voice, más lo que tarden las llamadas. Las llamadas cortas con guion son la carga más barata: con el motor classic, a $0.0867 por minuto conectado, 1000 llamadas de dos minutos suman unos $173 de tiempo de motor, facturados por segundo desde un saldo prepago, más la tarifa de tu operador. Una llamada que nadie contesta no cuesta nada.
Por Aqeel Shamsudheen · Publicado el · Actualizado el
- Duración
- Unos 30 minutos, más las llamadas
- Motor
- classic
- Tiempo de motor
- $0.0867 por minuto conectado
¿Qué necesitas antes de empezar?
- Una troncal SIP y un número saliente registrado en ella. La guía de Twilio y la documentación de troncales SIP explican ambas cosas.
- Una clave de API de Wixzel Voice con crédito, y Node.js 20 o posterior con
npm install wixzel-voice. - El consentimiento para llamar a cada lead de la lista donde la ley lo exija. El paso de cumplimiento de abajo resume lo que pide la Política de uso aceptable.
¿Cómo construyes esto en Wixzel Voice, paso a paso?
01Escribe el agente que llama
El agente es el guion. Los campos de combinación personalizan cada llamada:
agent.mjsimport { WixzelVoice } from 'wixzel-voice'; const client = new WixzelVoice({ apiKey: process.env.WIXZEL_API_KEY }); const agent = await client.agents.create({ name: 'Demo follow-up', outbound_phone_number_id: process.env.NUMBER_ID, system_prompt: [ 'You are calling {{name}} from {{company}}, who asked for a demo of Acme Scheduling.', 'Ask three questions, one at a time: how many staff take bookings,', 'what they use for bookings today, and when they would want to switch.', 'Keep replies short. If they are not interested, thank them and end the call.', 'If they ask not to be called again, confirm that you have noted it and end the call.', 'Finish by thanking them and saying a person will follow up by email.', ].join('\n'), opening_message: 'Hi {{name}}, this is an automated assistant calling for Acme about the demo you requested. Is now a good time?', voice: { stt: { model: 'deepgram/nova-3', language: 'en-US' }, llm: { model: 'openrouter/gpt-4o-mini' }, tts: { model: 'elevenlabs/eleven_flash_v2_5' }, }, }); console.log('AGENT_ID', agent.id);{{name}}se toma del lead, y cada clave de losfieldsde un lead también se convierte en campo de combinación, así que{{company}}sale de la subida de abajo. La frase de apertura dice que la llamada es automática, que es donde va ese aviso cuando la ley lo exige.outbound_phone_number_ides obligatorio para las campañas: es el identificador de llamada que muestra cada llamada.02Sube los leads
El resto de la implementación es un solo script,
campaign.mjs. Empieza con la subida:campaign.mjs, part 1import { WixzelVoice } from 'wixzel-voice'; const client = new WixzelVoice({ apiKey: process.env.WIXZEL_API_KEY }); // From your CRM or a CSV: only people you have consent to call. const rows = [ { name: 'Priya Nair', phone_number: '+14155550111', fields: { company: 'Northside Physio' } }, { name: 'Sam Carter', phone_number: '+14155550112', fields: { company: 'Carter Auto' } }, ]; const upload = await client.leads.bulkCreate({ leads: rows }); console.log('created', upload.created_count, 'failed', upload.failed_count); for (const e of upload.errors) console.log('row', e.index, e.phone_number, e.error); const leadIds = upload.data.map((lead) => lead.id);En una petición caben hasta 1000 leads. Las filas se validan una a una, así que revisa
failed_countyerrorsen lugar de dar por hecho que llegó toda la lista. Una subida masiva no dispara webhooks.03Ejecuta campañas ajustadas a tu límite de llamadas simultáneas
Una campaña es un agente y una lista de leads. Crearla no llama a nadie;
startsí, y gasta crédito a medida que se conecta cada llamada.Hoy, una campaña hace sus llamadas en rápida sucesión en lugar de ponerlas en cola, y cada llamada cuenta para el límite de llamadas simultáneas de la cuenta, cinco por defecto. Un lead que supera el límite se registra como llamada fallida en lugar de esperar su turno. Por eso, recorre la lista en lotes no mayores que tu límite, y empieza el siguiente lote cuando el anterior haya terminado:
campaign.mjs, part 2const LIMIT = 5; // your account's concurrent-call limit, minus any calls you expect meanwhile const DONE = new Set(['completed', 'failed', 'busy', 'no-answer', 'canceled']); const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function finishedCalls(campaignId) { let finished = 0; for await (const call of await client.calls.list({ campaign_id: campaignId, limit: 100 })) { if (DONE.has(call.status)) finished++; } return finished; } const campaignIds = []; for (let i = 0; i < leadIds.length; i += LIMIT) { const batch = leadIds.slice(i, i + LIMIT); const campaign = await client.campaigns.create({ name: 'Demo follow-up ' + (i / LIMIT + 1), agent_id: process.env.AGENT_ID, lead_ids: batch, }); await client.campaigns.start(campaign.id); campaignIds.push(campaign.id); const giveUpAt = Date.now() + 30 * 60 * 1000; while ((await finishedCalls(campaign.id)) < batch.length && Date.now() < giveUpAt) { await sleep(15000); } }startresponde con la campaña enstatus: "running". Para detener un lote antes de tiempo,client.campaigns.pause(campaign.id)lo detiene y cuelga sus llamadas en curso; después la campaña muestrastatus: "stopped". Volver a iniciar una campaña detenida llama otra vez a todos sus leads, incluidos los que ya se llamaron, así que para continuar, crea una campaña nueva con los leads que aún no se han contactado.scheduled_atal crearla inicia la campaña a una hora fijada en lugar de constart.04Consulta cada llamada
Cada llamada es un registro con su estado, su costo y su transcripción, vinculado a su lead por
lead_id:campaign.mjs, part 3for (const campaignId of campaignIds) { for await (const call of await client.calls.list({ campaign_id: campaignId, limit: 100 })) { const detail = await client.calls.retrieve(call.id); const answers = detail.transcript .filter((line) => line.role === 'user') .map((line) => line.content) .join(' / '); console.log(call.lead_id, call.status, call.duration_seconds, call.failure_code, answers); } }statusindica si la llamada se conectó,failure_codepor qué no (17 ocupado, 19 sin respuesta, 21 rechazada por el operador) ycost_microscuánto costó. Un lead rechazado antes de marcar, por el límite de llamadas simultáneas o por falta de crédito, aparece comofailedsinfailure_code.La calificación en sí la decides tú. Wixzel Voice registra la conversación; la transcripción contiene las respuestas a tus tres preguntas, así que puntúala con tus propias reglas o tu propio modelo y escribe el resultado en tu CRM. El campo
summarypuede estar vacío, así que no dependas de él. Para reaccionar cuando terminan las llamadas en lugar de consultar periódicamente, suscríbete al webhookcallCompleted, que incluye los ids del lead y de la campaña con el estado y la duración de la llamada.05Cumple las normas sobre llamadas
La Política de uso aceptable deja estas obligaciones a quien llama, es decir, a ti. Esto es un resumen de esa política, no asesoramiento legal.
Llama solo a personas cuyo consentimiento tengas donde la ley lo exija. En Estados Unidos, eso suele significar consentimiento previo, expreso y por escrito para llamadas de marketing a móviles según la TCPA; en la India, las normas de preferencias del cliente de la TRAI; en el Reino Unido y la UE, la PECR y el RGPD.
Consulta los registros nacionales y estatales de exclusión de llamadas y tu propia lista de exclusión antes de cada subida. Cuando alguien pida que no le vuelvan a llamar, elimínalo pronto y de forma permanente: el agente puede terminar la llamada con educación, pero eliminar el lead es tarea de tu código.
Avisa de que la llamada es automática al inicio, donde la ley lo exija, como hace la frase de apertura de arriba; respeta las restricciones de horario de llamadas y conserva la prueba del consentimiento durante el tiempo que exija la ley.
¿Cuánto cuesta esto en Wixzel Voice?
Tiempo de motor para llamadas de 2 minutos con el motor classic a $0.0867 por minuto conectado: unos $0.17 por llamada. La telefonía es tu propia troncal con la tarifa de tu operador y no está incluida.
| Llamadas al mes | Minutos conectados | Costo de motor al mes |
|---|---|---|
| 1000 | 2000 | $173 |
| 5000 | 10.000 | $867 |
| 20.000 | 40.000 | $3,468 |
Solo se factura el tiempo conectado, por segundo. Una llamada ocupada, sin respuesta o rechazada antes de marcar no cuesta nada, porque el motor nunca arranca. Tu operador factura la línea por separado con sus propias tarifas, sin margen.
Prepago, sin suscripción y sin plan gratuito: agrega crédito desde $5 y el uso lo va consumiendo. Calcula tu propia combinación.
¿Qué límites de Wixzel Voice se aplican a esto?
- Una campaña llama a sus leads en rápida sucesión y no espera en cola por el límite de llamadas simultáneas, cinco por cuenta por defecto; los leads que lo superan se registran como fallidos. Divide la lista en lotes según tu límite, o pide uno más alto.
- Volver a iniciar una campaña detenida llama otra vez a todos sus leads. Continúa con una campaña nueva formada por los leads que aún no se han contactado.
- Cada campaña admite hasta 10 000 leads, y una cuenta admite hasta 500 campañas por defecto; el límite se amplía a petición.
- Wixzel Voice registra la llamada y su transcripción. Decidir quién califica y mantener tu lista de exclusión es tarea de tu código.
- Los cambios de comportamiento de Wixzel Voice se publican detrás de un encabezado
Wixzel-Versioncon fecha.
Preguntas frecuentes
¿Cómo hago una campaña de llamadas salientes con IA en Wixzel Voice?
POST /v1/leads/bulk, crea una campaña con un agente y esos leads, y POST /v1/campaigns/{id}/start hace que el agente llame a cada uno por tu propia troncal SIP, uno tras otro. Mantén cada campaña dentro de tu límite de llamadas simultáneas, porque un lead que lo supera se marca como fallido en lugar de ponerse en cola. Cada llamada es un registro con su estado, su transcripción y su costo, vinculado al lead por lead_id. Las llamadas sueltas se hacen con POST /v1/calls.¿Cuántas llamadas salientes pueden estar en curso a la vez?
¿Uso campañas o llamadas sueltas?
POST /v1/calls por lead desde tu propia cola te da un control más fino: cada llamada lleva un lead_id y una clave de idempotencia, y tú decides cuándo empieza la siguiente.¿Es legal hacer llamadas salientes con IA?
Dónde leer más
- Inicio rápidodocumentación
Una troncal, un número, un agente y una llamada.
- Agentesdocumentación
Instrucciones, frases de apertura e identificadores de llamada.
- Webhooksdocumentación
callCompleted, campaignCompleted y firmas.
- Referencia de la APIdocumentación
Leads, campañas y llamadas, campo por campo.
El caso de uso y el precio de un mes de llamadas de campaña.
Las normas completas sobre consentimiento, exclusión de llamadas, aviso y grabación.
Conecta la troncal en la que está tu identificador de llamada.
Acerca de Wixzel Voice
Wixzel Voice es una API de IA de voz para crear agentes de IA que hacen y contestan llamadas telefónicas reales a través de tu propia troncal SIP, o que hablan con personas en tus apps web y móviles. Una clave de API y un saldo prepagado cubren todos los motores de voz, con cobro por segundo de uso real.
Más guías
Claude, en Claude Code o claude.ai, haciendo una llamada real por tu troncal SIP y leyéndote la transcripción, con una confirmación antes de marcar.
Tu número actual de Twilio atendido por un recepcionista de IA que agenda citas en la API, hecho en Node.js.
Dos agentes telefónicos, uno en hindi y otro en malayalam, con los modelos de Sarvam para idiomas de la India, que atienden o hacen llamadas por tu troncal SIP.
Una app Flutter en la que los usuarios hablan con tu agente de voz por WebSocket, con la clave de API guardada en tu servidor y sin ningún número de teléfono.
Un agente Gemini Live llamando a un teléfono real por tu troncal SIP a partir de cuatro peticiones cURL, y el registro de la llamada con su transcripción y su costo.
Una mascota que habla en la esquina de tu sitio web, a la que los visitantes llaman desde el navegador, limitada a tus dominios y a tus límites diarios, con cada persona que llama registrada.
Una pantalla de Flutter con la mascota de tu agente, que mueve la boca con la voz del agente durante una llamada en tiempo real, con tu clave de API guardada en tu servidor.
Crea tu primer agente de voz

