API reference

POST /v1/fraud · Score a conversation

Scores a phone call for scams while it's happening. Start a conversation when the call starts, send what each side says as it's said, and every response carries a live score from 0 to 100 for how likely it is that the other party is running a scam.

It's one endpoint for the whole call: what you put in the body decides what happens.

Note

New to this? The setup guide walks through a whole call, start to end, with the requests in order. It also explains every field of the score.

text
POST https://api.spoofey.com/v1/fraud

What to send

You want to Send You get back
Start a conversation with what was just said number and text (or utterances) 201 and the conversation, already scored
Start one before anyone has spoken, to stream its audio start: true and number 201 and the conversation
Add what was said id and text (or utterances) 200 and the updated score
Read the score id 200 and the conversation, as it stands
Attach what you know about the number id and classification, or id and classify: true 200 and the updated score
End it id and end: true, with any last lines 200 and the final score with its history
Warning

A body with only a number (no text, utterances, start or id) isn't a conversation: it's a number check, billed per check.

Body

Field Required Type Notes
id To work on a conversation string The conversation's id, from the response that started it. conversation_id works too.
text No string One line that was said, up to 2,000 characters. Counts as the remote party unless you set speaker.
speaker No string Who said text: remote (the party being assessed, the default), user (the person you're protecting) or unknown. caller and callee are accepted too.
utterances No array Several lines at once, in the order they were said: up to 50 { "speaker", "text" } objects. Use instead of text. Here speaker defaults to unknown, so set it.
number No string When starting: the number of the party being assessed, with its country code, like +14155550199. remote_number and phone work too. Needed for classify: true.
start No boolean true starts a conversation with nothing said yet.
end No boolean true ends the conversation, after adding any text or utterances sent with it.
classification No string, object or null What's known about the number: the id of one of your number checks, the whole number check response, or one of emergency, financial, carrier, business, ordinary. With id, it replaces the conversation's classification, and null removes it.
classify No boolean true runs a number check on the number now and attaches the result, at the number check's price. The result also comes back as classify.
include No string With id: transcript, history or transcript,history adds every line said and each change of score to the response.
user_number No string When starting: the number of the person you're protecting. For your own records.
language No string When starting: the call's language, for audio. Default en.
metadata No object When starting: anything you want back on the conversation, such as your own call id. Up to 2,000 characters as JSON.

Start a conversation

Start it as soon as you have the first thing the caller said. Keep the id from the response: everything else uses it.

bash
curl https://api.spoofey.com/v1/fraud \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"number": "+14155550199", "text": "Hi, this is the fraud department at Chase. We saw suspicious activity on your account.", "metadata": {"call_id": "abc-123"}}'

201 and the conversation, already scored:

json
{
  "id": "5fa8406c-0601-4eba-aa70-797917434f29",
  "object": "conversation",
  "status": "active",
  "end_reason": null,
  "risk_score": 45,
  "trust_score": 55,
  "peak_score": 45,
  "band": "elevated",
  "recommended_action": "caution",
  "scam_type": null,
  "claimed_identity": null,
  "summary": null,
  "advice": null,
  "cues": [
    { "cue": "authority_impersonation", "severe": false, "count": 1, "speakers": ["remote"], "evidence": "Hi, this is the fraud department at Chase. We saw suspicious activity on your account.", "source": "detector" },
    { "cue": "account_compromise_claim", "severe": false, "count": 1, "speakers": ["remote"], "evidence": "Hi, this is the fraud department at Chase. We saw suspicious activity on your account.", "source": "detector" }
  ],
  "components": { "model_score": null, "cue_score": 45, "classification_adjustment": 0, "adjustments": [] },
  "analysis": "full",
  "remote_number": "+14155550199",
  "user_number": null,
  "classification": null,
  "mode": "text",
  "words": 15,
  "utterances": 1,
  "billed_minutes": 1,
  "credits_charged": 0.06,
  "metadata": { "call_id": "abc-123" },
  "created_at": 1790812800000,
  "updated_at": 1790812800000,
  "ended_at": null
}

model_score is null until our AI has read the call. That read lands a few seconds later: get it from Follow the score live, from the next response, or by reading the score. What each field means is in the guide, under Reading the score.

If you're going to stream the call's audio instead of sending text, start with nothing said:

bash
curl https://api.spoofey.com/v1/fraud \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"start": true, "number": "+14155550199"}'

Add what was said

Send each line as soon as you have it, with the conversation's id. The sooner it arrives, the sooner a scam is caught. Batch lines with utterances if you have several.

bash
curl https://api.spoofey.com/v1/fraud \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"id": "5fa8406c-0601-4eba-aa70-797917434f29", "utterances": [{"speaker": "user", "text": "Oh no, what do I do?"}, {"speaker": "remote", "text": "Read me the verification code we just sent, right now, and do not tell anyone at the branch."}]}'

200 and the updated score, shortened here:

json
{
  "id": "5fa8406c-0601-4eba-aa70-797917434f29",
  "status": "active",
  "risk_score": 91,
  "trust_score": 9,
  "peak_score": 91,
  "band": "critical",
  "recommended_action": "end_call",
  "cues": [
    { "cue": "authority_impersonation", "severe": false, "count": 1, "speakers": ["remote"], "evidence": "Hi, this is the fraud department at Chase…", "source": "detector" },
    { "cue": "account_compromise_claim", "severe": false, "count": 1, "speakers": ["remote"], "evidence": "Hi, this is the fraud department at Chase…", "source": "detector" },
    { "cue": "requests_otp", "severe": true, "count": 1, "speakers": ["remote"], "evidence": "Read me the verification code we just sent…", "source": "detector" },
    { "cue": "urgency_pressure", "severe": false, "count": 1, "speakers": ["remote"], "evidence": "Read me the verification code we just sent…", "source": "detector" },
    { "cue": "secrecy_request", "severe": false, "count": 1, "speakers": ["remote"], "evidence": "Read me the verification code we just sent…", "source": "detector" }
  ],
  "components": { "model_score": null, "cue_score": 91, "classification_adjustment": 0, "adjustments": [] },
  "words": 39,
  "utterances": 3,
  "billed_minutes": 1
}

The score in this response comes from the instant check for clear scam signs. Act on recommended_action: at warn_user or end_call, show the person on the line the advice.

Read the score

Send just the id, or use GET /v1/fraud/:id. Add "include": "history" for each change of score, or "transcript" for everything said.

bash
curl https://api.spoofey.com/v1/fraud \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"id": "5fa8406c-0601-4eba-aa70-797917434f29", "include": "history"}'

Attach what you know about the number

Telling us what the caller's number is makes the score sharper: for example, a caller who claims to be a bank from a number that isn't tied to anyone. Do it when you start, or at any time during the call. The score updates at once.

bash
curl https://api.spoofey.com/v1/fraud \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"id": "5fa8406c-0601-4eba-aa70-797917434f29", "classify": true}'

classify: true checks the conversation's number now, at the number check price. If you already ran a number check, pass its id as classification instead and pay nothing more. How a classification moves the score is in the guide, under Using number classification.

End it

When the call ends, end the conversation. It stops billing, runs one last read of anything not yet assessed, and returns the final score with its score_history. Send the last lines with it if you have them. Ending a conversation that has already ended just returns it.

bash
curl https://api.spoofey.com/v1/fraud \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"id": "5fa8406c-0601-4eba-aa70-797917434f29", "end": true}'

200, shortened here:

json
{
  "id": "5fa8406c-0601-4eba-aa70-797917434f29",
  "status": "ended",
  "end_reason": "ended_by_client",
  "risk_score": 95,
  "peak_score": 100,
  "band": "critical",
  "scam_type": "bank_impersonation",
  "summary": "Caller claiming to be Chase's fraud team asked for the code just texted and said not to tell the branch.",
  "billed_minutes": 3,
  "score_history": [
    { "at": 1790812800000, "score": 45, "ai_score": null, "cue_score": 45, "adjustment": 0, "trigger": "cues" },
    { "at": 1790812805000, "score": 91, "ai_score": null, "cue_score": 91, "adjustment": 0, "trigger": "cues" },
    { "at": 1790812809000, "score": 100, "ai_score": 92, "cue_score": 91, "adjustment": 20, "trigger": "ai" },
    { "at": 1790812950000, "score": 95, "ai_score": 92, "cue_score": 91, "adjustment": 0, "trigger": "final" }
  ],
  "ended_at": 1790812950000
}

A conversation nobody sends anything to for 15 minutes ends on its own (end_reason: "idle"), and so does one that reaches 4 hours (max_duration).

Billing

Conversations are billed per minute from your credit balance, one minute ahead, at the text price shown at the top of this page. Starting one is free; billing starts with the first line. Audio streamed into a conversation is billed at the audio price. classify: true is charged at the number check price. The guide's Billing section explains how a minute is counted.

If your balance runs out mid-call, scoring pauses and requests return 402 insufficient_credits. Top up and send again, and it carries on where it stopped.

Errors

Errors come back as {"error":{"message":"...","code":"..."}}. See API errors and rate limits.

Status Code When
400 missing_input There's nothing to do: no number, text, utterances, start or id.
400 missing_id end: true without the conversation's id.
400 invalid_utterance A line has no text, or utterances isn't a list.
400 missing_utterances utterances is an empty list.
400 too_many_utterances More than 50 lines in one request.
400 invalid_speaker speaker isn't remote, user or unknown.
400 invalid_number A phone number isn't digits with a country code.
400 invalid_classification classification isn't one of the accepted forms, or is an id that isn't yours.
400 missing_remote_number classify: true, and there's no number to check.
400 invalid_metadata metadata isn't an object, or is too long.
402 insufficient_credits Your balance doesn't cover the next minute (or the number check). Scoring pauses; top up and send again.
402 max_duration The conversation reached 4 hours and has ended.
404 not_found No conversation of yours has that id.
409 conversation_ended The conversation has ended. Start a new one.
429 too_many_conversations You already have 50 live conversations. End one first.
429 rate_limited Over 1,200 requests a minute. Batch lines with utterances, or stream the audio.
503 lookup_unavailable classify: true and the number check couldn't run. You're not charged for it.

If the conversation was started but its first lines were refused (for example by 402), the error's message ends with the conversation's id, so you can send them again with that id.

Was this helpful?Your answer helps us improve this page.
Still stuck?Ask Spoofey AI about your exact case, or a person on our team will reply by email.
Last modified on October 23, 2026 · 10 min read
Edit