POST/v1/validate/enhanced

TrustCheck with full AI analysis

Runs the complete analysis pipeline on top of a standard TrustCheck: the trust narrative and overview from ?ai=true, plus fraud-pattern detection and AI name matching. Same request body as POST /v1/validate, with three optional flags to switch individual analyses off.

What this endpoint adds

  • ai_insights.trust_enhancement and ai_insights.overview: exactly as on /v1/validate?ai=true.
  • ai_insights.fraud_detection: a risk level, confidence, and patterns for this subject, alongside an aggregate view of your own recent request stream used as velocity context.
  • ai_insights.name_matching: how the submitted name compares to the matched record, accounting for nicknames, transliteration, middle names, and typos.

Authentication

Identical to the base endpoint: X-API-Key: tm_... or Authorization: Bearer tm_.... An enhanced call counts as one regular check; there is no AI surcharge on current plans.

Request body

A TrustCheck describes one person. Send their name, then whichever contact points you have as flat arrays. Each array holds up to five values.

Send more than a name. name is the only field the API requires, but a name on its own is a much weaker check than it looks. With one field there is nothing to cross-reference, so the response can only tell you whether that name appears in the identity graph — not whether it belongs to the person your user is dealing with. Send at least one of emails, phones or addresses alongside it and the result becomes a statement about an identity rather than about a string.
Each value is checked on its own. Sending three phones does not mean “this person has three phones”. It asks the identity graph about each number separately, and you get a verdict per number. The same is true of emails and addresses. More contact points means more evidence, not a stricter test.

Request Body

ParamTypeRequiredDescription
namestringYESThe person's full name. One name per request: a TrustCheck scores exactly one identity. Everything else you send is checked against this person.
emailsstring[]OPTUp to 5 email addresses belonging to that person. Lowercased and validated server-side. Each gets its own row in input_validation.email.inputs[].
phonesstring[]OPTUp to 5 phone numbers (10–15 digits). Formatting is stripped before matching, so +1 (661) 555-0101 and 6615550101 are the same input. Each gets its own row in input_validation.phone.inputs[].
addressesAddress[]OPTUp to 5 addresses associated with that person. Each is { street, street2?, city, state, zip, country? }, and every subfield is optional. A street on its own is a valid entry. Each address is checked independently and gets its own row in input_validation.address.inputs[]. Requires name.
intentstring (enum)OPTBiases the AI narrative without changing the numeric score. One of: online-dating, buying-or-selling, sending-money, suspected-scam, reconnecting, general. Unknown values fall back to general. Only affects /v1/validate?ai=true and /v1/validate/enhanced.
operation"validate" | "raw"OPTDefaults to validate (the scored TrustMatch response). Pass raw to also include the upstream identity-graph payload for debugging.
include_trust_enhancementbooleanOPTDefaults to true. Set false to skip the trust narrative; ai_insights.trust_enhancement then reports { ai_enabled: false, reason: "Not requested" }.
include_fraud_detectionbooleanOPTDefaults to true. Set false to skip the fraud-pattern analysis and the read of your recent request history it depends on.
include_name_matchingbooleanOPTDefaults to true. Set false to skip the name comparison between the submitted name and the matched record.

Example 1: one value per field

One name, one email, one phone, one address. This is the shape most integrations start with.

POST https://api.trustmatch.app/v1/validate/enhanced
X-API-Key: tm_YOUR_KEY
Content-Type: application/json

{
  "name": "Jane Q Doe",
  "emails": ["jane@example.com"],
  "phones": ["6615550101"],
  "addresses": [
    {
      "street": "123 Main St",
      "city": "Austin",
      "state": "TX",
      "zip": "78701"
    }
  ],
  "intent": "online-dating",
  "include_trust_enhancement": true,
  "include_fraud_detection": true,
  "include_name_matching": true
}

Example 2: one person, up to 5 of each

Same person, three emails, three phones, three addresses. Note the partial addresses: the second has no zip, and the third is a street on its own. Both are valid, and both are checked.

POST https://api.trustmatch.app/v1/validate/enhanced
X-API-Key: tm_YOUR_KEY
Content-Type: application/json

{
  "name": "Jane Q Doe",
  "emails": [
    "jane@example.com",
    "j.doe@work.example.com",
    "jqd1982@example.net"
  ],
  "phones": [
    "6615550101",
    "6615550102",
    "2145550147"
  ],
  "addresses": [
    {
      "street": "123 Main St",
      "city": "Austin",
      "state": "TX",
      "zip": "78701"
    },
    {
      "street": "9 Oak Ave",
      "city": "Dallas",
      "state": "TX"
    },
    {
      "street": "44 Pine Rd"
    }
  ]
}
Reading a multi-value response: Each field's top-level input and match_status are a verdict collapsed across every value you sent. The per-value truth is input_validation.<field>.inputs[], one row per submitted value, in submission order. Key rows by input, not position: phones are stripped to digits before matching.

Legacy shape

An earlier version of this API took the upstream graph's own shape, with nameAddresses, emailAddresses, and phoneNumbers. It still works and is not deprecated, so existing integrations need no change. New ones should use the shape above. Sending both forms of the same field is rejected rather than silently resolved.

{
  "operation": "validate",
  "nameAddresses": [
    {
      "fullName": "Jane Q Doe",
      "address": {
        "line1": "123 Main St",
        "city": "Austin",
        "region": "TX",
        "postalCode": "78701",
        "countryCode": "US"
      }
    }
  ],
  "emailAddresses": ["jane@example.com"],
  "phoneNumbers": ["6615550101"]
}

