Contact Match

Overview

Contact Match compares the identity attributes you already have against the identity Trustfull can resolve, and returns one status per attribute. It is a comparison product, not a decision product: the response tells you where your data agrees with our raw data, field by field, and your own policy decides what to do with that pattern.

Three properties define the contract:

  • Statuses, never raw data. Each result carries a field name and a status. Trustfull never returns its raw data for a field, so a mismatch tells you that you disagree, not what the alternative is.
  • No score and no verdict. There is no aggregate number in the payload. Counting and weighting the statuses is your decision.
  • Never wider than your request. Attributes you do not send are absent from the response.

Limited availability. Contact Match runs on a dedicated endpoint with its own API keys, separate from the main Trustfull API. Contact your account team to be enabled. Need help? See Getting Support.

Authentication

All requests require an x-api-key header carrying the key issued for Contact Match.

x-api-key: your-api-key-here

Keep your API key secure. Do not expose it in client-side code, public repositories, or browser requests. All calls must be made from your backend.

Endpoint

Contact Match uses a dedicated host rather than api.fido.id. Every comparison is a POST to a single endpoint:

POST https://kyc.trustfull.com/v1/verify

Request Format

Every attribute belongs to a single DataFields object, grouped by attribute type. DataFields is the only required key: every group inside it, and every field inside a group, is optional. Send only the attributes you actually have, because an absent field is never treated as a mismatch.

{
  "DataFields": {
    "PersonInfo": {
      "FirstGivenName": "John",
      "MiddleName": "Henry",
      "FirstSurName": "Smith",
      "DayOfBirth": "5",
      "MonthOfBirth": "3",
      "YearOfBirth": "1983",
      "Gender": "M"
    },
    "Location": {
      "BuildingNumber": "10",
      "UnitNumber": "3",
      "StreetName": "Lawford",
      "StreetType": "st",
      "City": "Milano",
      "Suburb": "Doncaster",
      "StateProvinceCode": "MI",
      "PostalCode": "20121"
    },
    "Communication": {
      "MobileNumber": "393401234567"
    }
  }
}

Three formatting rules affect your results:

  • Case is irrelevant. Every comparison upper-cases both sides first.
  • Date parts are whole numbers. "5" and 5 are equivalent, and an unpadded "3" is correct for March.
  • MobileNumber is matched as an exact string. Send the country code with no separators, spaces, or leading +. A differently formatted number produces a formatting mismatch, not an identity mismatch.
curl -X POST https://kyc.trustfull.com/v1/verify \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key-here" \
  -d '{
    "DataFields": {
      "PersonInfo": {
        "FirstGivenName": "John",
        "FirstSurName": "Smith",
        "DayOfBirth": "5",
        "MonthOfBirth": "3",
        "YearOfBirth": "1983"
      },
      "Communication": {
        "MobileNumber": "393401234567"
      }
    }
  }'

Supported Fields

Sixteen attributes are compared and can appear in the response. Each is compared in one of two ways:

  • Exact: case-insensitive whole-string equality. An exact field never returns partial_match.
  • Fuzzy: a bounded number of character differences is tolerated. Only fuzzy fields can return partial_match.

A key field also helps Trustfull resolve the person in the first place. See What Makes a Lookup Possible.

PersonInfo

FieldTypeComparedNotes
FirstGivenNamestringFuzzyKey. Given name.
MiddleNamestringFuzzyCompared only when you send it.
FirstSurNamestringFuzzyKey. Note the capital N in the field name.
DayOfBirthnumberExactKey. 1-31, unpadded.
MonthOfBirthnumberExactKey. 1-12, unpadded.
YearOfBirthnumberExactKey. Four digits.
GenderstringExactCompared as sent, for example M or F.

Location

FieldTypeComparedNotes
BuildingNumberstringExactStreet number.
UnitNumberstringExactFlat or apartment number.
StreetNamestringFuzzyName only. Keep the type in StreetType.
StreetTypestringExactVia, Corso, St, Rd.
CitystringExactExact, so send the official place name.
SuburbstringFuzzySubdivision or municipality.
StateProvinceCodestringExactProvince or state code.
PostalCodestringExactZIP or CAP.

Communication

FieldTypeComparedNotes
MobileNumberstringExactKey. The strongest resolution key.

What Makes a Lookup Possible

Before anything can be compared, Trustfull has to resolve the person. The two routes below are tried in order and the first one that resolves wins, so this list is a precedence and not a menu. Meeting at least one route is the difference between a useful response and a response of all missing.

  1. Communication.MobileNumber - the strongest route. A mobile number on its own resolves an identity, and sending it materially improves the fill rate of every other field.
  2. FirstGivenName + FirstSurName + DayOfBirth + MonthOfBirth + YearOfBirth - name plus a complete date of birth. All five must be present, so a year-only or month-and-year date does not qualify.

When no route resolves, the call still returns 200. Every attribute you sent comes back as missing. Read that as "we could not see this person", not as "this person is wrong": an all-missing response carries no evidence in either direction.

Sending a mobile number together with name and full date of birth is the most reliable request you can make. The number resolves the identity, and each remaining attribute is then compared on its own.

Response Format

A successful call returns 200 with one flat array of results. Order is stable (person attributes, then location, then mobile number), but key on FieldName rather than on position.

