Skip to main content
Call center fraud follows predictable playbooks: callers impersonate account holders, feign ignorance to extract information, and apply social pressure when agents push back. At the same time, agents under pressure make mistakes — skipping verification steps, disclosing information they shouldn’t, or leaving issues unresolved. The insight this playbook builds on is that your SOPs are already written. Velma lets you operationalize them as behaviors and monitor both sides of every call simultaneously — adversarial caller signals on one side, agent compliance on the other.

What this configuration detects

Caller-side signals (fraud and social engineering)
BehaviorWhat it catches
Account ImpersonationIdentity inconsistencies, partial knowledge of account details, rehearsed verification responses
VishingPhishing-style social engineering over voice — false urgency, impersonation of institutions
Feigned IgnoranceCaller claims not to know information they demonstrably do know, used to extract agent guidance
Bargaining ManipulationCajoling, conditional framing, sympathy plays used to pressure policy exceptions
Coercion ManipulationDirect threats or implied consequences tied to compliance demands
Agent-side signals (SOP compliance and CSAT)
BehaviorWhat it catches
Unaddressed QuestionCustomer’s stated concern is never acknowledged or resolved by the agent
Issue Not ResolvedCall ends without the original issue being addressed
Issue ResolvedPositive closure confirmed by either party
Agent Credential Disclosure (custom)Agent verbalizes a credential, PIN, or security code during the call
Verification Step Skipped (custom)Agent proceeds past an authentication checkpoint without completing it

Configuration

This playbook uses preset references for the caller-side behaviors and direct BehaviorDef objects for the agent-side SOP behaviors — both pre-built and custom. All entries go in the same behaviors array.
{
  "conversation_types": [
    {
      "conversation_type_uuid": "11111111-1111-4111-8111-111111111008",
      "name": "Customer Support Call",
      "short_description": "A customer contacting a business for help with a product or service.",
      "detailed_description": "A professional support interaction. The agent is expected to follow verification and disclosure procedures before accessing or modifying account information. The customer may or may not be the legitimate account holder."
    }
  ],
  "participant_roles": [
    {
      "participant_role_uuid": "22222222-2222-4222-8222-222222222017",
      "name": "Customer",
      "short_description": "The person calling in, claiming to be the account holder.",
      "detailed_description": "The inbound caller. May be a legitimate account holder or a fraudulent actor attempting to access an account that does not belong to them."
    },
    {
      "participant_role_uuid": "22222222-2222-4222-8222-222222222012",
      "name": "Agent",
      "short_description": "The company representative handling the call.",
      "detailed_description": "A trained support agent responsible for verifying caller identity before accessing account information and following escalation and disclosure procedures at all times."
    }
  ],
  "behaviors": [
    "preset:account-impersonation",
    "preset:vishing",
    "preset:feigned-ignorance",
    "preset:bargaining-manipulation",
    "preset:coercion-manipulation",
    {
      "behavior_uuid": "33333333-3333-4333-8333-033333333033",
      "name": "Unaddressed Question",
      "short_description": "Customer's question or stated concern goes unacknowledged.",
      "detailed_description": "This behavior is present if the customer clearly states a question or issue and the agent responds without acknowledging or attempting to address it. A direct subject change, scripted response unrelated to the stated issue, or call end without acknowledgment all qualify. Do not flag if the agent explicitly defers the question and explains why.",
      "applies_to_participant_role_uuids": ["22222222-2222-4222-8222-222222222012"]
    },
    {
      "behavior_uuid": "33333333-3333-4333-8333-033333333035",
      "name": "Issue Not Resolved",
      "short_description": "Call ends without the customer's original issue being addressed.",
      "detailed_description": "This behavior is present if the speech near the end of the call features an affirmation from either party that the reason for the call was not or could not be resolved, or a sudden call end before any such affirmation. Consider only the final 20% of the transcript. Do not flag if any participant confirms the issue was resolved.",
      "applies_to_participant_role_uuids": ["22222222-2222-4222-8222-222222222012"]
    },
    {
      "behavior_uuid": "<generate-a-uuid>",
      "name": "Agent Credential Disclosure",
      "short_description": "Agent verbalizes a credential or security code during the call.",
      "detailed_description": "This behavior is present if all of the following criteria are met: the speech is attributed to the agent role; the speech contains a direct verbalization of an account password, PIN, one-time passcode, or security question answer in full; the verbalization is not a masked or partial value such as 'ending in 4521'. Do not flag if the agent is instructing the customer on how to reset credentials through a self-service flow. Do not flag if the agent reads back the last four digits of an account number for verification.",
      "applies_to_participant_role_uuids": ["22222222-2222-4222-8222-222222222012"]
    },
    {
      "behavior_uuid": "<generate-a-uuid>",
      "name": "Verification Step Skipped",
      "short_description": "Agent proceeds past an authentication checkpoint without completing it.",
      "detailed_description": "This behavior is present if the agent moves to account access or modification actions — such as providing account details, processing a change, or issuing a credit — without having first received at least two distinct forms of identity confirmation from the caller. Identity confirmation includes: correct statement of date of birth, last four of SSN, account PIN, or security question answer. Statements from the caller that they do not know this information do not qualify as confirmation.",
      "applies_to_participant_role_uuids": ["22222222-2222-4222-8222-222222222012"]
    }
  ],
  "stt": {
    "speaker_diarization": true
  },
  "produce_topics": false,
  "produce_topic_sentiments": false,
  "produce_summary": true
}
Replace <generate-a-uuid> with a UUID v4 you generate (python3 -c "import uuid; print(uuid.uuid4())") before sending the config. Each custom behavior needs a unique UUID that stays consistent across sessions so you can track detections over time.