Response

200 for Example 1, trimmed to what this endpoint adds. Everything outside ai_insights is identical to the base endpoint, including input_validation.<field>.inputs[] for multi-input requests.

Response Model

200 OKContent-Type: application/json
{
  "success": true,
  "request_id": "5f3c8b1e-2a4d-4e9c-b6a1-9c7e3f1d8b25",
  "trustworthiness_score": 87,
  "status": "HIGH",
  /* …input_validation, scores, history: identical to POST /v1/validate… */
  "ai_insights": {
    "ai_enabled": true,
    "trust_enhancement": {
      "ai_enabled": true,
      "feature": "trust_enhancement",
      "model": "gemini-3.6-flash",
      "intent": "online-dating",
      "ai_trust_analysis": {
        "summary": "Strong, consistent identity match with a multi-year history.",
        "key_factors": [
          "Name, email, phone and address all resolve to the same primary identity.",
          "Identity first seen over four years ago with recent activity."
        ],
        "red_flags": [],
        "recommendations": [
          "Video chat before meeting in person.",
          "Do not send money, even with a strong verification."
        ]
      }
    },
    "fraud_detection": {
      "ai_enabled": true,
      "feature": "fraud_detection",
      "model": "gemini-3.6-flash",
      "fraud_analysis": {
        "risk_level": "LOW",
        "confidence": 0.86,
        "patterns_detected": [],
        "velocity_concerns": false,
        "consistency_issues": [],
        "stream_observations": [
          "Caller submitted 4 checks in the recent window; no unusual cadence."
        ],
        "recommendation": "No fraud patterns detected for this subject. Proceed with standard precautions."
      },
      "history_analyzed": 4,
      "request_stream": {
        "records_in_window": 4,
        "catfish_flag_count": 0,
        "earliest_timestamp": "2026-09-08T14:02:11Z",
        "latest_timestamp": "2026-09-11T09:41:37Z"
      },
      "scope_note": "fraud_analysis describes the submitted subject. request_stream describes this API caller's own recent traffic and is not a statement about the subject."
    },
    "name_matching": {
      "ai_enabled": true,
      "feature": "name_matching",
      "model": "gemini-3.6-flash",
      "provided_name": "Jane Doe",
      "matched_name": "JANE A DOE",
      "name_analysis": {
        "match_confidence": 96,
        "variation_type": "partial",
        "same_person_likely": true,
        "concerns": [],
        "explanation": "Matched record carries a middle initial the caller omitted; otherwise identical."
      }
    },
    "overview": {
      "overview": "Jane Doe's identity verifies cleanly across every channel you submitted, with no catfish signals.",
      "key_findings": [
        "All four contact channels resolve to one dominant identity.",
        "Identity history spans 4+ years, well above the catfish threshold."
      ],
      "positive_signals": [
        "Email and phone both match the primary identity."
      ],
      "risk_factors": [],
      "recommended_actions": [
        "Video chat before any in-person meeting.",
        "Never send money to someone you have not met."
      ],
      "review_priority": "AUTO_APPROVE"
    }
  }
}

Field reference

  • ai_insights.ai_enabled: true when the AI pipeline ran. Each feature block also carries its own ai_enabled; a block with ai_enabled: true and an error key means that one analysis failed while the rest succeeded. The base response is always complete.
  • fraud_detection.fraud_analysis.risk_level: one of LOW, MEDIUM, HIGH, with confidence 0–1. patterns_detected[], consistency_issues[], and recommendation describe the submitted subject only.
  • fraud_detection.request_stream and stream_observations[] describe your recent API traffic (counts and a time span, never other subjects' outcomes). velocity_concerns is derived from it. Read scope_notebefore rendering any of this next to a subject's name.
  • name_matching.name_analysis.match_confidence: 0–100. variation_type is one of exact, nickname, cultural, transliteration, typo, partial, no_match. same_person_likely is the boolean summary.
  • name_matching.matched_name: the name on the record the graph resolved to, or null when nothing matched. When no name was matched at all, the block reports skipped: true.
  • overview.review_priority: one of AUTO_APPROVE, MANUAL_REVIEW, AUTO_REJECT. Treat as a hint, not a decision.
Fraud detection is not a background check. fraud_detection reasons over the scores and match flags of this request and the cadence of your own API calls. It has no access to criminal, credit, employment, or tenancy data, and its output must not be used for any decision covered by the Fair Credit Reporting Act. TrustMatch is built for dating safety, private sales, sending money, and real-life meetups.

Intent: tailoring the AI narrative

The optional intent field tells TrustMatch what situation the check is for. The Gemini overview adjusts its positive_signals, risk_factors, and recommended_actions to match: the same scores get a different story. The numeric trustworthiness_score and signal status flags are intent-agnostic.

intent valueWhen to use it
online-datingUser is vetting a romantic interest from a dating app, DM, or long-distance contact.
buying-or-sellingUser is about to do a peer-to-peer commerce transaction (Marketplace, OfferUp, watches, cars, tickets).
sending-moneyUser is about to send funds (Zelle, Venmo, crypto, gift cards, vendor deposits, GoFundMe).
suspected-scamUser already suspects fraud. The AI leads with red flags instead of balancing the verdict.
reconnectingUser is verifying a claimed identity from a returning contact, old friend, or claimed family.
generalDefault. Balanced verdict with no use-case bias. Use when none of the above fit.
Note: Intent only changes the AI narrative. On a plain POST /v1/validate call it is recorded but has no visible effect; the base response shape is unchanged.