POST/v1/validate?ai=true

TrustCheck with AI insights

The same TrustCheck as POST /v1/validate, plus a Gemini-generated narrative: a plain-language trust assessment and an overview with positive signals, risk factors, and recommended next steps. Add ?ai=true to the URL; the request body, auth, and every base response field are unchanged.

What the flag adds

  • ai_insights.trust_enhancement: a short assessment of the scores (summary, key factors, red flags, recommendations), biased by intent.
  • ai_insights.overview: the end-user-safe narrative: headline, key findings, positive signals, risk factors, recommended actions, and a review_priority hint.
  • fraud_detection and name_matching are null here. For those, use POST /v1/validate/enhanced.

Authentication

Identical to the base endpoint: X-API-Key: tm_... or Authorization: Bearer tm_.... An AI 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.

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?ai=true
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"
    }
  ]
}

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?ai=true
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 variant 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.",
          "No transaction-risk signals on the matched identity."
        ],
        "red_flags": [],
        "recommendations": [
          "Video chat before meeting in person.",
          "Meet in a public place and arrange your own transportation.",
          "Do not send money, even with a strong verification."
        ]
      }
    },
    "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.",
        "Established history is inconsistent with romance-scam patterns."
      ],
      "risk_factors": [],
      "recommended_actions": [
        "Video chat before any in-person meeting.",
        "First meet in a public place. Do not accept rides.",
        "Never send money to someone you have not met."
      ],
      "review_priority": "AUTO_APPROVE"
    },
    "fraud_detection": null,
    "name_matching": null
  }
}

Field reference

  • ai_insights.ai_enabled: true when the AI call succeeded. If false, the base response is still valid and complete; treat the AI block as a soft failure and fall back to summary and insights[].
  • trust_enhancement.ai_trust_analysis.summary: one sentence on the trust level. key_factors[], red_flags[], and recommendations[] are short lists, each 0–3 items.
  • trust_enhancement.intent: the intent the narrative was generated for, after normalisation. Unknown values resolve to general.
  • overview.overview: 1–2 sentence headline, safe to show to end users.
  • overview.positive_signals[]: verified facts that raise confidence (max 5 items). overview.risk_factors[]: flagged concerns; empty when none are detected.
  • overview.recommended_actions[]: suggested next steps; use these to drive your own UI checklist.
  • overview.review_priority: one of AUTO_APPROVE, MANUAL_REVIEW, AUTO_REJECT. Treat as a hint, not a decision.
The narrative never changes the numbers. trustworthiness_score, status, and every per-input match_status are computed before the AI runs and are identical with or without ?ai=true. The AI explains the result; it does not re-score it.

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.