Use cases

Deep dive: fraud alert verification (voice)

Full end-to-end walkthrough — build the outbound fraud verification agent via the SDK, configure the voice channel and escalation path in the Console dashboard, and trace a complete verification call including the human-escalation branch.

DifficultyAdvanced
TrackDeveloper Track
ChannelsVoice (Outbound)
IntegrationsTransaction monitoring systemCustomer contact databaseEscalation email

This page is a deep dive into the PrimoAI banking fraud verification pattern. It is longer than the recipe and covers the verification flow logic in detail, the voice and escalation configuration in the Console dashboard, and the full conversation walkthrough — including the path where the customer denies the transaction and human escalation is triggered.

Read Anatomy of a workflow agent before going further.

What you are building

An outbound voice agent that handles the end-to-end fraud alert workflow automatically:

  1. Transaction monitoring system flags a suspicious transaction.
  2. Agent places an outbound call to the cardholder.
  3. Agent introduces itself, states the flagged transaction, and runs through structured verification questions.
  4. If the customer confirms the transaction: call ends, transaction marked verified, no further action.
  5. If the customer denies the transaction: agent instructs card block, triggers human escalation (fraud analyst email), and informs the customer a human will follow up within 60 minutes.
  6. If the customer cannot be reached: agent leaves a voicemail and schedules a retry, fraud analyst notified.

This pattern is in production at PrimoAI's banking demo, where it handles hundreds of outbound fraud calls per day with no human in the loop for verified transactions. Human analysts only receive escalations on denied or unverified calls.

Prerequisites

  • BimpeAI account with an active API key (sk_…)
  • A transaction monitoring system with webhook or API integration capabilities
  • A customer contact database that maps transaction IDs to phone numbers
  • An outbound voice phone number provisioned in the Console dashboard
  • An escalation email address for the fraud analyst team

Step 1: Find the fraud verification workflow

import { BimpeAI } from "@bimpeai/sdk";

const bimpe = new BimpeAI({ apiKey: process.env.BIMPEAI_API_KEY! });

const page = await bimpe.workflows.list({ scope: "public", search: "fraud verification" });
const workflow = page.data[0];
console.log(workflow.id, workflow.name);

// Inspect the full workflow to understand its conversation branches
const full = await bimpe.workflows.retrieve(workflow.id);
console.log("Branches:", full.flows?.map((f) => f.name));
import os
from bimpeai import BimpeAI

client = BimpeAI(api_key=os.environ["BIMPEAI_API_KEY"])

page = client.workflows.list(scope="public", search="fraud verification")
workflow = page.data[0]
print(workflow.id, workflow.name)

# Inspect the full workflow to understand its conversation branches
full = client.workflows.retrieve(workflow.id)
if full.flows:
    print("Branches:", [f.name for f in full.flows])

The fraud verification workflow's branches should include: introduction and identity verification, transaction confirmation, denial path (escalation), unreachable path (voicemail + retry), and call summary. Confirm those branches are present before building on this workflow.

Step 2: Create the agent

The system prompt encodes the verification logic, the tone (authoritative but not alarming), and the escalation instructions. Every bank has different verification questions — this prompt is a starting point.

const agent = await bimpe.agents.create(
  {
    name: "PrimoAI Bank — fraud alert agent",
    description: "Outbound fraud verification agent for PrimoAI Bank.",
    system_prompt:
      "You are the automated fraud alert agent for PrimoAI Bank. " +
      "You have been given a flagged transaction and a customer's phone number. Your job is to call the customer, verify their identity, and determine whether the transaction is authorised. " +
      "Introduction: Greet the customer, state that you are calling from PrimoAI Bank's fraud team, and confirm you are speaking to the account holder by asking them to confirm their name and the last four digits of their card. " +
      "If they cannot confirm identity: do not proceed. Tell them to call the number on the back of their card and end the call. " +
      "Transaction verification: State the transaction amount, merchant, and date. Ask: 'Did you make this transaction?' " +
      "If yes: thank them, confirm the transaction will be marked as verified, and end the call politely. " +
      "If no or unsure: tell them to freeze their card immediately in their banking app (Settings → Cards → Freeze). " +
      "Tell them a fraud analyst will call them back within 60 minutes on this number. " +
      "Do not attempt to block the card yourself — that is handled by the card management team. " +
      "If no answer: leave a voicemail stating there is an urgent security matter and they should call the number on the back of their card. " +
      "Never read out the full card number. Never transfer to an external number. Never state the call is unrecorded — all calls are recorded.",
    agent_workflow_id: workflow.id,
    language: "en",
    timezone: "Europe/London",
  },
  { idempotencyKey: "create-primoai-fraud-agent-v1" },
);

