Telecom-signal fraud intelligence for fintech transaction pipelines.
TrustMesh is an API that sits in front of a payment or remittance authorization step and answers one question: does the telecom network layer say this transaction looks like account takeover? It queries SIM-swap history, phone-number verification, and device-status signals (the GSMA Open Gateway CAMARA APIs), reasons over them with contextual scoring, and returns a 0-100 risk score plus a recommended action — allow, audit, biometric step-up, email OTP step-up, or block — with a plain-language explanation.
The blind spot it closes: application-layer fraud engines (device fingerprinting, behavioral analytics) cannot see that a customer's SIM was swapped two hours before a transfer. By the time behavioral anomalies surface, the money is gone. TrustMesh adds the missing network-layer signal.
This project started as a GSMA MENA Ignite Hackathon 2026 submission. The original pitch deck, architecture doc, and market research are preserved in docs/hackathon-archive/ for reference. It is now being developed as a standalone commercial product.
A working TypeScript/Express API in server/:
POST /v1/risk-check— accepts a transaction + phone number, fetches the three CAMARA signals, scores risk, and returns a decision.- Dual scoring engine — tries an LLM (Groq/Llama by default) for contextual reasoning, and always falls back to a deterministic rule engine (server/src/engine/ruleEngine.ts) if no LLM key is configured or the call fails. The service is fully functional with zero external API keys.
- Mock CAMARA client (server/src/camara/mockClient.ts) with deterministic fixtures covering all five risk tiers below, so you can demo and test without live telecom sandbox credentials. A best-effort real client for actual CAMARA/Nokia NaC endpoints is in server/src/camara/realClient.ts.
- API-key auth + usage metering — every request is tracked per key
against a monthly plan quota, returning
429with an upgrade prompt when exceeded — see server/src/usage/meter.ts. - Test suite covering all five risk tiers and the mock client (
npm testinserver/, 9 passing tests).
cd server
npm install
npm run dev # starts on :8080, CAMARA_MODE=mock by defaultcurl -X POST http://localhost:8080/v1/risk-check \
-H "Content-Type: application/json" \
-H "x-api-key: tm_sandbox_demo" \
-d '{
"phoneNumber": "+971500000005",
"transaction": {"amount": 8000, "currency": "AED", "type": "remittance"},
"deviceFingerprint": "fp1",
"sessionId": "s1",
"timestamp": "2026-09-06T12:00:00.000Z"
}'Demo phone numbers wired to fixed scenarios in the mock client:
| Phone number | Scenario | Expected tier |
|---|---|---|
+971500000001 |
All clear | Silent Allow (0-20) |
+971500000002 |
Old SIM swap (45d), stable device | Allow + Audit (21-40) |
+971500000003 |
Recent device change, number matches | Biometric (41-65) |
+971500000004 |
SIM swap <24h + device change | Email OTP (66-85) |
+971500000005 |
SIM swap + number mismatch + new device | Block (86-100) |
Any other number gets a deterministic pseudo-random "mostly clean" profile.
To enable LLM-based contextual reasoning instead of the rule fallback, copy
server/.env.example to server/.env and set GROQ_API_KEY.
A live console for the API — pick a demo scenario or enter your own, run a risk check, and see the score/action/explanation render in real time, alongside per-key usage against the plan quota:
cd web
npm install
npm run dev # starts on :5173, talks to the API at :8080Enter the API base URL and key in the header (defaults to
http://localhost:8080 / tm_sandbox_demo, matching the server's seeded
sandbox key).
TrustMesh/
├── README.md # this file
├── LICENSE
├── server/ # the API — see server/ for full structure
│ ├── src/
│ │ ├── camara/ # SIM Swap / Number Verification / Device Status clients (mock + real)
│ │ ├── engine/ # LLM reasoning + deterministic rule-based fallback
│ │ ├── middleware/ # API key auth
│ │ ├── usage/ # per-key metering (the monetization hook)
│ │ └── routes/ # POST /v1/risk-check, GET /v1/usage
│ └── test/
├── web/ # live dashboard console (Vite + React)
└── docs/
└── hackathon-archive/ # original Phase 1 hackathon submission materials
| Signal combination | Score | Action |
|---|---|---|
| No recent swap, number match, stable device | 0-20 | Silent Allow |
| Old SIM swap (>30 days), no device change | 21-40 | Allow + Audit |
| Recent device change, number matches | 41-65 | Biometric Re-auth |
| Recent SIM swap (<24h) + device change | 66-85 | Email OTP Step-Up |
| Recent SIM swap + number mismatch + new device | 86-100 | Block + Flag |
This table is what the rule-engine fallback implements exactly (server/src/engine/ruleEngine.ts); the LLM engine uses it as a starting point but reasons over the full context (transaction amount included).
Stripe billing, self-serve API key signup, and validated live CAMARA credentials beyond the best-effort client in server/src/camara/realClient.ts.