Run a TrustCheck
Submit one person's name plus any combination of emails, phones, and addresses. Get back a scored verification with a verdict per submitted value, sub-scores, history, and an overall result. TrustMatch generates the request_idfor you; you don't need to mint or pass an identifier.
Authentication
Send your key as either X-API-Key: tm_... or Authorization: Bearer tm_.... Each successful call counts against your monthly included quota; calls beyond your plan's included calls are billed as overage on your next invoice.
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.
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.Request Body
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
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
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"
}
]
}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 above. Every field has an inputs[] array even when you sent one value, so a single code path can read both shapes.
Response Model
{
"success": true,
"request_id": "5f3c8b1e-2a4d-4e9c-b6a1-9c7e3f1d8b25",
"trustworthiness_score": 87,
"status": "HIGH",
"confidence_level": "HIGH",
"possible_catfish": false,
"summary": "Identity matched across name, email, phone and address.",
"message": "Strong verification. Standard precautions still apply.",
"input_validation": {
"name": {
"input": "Jane Q Doe",
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Name matches the primary verified identity.",
"inputs": [
{ "input": "Jane Q Doe", "standardized": "JANE Q DOE", "match_status": "Primary Match", "matched_identity": 1, "is_primary": "Yes", "validated": true }
]
},
"email": {
"input": "jane@example.com",
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Email matches the primary verified identity.",
"inputs": [
{ "input": "jane@example.com", "standardized": "jane@example.com", "match_status": "Primary Match", "matched_identity": 1, "is_primary": "Yes", "validated": true }
]
},
"phone": {
"input": "6615550101",
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Phone matches the primary verified identity.",
"inputs": [
{ "input": "6615550101", "standardized": "+16615550101", "match_status": "Primary Match", "matched_identity": 1, "is_primary": "Yes", "validated": true }
]
},
"address": {
"input": ["123 Main St, Austin, TX, 78701"],
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Address matches the primary verified identity.",
"inputs": [
{
"input": { "line1": "123 Main St", "line2": "", "city": "Austin", "region": "TX", "postalCode": "78701", "plus4": "", "countryCode": "" },
"standardized": { "line1": "123 MAIN ST", "line2": "", "city": "AUSTIN", "region": "TX", "postalCode": "78701", "plus4": "1234", "countryCode": "US" },
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"validated": true
}
]
},
"overall_match": { "all_components_match_same_identity": true, "matched_identity": 1 }
},
"identity_score": { "final": 90, "raw": 90, "adjusted": 90, "penalties": 0, "bonuses": 0, "fraud_risk_penalty": 0, "submitted_fields": ["name", "email", "phone"], "match_flags": { "name": "Primary Match", "email": "Primary Match", "phone": "Primary Match" } },
"trust_score": { "final": 85, "raw": 85, "reasons": ["Identity history: 4+ years", "No recent risk signals"] },
"combined_trust_score": { "final": 87, "pre_capped": 87, "confidence_level_label": "high", "explanation": "Strong cross-channel match with established history." },
"verification_flags": [],
"insights": [],
"dominant_identity": 1,
"field_summary": {
"name": { "status": "Primary Match", "matched_identity": 1, "total": 1, "validated": 1, "primary_for_dominant": 1, "validated_for_dominant": 1, "validated_other_identities": {}, "unverified": 0 },
"email": { "status": "Primary Match", "matched_identity": 1, "total": 1, "validated": 1, "primary_for_dominant": 1, "validated_for_dominant": 1, "validated_other_identities": {}, "unverified": 0 },
"phone": { "status": "Primary Match", "matched_identity": 1, "total": 1, "validated": 1, "primary_for_dominant": 1, "validated_for_dominant": 1, "validated_other_identities": {}, "unverified": 0 },
"address": { "status": "Primary Match", "matched_identity": 1, "total": 1, "validated": 1, "primary_for_dominant": 1, "validated_for_dominant": 1, "validated_other_identities": {}, "unverified": 0 }
},
"history": {
"first_seen": "2021-08-14T00:00:00Z",
"last_seen": "2026-04-30T00:00:00Z",
"days_since_first_seen": 1721,
"days_since_last_seen": 14
},
"ai_insights": null
}Response: multiple values
200 for Example 2, trimmed to the parts that change. One name row, then one row per submitted email, phone, and address. The field_summary counts tell you how many values resolved without walking the rows.
{
"success": true,
"request_id": "9b2e4d71-6c0f-4a3e-8d5b-2f1c7e9a0b64",
"trustworthiness_score": 79,
"status": "HIGH",
/* …summary, scores, history: same fields as the single-input response… */
"input_validation": {
"name": {
"input": "Jane Q Doe",
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Name matches the primary verified identity.",
"inputs": [
{ "input": "Jane Q Doe", "standardized": "JANE Q DOE", "match_status": "Primary Match", "matched_identity": 1, "is_primary": "Yes", "validated": true }
]
},
"email": {
"input": "jane@example.com",
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Email matches the primary verified identity.",
"inputs": [
{ "input": "jane@example.com", "standardized": "jane@example.com", "match_status": "Primary Match", "matched_identity": 1, "is_primary": "Yes", "validated": true },
{ "input": "j.doe@work.example.com", "standardized": "j.doe@work.example.com", "match_status": "Secondary Match", "matched_identity": 1, "is_primary": "No", "validated": true },
{ "input": "jqd1982@example.net", "standardized": "jqd1982@example.net", "match_status": "Different Identity Match (ID 2)", "matched_identity": 2, "is_primary": "No", "validated": true }
]
},
"phone": {
"input": "6615550101",
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Phone matches the primary verified identity.",
"inputs": [
{ "input": "6615550101", "standardized": "+16615550101", "match_status": "Primary Match", "matched_identity": 1, "is_primary": "Yes", "validated": true },
{ "input": "6615550102", "standardized": "+16615550102", "match_status": "Secondary Match", "matched_identity": 1, "is_primary": "No", "validated": true },
{ "input": "2145550147", "standardized": "+2145550147", "match_status": "Unverified", "matched_identity": null, "is_primary": "No", "validated": false }
]
},
"address": {
"input": [
"123 Main St, Austin, TX, 78701",
"9 Oak Ave, Dallas, TX",
"44 Pine Rd"
],
"match_status": "Primary Match",
"matched_identity": 1,
"is_primary": "Yes",
"match_message": "VERIFIED MATCH: Address matches the primary verified identity.",
"inputs": [
{ "input": { "line1": "123 Main St", "line2": "", "city": "Austin", "region": "TX", "postalCode": "78701", "plus4": "", "countryCode": "" }, "standardized": { "line1": "123 MAIN ST", "line2": "", "city": "AUSTIN", "region": "TX", "postalCode": "78701", "plus4": "1234", "countryCode": "US" }, "match_status": "Primary Match", "matched_identity": 1, "is_primary": "Yes", "validated": true },
{ "input": { "line1": "9 Oak Ave", "line2": "", "city": "Dallas", "region": "TX", "postalCode": "", "plus4": "", "countryCode": "" }, "standardized": { "line1": "9 OAK AVE", "line2": "", "city": "DALLAS", "region": "TX", "postalCode": "", "plus4": "", "countryCode": "US" }, "match_status": "Secondary Match", "matched_identity": 1, "is_primary": "No", "validated": true },
{ "input": { "line1": "44 Pine Rd", "line2": "", "city": "", "region": "", "postalCode": "", "plus4": "", "countryCode": "" }, "standardized": { "line1": "44 PINE RD", "line2": "", "city": "", "region": "", "postalCode": "", "plus4": "", "countryCode": "" }, "match_status": "Unverified", "matched_identity": null, "is_primary": "No", "validated": false }
]
},
"overall_match": { "all_components_match_same_identity": true, "matched_identity": 1 }
},
"dominant_identity": 1,
"field_summary": {
"name": { "status": "Primary Match", "matched_identity": 1, "total": 1, "validated": 1, "primary_for_dominant": 1, "validated_for_dominant": 1, "validated_other_identities": {}, "unverified": 0 },
"email": { "status": "Primary Match", "matched_identity": 1, "total": 3, "validated": 3, "primary_for_dominant": 1, "validated_for_dominant": 2, "validated_other_identities": { "2": 1 }, "unverified": 0 },
"phone": { "status": "Primary Match", "matched_identity": 1, "total": 3, "validated": 2, "primary_for_dominant": 1, "validated_for_dominant": 2, "validated_other_identities": {}, "unverified": 1 },
"address": { "status": "Primary Match", "matched_identity": 1, "total": 3, "validated": 2, "primary_for_dominant": 1, "validated_for_dominant": 2, "validated_other_identities": {}, "unverified": 1 }
},
"insights": [
"One email resolves to a different identity (ID 2).",
"No matching records for 1 of 3 submitted phone entries.",
"No matching records for 1 of 3 submitted address entries."
]
}Response shape: v1 and v2
Everything above is v1, which is the default and is frozen. It will not change. Integrations built against it keep working with no action.
v2 is opt-in, per request, with ?response=v2 or an Accept-Version: v2 header. It exists because v1 answers in the identity graph’s vocabulary while the request speaks ours: singular keys for plural inputs, and a different set of words for the parts of an address than the ones you just sent.
- Each field of
input_validationis a list, named as you named it —emails, notemail. In v1 the outer object describes only the value the field-level verdict resolved against, so reading it as “the verdict for my emails” is wrong whenever you sent more than one. - Addresses come back as
street/city/state/zip— the same words you sent — rather thanline1/region/postalCode. is_primaryis a boolean, not the string"true".- Scores and
field_summaryare unchanged.
{
"response_version": "v2",
"input_validation": {
"name": [
{
"input": "Jane Q Doe",
"standardized": "JANE Q DOE",
"match_status": "Verified",
"matched_identity": 1,
"is_primary": true,
"validated": true
}
],
"emails": [
{
"input": "jane@example.com",
"standardized": "jane@example.com",
"match_status": "Verified",
"matched_identity": 1,
"is_primary": true,
"validated": true
}
],
"phones": [
{
"input": "6615550101",
"standardized": "6615550101",
"match_status": "Verified",
"matched_identity": 1,
"is_primary": true,
"validated": true
}
],
"addresses": [
{
"input": {
"street": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701"
},
"standardized": {
"street": "123 MAIN ST",
"city": "AUSTIN",
"state": "TX",
"zip": "78701",
"plus4": "1234",
"country": "US"
},
"match_status": "Verified",
"matched_identity": 1,
"is_primary": true,
"validated": true
}
],
"overall_match": {
"all_components_match_same_identity": true,
"matched_identity": 1
}
}
}Notes
request_idis server-generated. Use it to look up this call later or correlate logs.trustworthiness_scoreis 0–100. Verdicts:85+= VERIFIED,65–84= LIKELY REAL,40–64= SUSPICIOUS, below40= HIGH RISK.Unverifiedmeans “no matching record”, not “this failed a check”. It means the identity graph returned nothing it could link to that value. A phone that is real, in service, and genuinely belongs to the person still returnsUnverifiedif it has never appeared in the underlying data. Render it as no record. Do not render it as invalid, suspicious, or could not be verified; those assert a negative finding about a named individual that this response does not support. A value that genuinely belongs to someone else is a different status:Different Identity Match (ID n).- Submitting more than one value for a field? Read
input_validation.<field>.inputs[]; it carries one row per submitted value. The field-levelmatch_statusandmatch_messageare collapsed across every value you sent, andinputnames only the single value the identity graph resolved against. Never treat that pair as a verdict about the other values. addressis present ininput_validationonly when you sent at least one address. Its rows echo what you sent ininputand the graph's canonical form instandardized. Both use the identity graph's field names, so thestreetyou send comes back asline1,stateasregion, andzipaspostalCode.ai_insightsisnullon this endpoint. See the two AI variants below.
AI enhancement
TrustMatch can layer a Gemini-powered analysis on top of any verification. Two opt-in variants, same request body, same auth, same price as a plain call. Each has its own reference page.
TrustCheck + AI. Same payload, plus a Gemini narrative and overview. Read the reference →
TrustCheck Enhanced. Full AI analysis: narrative, fraud patterns, name matching. Read the reference →