console.log("Agent ID:", agent.id);
agent = client.agents.create(
    name="PrimoAI Bank — fraud alert agent",
    description="Outbound fraud verification agent for PrimoAI Bank.",
    system_prompt=(
        "You are the automated fraud alert agent for PrimoAI Bank. "
        "You have been given a flagged transaction and a customer's phone number. Your job is to call the customer, verify their identity, and determine whether the transaction is authorised. "
        "Introduction: Greet the customer, state that you are calling from PrimoAI Bank's fraud team, and confirm you are speaking to the account holder by asking them to confirm their name and the last four digits of their card. "
        "If they cannot confirm identity: do not proceed. Tell them to call the number on the back of their card and end the call. "
        "Transaction verification: State the transaction amount, merchant, and date. Ask: 'Did you make this transaction?' "
        "If yes: thank them, confirm the transaction will be marked as verified, and end the call politely. "
        "If no or unsure: tell them to freeze their card immediately in their banking app (Settings → Cards → Freeze). "
        "Tell them a fraud analyst will call them back within 60 minutes on this number. "
        "Do not attempt to block the card yourself — that is handled by the card management team. "
        "If no answer: leave a voicemail stating there is an urgent security matter and they should call the number on the back of their card. "
        "Never read out the full card number. Never transfer to an external number. Never state the call is unrecorded — all calls are recorded."
    ),
    agent_workflow_id=workflow.id,
    language="en",
    timezone="Europe/London",
    idempotency_key="create-primoai-fraud-agent-v1",
)

print("Agent ID:", agent.id)

The explicit prohibition on reading full card numbers and the recording disclosure are included in the system prompt because they are regulatory requirements for financial services in many jurisdictions. Adjust to match your own compliance obligations.

Step 3: Add knowledge bases

Two knowledge bases give the agent consistent, policy-compliant answers without the model improvising under pressure.

// Fraud response policy and verification question sequence
await bimpe.agents.knowledgeBases.create(agent.id, {
  type: "text",
  name: "Fraud response policy",
  content:
    "A transaction is flagged when it meets one or more of these criteria:\n" +
    "- Amount exceeds 3× the customer's 30-day average spend\n" +
    "- Transaction originates from a country the customer has not previously transacted in\n" +
    "- Merchant matches a known fraud pattern in our monitoring system\n" +
    "- Transaction occurs between 02:00–05:00 local time with no prior activity in that window\n" +
    "\n" +
    "Identity verification (ask in order, stop if identity is not confirmed):\n" +
    "1. 'Can you confirm the name on the account?'\n" +
    "2. 'Can you confirm the last four digits of the card used?'\n" +
    "\n" +
    "Transaction verification question:\n" +
    "'On [date] a transaction of [amount] was made at [merchant]. Did you authorise this?'\n" +
    "\n" +
    "If transaction is denied:\n" +
    "1. Ask the customer to freeze their card immediately via the banking app.\n" +
    "2. Confirm a fraud analyst will call back within 60 minutes.\n" +
    "3. Do not attempt to block the card during the call — the card management team handles this after the call.\n" +
    "\n" +
    "Regulatory note: all calls are recorded for quality and compliance purposes. State this if asked.",
});

