Inyo

Phone Verification

Phone Verification checks that a phone number actually belongs to the person who claims it, using a carrier identity-match lookup. It compares the sender's name, address, and date of birth against the data the mobile carrier holds for that number and returns a match score. Use it as a fraud signal during onboarding or before a first transaction.

This check is diagnostic and explicit β€” it never runs automatically from the transaction flow, and it never rewrites the sender's stored phone number. Call it when you want a check.


Verifying a Phone Number

Endpoint: POST /organizations/{tenant}/v2/people/verifyPhone
Authentication: Agent-level (x-api-key + x-agent-id + x-agent-api-key)

There are two mutually exclusive calling modes:

ModeSendBehavior
Person modepersonId onlyInyo loads the sender's name, address, and date of birth from the stored record, verifies against the carrier, and mirrors the outcome onto the person (phoneVerificationScore, phoneVerificationStatus, phoneVerificationLastCheckedAt).
Inline modeThe identity fields directly, no personIdStateless β€” nothing is read from or written to the person record.

⚠️ The modes cannot be combined. If you send personId, you must not send any inline identity field, or the request returns 422.

Person Mode

curl --request POST \
  --url https://{FQDN}/organizations/$TENANT/v2/people/verifyPhone \
  --header 'Content-Type: application/json' \
  --header "x-api-key: $API_KEY" \
  --header "x-agent-id: $AGENT_ID" \
  --header "x-agent-api-key: $AGENT_KEY" \
  --data '{
  "personId": "48066496-9445-41b7-acbe-85e069a77cb7"
}'

The sender's stored phoneNumber must already be in E.164 format, otherwise the request returns 422.

Inline Mode

curl --request POST \
  --url https://{FQDN}/organizations/$TENANT/v2/people/verifyPhone \
  --header 'Content-Type: application/json' \
  --header "x-api-key: $API_KEY" \
  --header "x-agent-id: $AGENT_ID" \
  --header "x-agent-api-key: $AGENT_KEY" \
  --data '{
  "phoneNumber": "+14145447770",
  "firstName": "John",
  "lastName": "Doe",
  "addressLine1": "123 Market St",
  "city": "San Francisco",
  "state": "CA",
  "postalCode": "94105",
  "addressCountryCode": "US",
  "dateOfBirth": "1990-01-15"
}'

Request Fields

FieldTypeRequiredDescription
personIdstring (UUID)Person modeThe sender to verify. When present, all identity fields are loaded from the record and none may be sent inline.
phoneNumberstringInline modeThe number to verify, E.164 (+ and 1–15 digits, e.g. +14145447770). Not normalized β€” canonicalize before sending.
firstNamestringNoGiven name to match
lastNamestringNoFamily name to match
addressLine1stringNoStreet address to match
addressLine2stringNoAdditional address line
citystringNoCity to match
statestringNoState/province to match
postalCodestringNoPostal/ZIP code to match
addressCountryCodestringNoISO 3166-1 alpha-2 country code
dateOfBirthstringNoYYYY-MM-DD or YYYYMMDD

More identity fields you provide means a more complete match result.


Response

{
  "verificationId": 42,
  "phoneNumber": "+14145447770",
  "status": "MATCH",
  "summaryScore": 100,
  "callerType": "CONSUMER",
  "valid": true,
  "nationalFormat": "(414) 544-7770",
  "countryCode": "US",
  "identityMatch": {
    "first_name_match": "exact_match",
    "last_name_match": "exact_match",
    "address_lines_match": "exact_match",
    "date_of_birth_match": "exact_match",
    "summary_score": 100
  },
  "verifiedAt": "2026-09-09T14:22:11+00:00",
  "cached": false
}
FieldDescription
verificationIdIdentifier for this verification record
statusOverall outcome β€” MATCH, PARTIAL, NO_MATCH, or ERROR
summaryScoreMatch score 0–100, or null when the provider returned no score
callerTypeCONSUMER, BUSINESS, or similar carrier classification
validWhether the number is a valid, reachable line
nationalFormatThe number formatted for its country
countryCodeISO country code of the number
identityMatchPer-field match detail (name, address parts, date of birth, etc.)
verifiedAtWhen the verification was performed
cachedtrue when this result was served from cache (see below)

Status Thresholds

status is derived from summaryScore using per-tenant thresholds (defaults: MATCH β‰₯ 80, PARTIAL β‰₯ 40, below β†’ NO_MATCH). The status is captured at verification time β€” later threshold changes do not re-bucket historical results. Contact Inyo to tune your thresholds.


Caching

Identical requests are cached per tenant for 90 days, keyed on the full input tuple (phone number, name, address, date of birth). A cache hit returns the stored result with "cached": true and does not re-bill the verification provider. Vary any input field to force a fresh lookup.


Error Responses

HTTPErrorCause
422VALIDATION_ERRORMissing/invalid fields, non-E.164 phone, or personId sent together with inline identity fields
501PROVIDER_NOT_CONFIGUREDThe verification provider is not configured for your tenant β€” contact Inyo support
502PROVIDER_ERRORThe provider is temporarily unavailable β€” retry the request

Sandbox Testing

In the sandbox, phone verification does not call the real provider β€” no billing, no live lookups. Instead, the outcome is driven entirely by the last digit of the phone number, so you can exercise every branch by choosing the number you send:

Phone ends instatussummaryScoreWhat it simulates
0, 1, 2MATCH100Full identity match β€” all fields exact_match
3, 4, 5PARTIAL60Mixed β€” some fields match, some don't
6, 7NO_MATCH20Mostly no_match fields
8ERRORnullProvider returned no score (nothing to match against)
9β€”β€”Upstream 500 β†’ the endpoint returns 502 PROVIDER_ERROR

For example, +14145550002 returns MATCH, and +14145550009 returns 502.

Because the cache key includes the phone number, re-running the same sandbox number returns "cached": true on the second call. Change the number (or any other field) to force a fresh simulated lookup.


All Endpoints

OperationMethodEndpoint
Verify a phone numberPOST/organizations/{tenant}/v2/people/verifyPhone