import asyncio, csv
from collections import defaultdict
from telequick.client import TeleQuickClient
from telequick.method_id import MethodID
RETRY_CAUSES = {{17, 18, 19}} # busy, no-user-response, no-answer
async def run_campaign(csv_url: str):
client = TeleQuickClient(
"quic://engine.telequick.dev:9090",
"/etc/telequick/service-account.json",
)
final_cause: dict[str, int] = {{}}
retried: set[str] = set()
def on_event(payload):
sid, status = client.deserialize_call_event(payload)
# Real apps should parse the full CallEvent for q850_cause; this
# shorthand uses status as a proxy.
if status in ("BUSY", "NO_ANSWER"):
final_cause[sid] = 17
client.on_call_event = on_event
async with client.connect_async():
await client.originate_bulk(
csv_url=csv_url,
trunk_id="default",
calls_per_second=5,
max_concurrent=50,
campaign_id="campaign-2026-04",
)
await asyncio.sleep(600) # let it run for 10 minutes
asyncio.run(run_campaign("https://example.com/numbers.csv"))