// Card freeze and block instructions
await bimpe.agents.knowledgeBases.create(agent.id, {
  type: "text",
  name: "Card freeze instructions",
  content:
    "Freeze via banking app (immediate effect):\n" +
    "  Open PrimoAI Bank app → tap Cards → select the card → tap Freeze card.\n" +
    "  A freeze stops new contactless and online transactions but allows ATM withdrawals with the PIN.\n" +
    "\n" +
    "Freeze via telephone banking:\n" +
    "  Call the number on the back of the card. Automated freeze takes under 2 minutes.\n" +
    "\n" +
    "Freeze vs. cancel:\n" +
    "  A freeze is temporary and reversible — useful while the investigation is active.\n" +
    "  A permanent cancel requires a replacement card (5–7 business days standard, 1–2 days express).\n" +
    "  The fraud analyst will recommend cancel vs. keep frozen during the follow-up call.\n" +
    "\n" +
    "Pending transactions at the time of freeze: these may still settle. The fraud team reviews and refunds disputed settled transactions within 5 business days.",
});
# Fraud response policy and verification question sequence
client.agents.knowledge_bases.create(agent.id, {
    "type": "text",
    "name": "Fraud response policy",
    "content": (
        "A transaction is flagged when it meets one or more of these criteria:\n"
        "- Amount exceeds 3× the customer's 30-day average spend\n"
        "- Transaction originates from a country the customer has not previously transacted in\n"
        "- Merchant matches a known fraud pattern in our monitoring system\n"
        "- Transaction occurs between 02:00–05:00 local time with no prior activity in that window\n"
        "\n"
        "Identity verification (ask in order, stop if identity is not confirmed):\n"
        "1. 'Can you confirm the name on the account?'\n"
        "2. 'Can you confirm the last four digits of the card used?'\n"
        "\n"
        "Transaction verification question:\n"
        "'On [date] a transaction of [amount] was made at [merchant]. Did you authorise this?'\n"
        "\n"
        "If transaction is denied:\n"
        "1. Ask the customer to freeze their card immediately via the banking app.\n"
        "2. Confirm a fraud analyst will call back within 60 minutes.\n"
        "3. Do not attempt to block the card during the call — the card management team handles this after the call.\n"
        "\n"
        "Regulatory note: all calls are recorded for quality and compliance purposes. State this if asked."
    ),
})

# Card freeze and block instructions
client.agents.knowledge_bases.create(agent.id, {
    "type": "text",
    "name": "Card freeze instructions",
    "content": (
        "Freeze via banking app (immediate effect):\n"
        "  Open PrimoAI Bank app → tap Cards → select the card → tap Freeze card.\n"
        "  A freeze stops new contactless and online transactions but allows ATM withdrawals with the PIN.\n"
        "\n"
        "Freeze via telephone banking:\n"
        "  Call the number on the back of the card. Automated freeze takes under 2 minutes.\n"
        "\n"
        "Freeze vs. cancel:\n"
        "  A freeze is temporary and reversible — useful while the investigation is active.\n"
        "  A permanent cancel requires a replacement card (5–7 business days standard, 1–2 days express).\n"
        "  The fraud analyst will recommend cancel vs. keep frozen during the follow-up call.\n"
        "\n"
        "Pending transactions at the time of freeze: these may still settle. The fraud team reviews and refunds disputed settled transactions within 5 business days."
    ),
})

Step 4: Configure voice, escalation, and integrations (Console dashboard)

Voice channel and outbound calling are dashboard-only — there is no API surface for voice

The BimpeAI API has no voice value in the channel filter enum. Outbound voice calls cannot be initiated from the SDK — there is no calls.create or equivalent method. The voice channel, outbound phone number, telephony carrier connection, and escalation email are all configured in the Console dashboard. The SDK cannot start calls, and voice conversations are not surfaced through the conversations.list channel filter. Read voice call outcomes from the dashboard or use the transaction monitoring system's own audit trail.

Configure the outbound voice channel

  1. Open Console dashboardAgents → select "PrimoAI Bank — fraud alert agent".
  2. Under Channels, click Add channelVoice.
  3. Purchase or port an outbound phone number. Numbers are provisioned from the carrier pool available in your region. The number appears on customers' caller ID when the agent calls — use a number that matches your bank's published contact number wherever possible.
  4. Configure voice settings: speaking rate, voice model, and language. For a fraud alert call, a measured speaking rate reduces customer anxiety — avoid the fastest available setting.
  5. Status should show Active.