Code example

Python
import os, json, asyncio, websockets

BEHAVIORS_TO_ALERT = {
    "Account Impersonation",
    "Vishing",
    "Agent Credential Disclosure",
    "Verification Step Skipped",
}

config = { ... }  # paste your BatchConfig here

async def monitor_call(audio_path: str, call_id: str):
    url = f"wss://modulate-developer-apis.com/api/velma-2-streaming?api_key={os.environ['MODULATE_API_KEY']}"

    async with websockets.connect(url) as ws:
        await ws.send(json.dumps(config))

        async def send_audio():
            with open(audio_path, "rb") as f:
                while chunk := f.read(4096):
                    await ws.send(chunk)
            await ws.send("")

        send_task = asyncio.create_task(send_audio())

        try:
            async for message in ws:
                event = json.loads(message)

                if event["type"] == "behavior_detection":
                    d = event["detection"]
                    if d["detected"]:
                        severity = "HIGH" if d["behavior_name"] in BEHAVIORS_TO_ALERT else "INFO"
                        print(
                            f"[{severity}] {d['behavior_name']} | "
                            f"speaker={d['speaker_label']} | "
                            f"confidence={d['confidence']:.2f} | "
                            f"call={call_id}"
                        )
                        # send to your alerting system here

                elif event["type"] == "summary":
                    print(f"[SUMMARY] {call_id}: {event['text']}")
                    # write to your QA database here

                elif event["type"] == "done":
                    print(f"[DONE] {call_id} processed — {event['duration_ms']}ms")
                    break

        finally:
            if not send_task.done():
                send_task.cancel()

asyncio.run(monitor_call("call_recording.mp3", "call-20260602-00142"))

Reading the output

Behavior detections arrive per-behavior per-speaker throughout the session. The speaker_label field tells you which side of the call triggered the detection. Use evidence_clip_uuids to look up the specific transcript clips that drove the verdict — these are the quotes you surface in a QA review or compliance report. Confidence scores are on a 0–1 scale. For high-stakes behaviors like Account Impersonation and Verification Step Skipped, consider alerting at any detected: true result regardless of score. For softer signals like Bargaining Manipulation, a confidence threshold (e.g. >= 0.75) reduces noise. The summary gives you a call narrative suitable for a QA system or CRM note without any additional processing.

Turning your SOP into behaviors

The two custom behaviors above are starting points — the real value comes from encoding your specific verification procedures. A few principles that apply directly to this use case: Scope every agent behavior to the agent role. Use applies_to_participant_role_uuids with the agent’s UUID. A customer asking “can you confirm my account number?” is routine — the same question from an agent may not be. Define your verification steps concretely. If your SOP requires two of five specific identity factors before account access, list those five factors explicitly in the detailed_description. Don’t write “proper verification” — write the actual steps. Write negation criteria for scripted disclosures. Agents read disclosures at the start of calls that might superficially trigger some behaviors. Add explicit exclusions for known scripted content.