Skip to content

Fraud detection

Checks: sender ID, genuine format, spelling, scam phrases, disguised (accented) letters, transaction ID length, balance consistency, and an optional ML model. Signals combine with a noisy-OR: score = 1 - (1 - s1)(1 - s2).... LOW < 0.35 <= MEDIUM <= 0.70 < HIGH.

Warning

Results are risk indicators, not guarantees. Always confirm payments in the official app.

cedikit.fraud

Detect likely fake Mobile Money payment alerts and explain why.

Results are risk indicators, not guarantees. Always confirm a payment in the official Mobile Money app before releasing goods.

Example

from cedikit import fraud report = fraud.check(message_text, sender="0551234567") # doctest: +SKIP print(report) # doctest: +SKIP Risk: HIGH (score 0.97) Reasons: - Sent from a personal phone number ...

FraudReport dataclass

The result of :func:check.

Attributes:

Name Type Description
risk Risk

"LOW", "MEDIUM" or "HIGH". A risk indicator, not a guarantee.

score float

Combined score from 0 to 1.

reasons list[str]

Human-readable explanations, strongest first.

checks dict[str, bool]

Each check that could run, mapped to True if it passed.

signals list[Signal]

The raw evidence behind reasons.

parsed ParseResult | None

The SMS parser's reading of the message.

advice str

What the user should do before trusting any alert.

Signal dataclass

One piece of evidence from one check.

check(message, sender=None, history=(), *, parser=None, classifier=None)

Assess how likely a payment SMS is to be fake.

Parameters:

Name Type Description Default
message str

The SMS text.

required
sender str | None

Who sent it (sender ID or phone number). Strongly recommended: fake alerts almost always come from personal numbers.

None
history Iterable[Transaction | ParseResult]

Earlier genuine transactions from the same wallet, oldest first, used to check that the claimed balance adds up.

()
parser Parser | None

A custom SMS parser, if you use extra templates.

None
classifier ScamClassifier | None

An optional trained :class:~cedikit.fraud.classifier.ScamClassifier, added as one more signal.

None

Returns:

Name Type Description
A FraudReport

class:FraudReport. It is a risk indicator, not a guarantee:

FraudReport

always confirm payments in the official app before releasing goods.

Example

report = check( ... "SORRY YOU HAVE BEING BLOCKED BY TOO MANY AGENT REPORT, DO NOT TRY YOUR PIN", ... sender="0241234567", ... ) report.risk 'HIGH'

risk_level(score)

Map a 0-1 score to a risk level.

cedikit.fraud.classifier

Optional machine-learning scam classifier (needs pip install 'cedikit[ml]').

The model is an extra signal for :func:cedikit.fraud.check, never the only one. cedikit does not ship a trained model: train one on your own labelled, anonymised messages (hundreds of each class, ideally) and keep a held-out set for evaluation.

Example::

from cedikit.fraud.classifier import ScamClassifier
model = ScamClassifier.train(genuine_texts, scam_texts)
model.save("scam_model.joblib")
report = fraud.check(text, sender=sender, classifier=model)

Security: :meth:ScamClassifier.load uses joblib (pickle), which can run code. Only load model files you created yourself.

ScamClassifier

Character n-gram TF-IDF + logistic regression.

Character n-grams cope with typos and odd spacing ("Avaliable", "balan"), which word-based models would treat as unknown words.

train(genuine, scam) classmethod

Fit a new model. Needs at least two examples of each class.

probability(text)

Estimated probability (0-1) that text is a scam.

load(path) classmethod

Load a model saved with :meth:save. Only load files you trust.

prepare(text)

Normalise text so the model learns wording, not specific amounts or IDs.