Configure the escalation email

  1. Under Settings → Escalation, enter the fraud analyst team's email address.
  2. When the agent reaches the denial branch of the conversation flow, the workflow triggers an escalation event. The Console sends an email to this address with the call summary, flagged transaction details, and customer contact information.
  3. The fraud analyst uses this email as the handoff brief for the follow-up call they place within 60 minutes.

Connect the transaction monitoring system

  1. Under Integrations, click Add integration and choose your transaction monitoring provider.
  2. Configure the webhook from your transaction monitoring system to notify the BimpeAI Console when a transaction is flagged. The Console then triggers the outbound call.
  3. The agent receives the transaction amount, merchant name, date, and customer phone number as context at call initiation.

Connect the customer contact database

  1. Under Integrations, click Add integration and connect your customer contact database.
  2. The agent uses this to resolve a transaction ID to a customer name, card last-four, and phone number during the call.

Verify programmatically

// Verify integrations are connected (dashboard must connect these first)
const integrations = await bimpe.agents.integrations.list(agent.id);
console.log("Integrations:", integrations.map((i) => i.name));
// Expected: ["Transaction monitoring", "Customer contact DB"]

// Channels list reflects what was configured in the dashboard
const channels = await bimpe.agents.channels.list(agent.id);
console.log("Channels:", channels.map((c) => c.type));
// Note: voice channel type appears here but there is no "voice" filter in conversations.list
# Verify integrations are connected (dashboard must connect these first)
integrations = client.agents.integrations.list(agent.id)
print("Integrations:", [i.name for i in integrations])
# Expected: ['Transaction monitoring', 'Customer contact DB']

# Channels list reflects what was configured in the dashboard
channels = client.agents.channels.list(agent.id)
print("Channels:", [c.type for c in channels])
# Note: voice channel type appears here but there is no "voice" filter in conversations.list

Both integrations must be present before the agent can handle a real fraud alert. A missing transaction monitoring connection means the agent has no transaction context when a call connects. A missing contact database connection means the agent cannot look up the customer's phone number from a transaction ID.

Conversation walkthrough

The verified transaction path

This is the happy path: the customer picks up, recognises the transaction, and confirms it.

Agent: Hello, this is PrimoAI Bank's automated security line calling for James Mitchell. This call may be recorded for compliance purposes. Can I confirm I'm speaking with James Mitchell?

Customer: Yes, that's me.

Agent: Thank you, James. To confirm your identity, could you give me the last four digits of the card ending in your most recent transaction?

Customer: 7823.

Agent: Thank you. I'm calling because we have flagged a transaction on your account for review. On Tuesday 17 June, a transaction of £349.00 was made at Currys PC World, Manchester. Did you authorise this transaction?

Customer: Yes, that was me — I bought a laptop.

Agent: Perfect. That transaction has been marked as verified. No further action is needed on your end. Thank you for your time, James, and apologies for interrupting your day. Goodbye.

Call duration: approximately 90 seconds. No human involved.

The denied transaction path (escalation)

The customer does not recognise the transaction. This triggers card freeze instructions and human escalation.

Agent: Hello, this is PrimoAI Bank's automated security line calling for Priya Sharma. This call may be recorded for compliance purposes. Can I confirm I'm speaking with Priya Sharma?

Customer: Yes.

Agent: Thank you, Priya. To confirm your identity, could you give me the last four digits of your card?

Customer: 4412.

Agent: Thank you. On Wednesday 18 June, a transaction of £1,200.00 was made at Lux Electronics, Online. Did you authorise this transaction?

Customer: No — I have no idea what that is.

Agent: I understand, Priya. Please take these steps right away.

First: open your PrimoAI Bank app, go to Cards, select the card ending in 4412, and tap Freeze card. This stops any new transactions immediately. If you cannot access the app, call the number on the back of your card and our automated system will freeze it in under two minutes.

Second: a fraud analyst from our team will call you back on this number within 60 minutes with next steps, including a replacement card if needed.

Do not share your PIN or full card number with anyone who contacts you — PrimoAI Bank will never ask for those.