{
  "DatasourceResults": {
    "DatasourceFields": [
      { "FieldName": "FirstGivenName", "Status": "partial_match" },
      { "FieldName": "MiddleName",     "Status": "missing" },
      { "FieldName": "FirstSurName",   "Status": "match" },
      { "FieldName": "MonthOfBirth",   "Status": "match" },
      { "FieldName": "YearOfBirth",    "Status": "no_match" },
      { "FieldName": "Gender",         "Status": "match" },
      { "FieldName": "StreetName",     "Status": "partial_match" },
      { "FieldName": "PostalCode",     "Status": "match" },
      { "FieldName": "MobileNumber",   "Status": "match" }
    ]
  }
}

One rule governs the contents of the array, and it means the array can be shorter than you expect:

  • Attributes you did not send are omitted entirely. There is no not_provided status in the payload, so silence means you never asked. In the example above, DayOfBirth is absent because the request did not include it.

Status values are always lower case.

The Four Statuses

These are four distinct outcomes rather than a scale. In evidential terms missing and no_match are opposites: one is an absence of information, the other is a contradiction.

StatusMeaning
matchYour value and our raw data are both present and identical, ignoring case. On a fuzzy field this means zero character differences.
partial_matchYour value and our raw data are both present and not identical, but the difference falls inside the tolerance for that field's length. Only fuzzy fields return this.
no_matchYour value and our raw data are both present and disagree beyond tolerance. This is positive evidence of a discrepancy.
missingYou sent the attribute but Trustfull has no raw data for it, either because the resolved identity is not populated for that attribute or because no identity could be resolved. It is never a statement about your value.

Because missing covers both "attribute not available" and "person not found", treat an all-missing response as no signal rather than a negative one. A response that mixes match with a single no_match is the informative case.

How Partial Match Is Decided

Five fields tolerate a small difference between your value and our raw data: FirstGivenName, MiddleName, FirstSurName, StreetName, and Suburb. Roughly one character in five may differ, so a typo, an accent, or a transliteration variant still returns partial_match. Case never matters anywhere.

Every other compared field is matched exactly and returns only match, no_match, or missing. That includes dates, gender, building and unit numbers, street type, city, state or province code, postal code, and mobile number.

One consequence is worth planning for: your value is compared only once Trustfull also has raw data for that field. Absent raw data always reads as missing and never as no_match.

Do not read partial_match as "weak match". It means your value and our raw data differ by an amount consistent with a transliteration, a typo, or a diacritic that survived differently on each side. Most integrators count it with match on name fields and review it separately on address fields, where a single difference can point to a different street. That choice is yours to tune.

Worked Comparisons

You sendOur raw dataResult
johnJOHNmatch
JohnJOHNSpartial_match
SmithSMYTHpartial_match
LawfordLAWFORpartial_match
Maria-LuisaMARIALUISApartial_match
LiLUno_match
RossiVERDIno_match
MilanoMILANno_match
HenryNo raw datamissing

Errors

CodeBodyWhen
200DatasourceResultsComparison completed. Also returned when no identity could be resolved, in which case every status is missing.
403{"status":"ko","error":"missing x-api-key"}No x-api-key header on the request.
403{"status":"ko","error":"auth failed"}Key not recognised, or not enabled for Contact Match.
500{"status":"ko","error":"internal error"}Includes a malformed body and a payload with no DataFields object. Validate your payload shape before retrying.

Integration Notes

  • Retries are safe. The call has no side effects you can observe, and an identical request returns identical statuses.
  • Set a client timeout you can live with. Budget a few seconds, and fail open or closed according to your own policy.
  • Send the widest payload you legitimately have. Unmatched fields cost you nothing because they are omitted rather than penalised, and every extra attribute is another independent piece of evidence.
  • Key on FieldName and tolerate unknown names. Comparable attributes are added over time, and a parser that fails on an unrecognised field name will break on a future release.

FAQ

📘

Do you return your raw data when a field does not match?

No. Every result is a field name and a status. Trustfull never returns its raw data, so no_match tells you that your value and our raw data disagree, and nothing about what our raw data contains.

📘

Every field came back as missing. What went wrong?

Nothing failed: the call succeeded, but no identity could be resolved from what you sent. Check the request against What Makes a Lookup Possible, and remember that an all-missing response is an absence of evidence rather than a negative result.

📘

Should I treat partial_match as a pass or a fail?

That is your policy decision. Most integrators count it as a pass on name fields, where it usually reflects a spelling or transliteration variant, and review it separately on address fields, where a small difference can point to a different street.

📘

Why is City a no_match when my value is nearly right?

City is compared exactly, so Milano and MILAN disagree. Only FirstGivenName, MiddleName, FirstSurName, StreetName, and Suburb allow a near value. Send official place names rather than colloquial or anglicised ones.

📘

I sent a field but it is not in the response. Why?

The most likely cause is a spelling difference in the key name, so the field never arrived. FirstSurName carries a capital N, and that one catches most integrations. Check the request against Supported Fields.

📘

Can I send a name without a date of birth?

You can, and the fields you send are still compared. Without a mobile number, though, a name on its own rarely resolves an identity, so expect a response of all missing.

📘

Is it safe to retry a request?

Yes. The call has no side effects you can observe, and an identical request returns identical statuses.


Did this page help you?