Is there anything else I can clarify before I let you go?

Customer: No, I'll freeze it now. Thank you.

Agent: Thank you, Priya. Stay safe, and expect a call from our fraud team within the hour. Goodbye.

What happens after the call ends: the workflow triggers the escalation event, the Console sends an email to the fraud analyst team containing the call summary (transaction details, customer confirmation of denial, call timestamp), and the analyst team uses that as their brief for the follow-up call.

The unreachable path

If no one picks up after the configured number of rings:

Agent (voicemail): Hello, this is an automated message from PrimoAI Bank's security team. We need to speak with you urgently regarding your account. Please call the number on the back of your card as soon as possible — do not reply to this message. Thank you.

The workflow logs the unreachable outcome and the analyst team is notified via the same escalation email path.

Reading completed call outcomes

After a call completes, you can read the conversation log from the API. Voice conversations appear in conversations.list but are not filterable by a voice channel parameter — use the list without a channel filter and identify voice calls by their duration or metadata.

// List all recent conversations (voice calls will appear here after they complete)
const conversations = await bimpe.conversations.list(agent.id);

for (const conv of conversations.data) {
  console.log(conv.id, conv.created_at);

  // Retrieve the full message history of a completed call
  const messages = await bimpe.conversations.messages.list(agent.id, conv.id);
  for (const msg of messages.data) {
    console.log(`[${msg.role}] ${msg.message}`);
  }
}
# List all recent conversations (voice calls will appear here after they complete)
conversations = client.conversations.list(agent.id)

for conv in conversations.data:
    print(conv.id, conv.created_at)

    # Retrieve the full message history of a completed call
    messages = client.conversations.messages.list(agent.id, conv.id)
    for msg in messages.data:
        print(f"[{msg.role}] {msg.message}")

Full runnable example

import { BimpeAI } from "@bimpeai/sdk";

const bimpe = new BimpeAI({ apiKey: process.env.BIMPEAI_API_KEY! });

// 1. Find workflow
const page = await bimpe.workflows.list({ scope: "public", search: "fraud verification" });
const workflow = page.data[0];

// 2. Create agent
const agent = await bimpe.agents.create(
  {
    name: "PrimoAI Bank — fraud alert agent",
    system_prompt:
      "You are the automated fraud alert agent for PrimoAI Bank. " +
      "Call the cardholder, verify identity (name + last 4 digits), then ask about the flagged transaction. " +
      "If confirmed: end the call. " +
      "If denied: instruct card freeze and tell them a fraud analyst calls back within 60 minutes. " +
      "Never read the full card number. All calls are recorded.",
    agent_workflow_id: workflow.id,
    language: "en",
    timezone: "Europe/London",
  },
  { idempotencyKey: "create-primoai-fraud-agent-v1" },
);

// 3. Add knowledge bases
await bimpe.agents.knowledgeBases.create(agent.id, {
  type: "text",
  name: "Fraud response policy",
  content:
    "Identity verification: confirm name + last 4 card digits before proceeding.\n" +
    "Transaction verification question: 'On [date] a transaction of [amount] at [merchant]. Did you authorise this?'\n" +
    "If denied: instruct card freeze via app (Cards → Freeze), confirm analyst callback within 60 minutes.\n" +
    "Do not block the card during the call — card management team handles this after the call.",
});

await bimpe.agents.knowledgeBases.create(agent.id, {
  type: "text",
  name: "Card freeze instructions",
  content:
    "Freeze via app: PrimoAI Bank app → Cards → select card → Freeze card.\n" +
    "Freeze via phone: call number on back of card, automated system freezes in 2 minutes.\n" +
    "Freeze is temporary and reversible. Analyst will advise cancel vs. keep frozen.",
});

// 4. Verify integrations (all connected in the dashboard — voice channel is also dashboard-only)
const integrations = await bimpe.agents.integrations.list(agent.id);
const channels = await bimpe.agents.channels.list(agent.id);

console.log("Agent ID:", agent.id);
console.log("Integrations:", integrations.map((i) => i.name));
console.log("Channels:", channels.map((c) => c.type));

// 5. Read completed call outcomes
// Outbound calls are initiated from the dashboard or the transaction monitoring webhook.
// The SDK cannot initiate calls. After a call completes it appears in conversations.list.
const conversations = await bimpe.conversations.list(agent.id);
console.log("Completed conversations:", conversations.data.length);
import os
from bimpeai import BimpeAI

client = BimpeAI(api_key=os.environ["BIMPEAI_API_KEY"])

# 1. Find workflow
page = client.workflows.list(scope="public", search="fraud verification")
workflow = page.data[0]

# 2. Create agent
agent = client.agents.create(
    name="PrimoAI Bank — fraud alert agent",
    system_prompt=(
        "You are the automated fraud alert agent for PrimoAI Bank. "
        "Call the cardholder, verify identity (name + last 4 digits), then ask about the flagged transaction. "
        "If confirmed: end the call. "
        "If denied: instruct card freeze and tell them a fraud analyst calls back within 60 minutes. "
        "Never read the full card number. All calls are recorded."
    ),
    agent_workflow_id=workflow.id,
    language="en",
    timezone="Europe/London",
    idempotency_key="create-primoai-fraud-agent-v1",
)

# 3. Add knowledge bases
client.agents.knowledge_bases.create(agent.id, {
    "type": "text",
    "name": "Fraud response policy",
    "content": (
        "Identity verification: confirm name + last 4 card digits before proceeding.\n"
        "Transaction verification question: 'On [date] a transaction of [amount] at [merchant]. Did you authorise this?'\n"
        "If denied: instruct card freeze via app (Cards → Freeze), confirm analyst callback within 60 minutes.\n"
        "Do not block the card during the call — card management team handles this after the call."
    ),
})

client.agents.knowledge_bases.create(agent.id, {
    "type": "text",
    "name": "Card freeze instructions",
    "content": (
        "Freeze via app: PrimoAI Bank app → Cards → select card → Freeze card.\n"
        "Freeze via phone: call number on back of card, automated system freezes in 2 minutes.\n"
        "Freeze is temporary and reversible. Analyst will advise cancel vs. keep frozen."
    ),
})

# 4. Verify integrations (all connected in the dashboard — voice channel is also dashboard-only)
integrations = client.agents.integrations.list(agent.id)
channels = client.agents.channels.list(agent.id)

print("Agent ID:", agent.id)
print("Integrations:", [i.name for i in integrations])
print("Channels:", [c.type for c in channels])

# 5. Read completed call outcomes
# Outbound calls are initiated from the dashboard or the transaction monitoring webhook.
# The SDK cannot initiate calls. After a call completes it appears in conversations.list.
conversations = client.conversations.list(agent.id)
print("Completed conversations:", len(conversations.data))

Demo tips

What judges and visitors should see when you demonstrate this agent:

Start by explaining the trigger: a transaction monitoring alert fires (show a sample JSON payload from your monitoring system or the dashboard) and the Console initiates an outbound call automatically. This sets the context that the agent is reactive to a real event, not being called manually.

Play or simulate the verified transaction call first (approximately 90 seconds). The call should sound calm, structured, and fast. Point out that the agent confirmed identity before discussing the transaction — that is a compliance requirement, not just politeness, and it is encoded in the knowledge base.

Then play the denial call. The most important moment is the handoff: the agent gives card freeze instructions and a 60-minute callback commitment before ending the call. Immediately after, show the escalation email arriving in the analyst team's inbox — the timing between call end and email arrival should be under 30 seconds. That instant handoff is the value proposition for banks: no analyst has to monitor a queue or listen to call recordings to know an escalation happened.

If doing a live demo rather than a recorded one, use a test phone number and walk through the verified transaction path live. The audience hears a real phone ring, a natural-sounding AI voice, and a structured verification flow. End by showing the conversation log in the BimpeAI Console — the full transcript of the call, timestamped, searchable, and audit-ready.

The PrimoAI production deployment handles over 300 outbound calls per day. For a demo audience, the key number to quote is not volume — it is the false positive rate: 94% of flagged transactions are confirmed by the customer in the first call, meaning analysts only receive 6% as escalations. That is the cost reduction story.

On this page