Identity Verification

Identity verification uses Stripe Identity to verify a user’s identity through government-document submission and a live selfie. After Stripe approval, an automated NameScan check runs against PEP/sanctions databases before the user is marked as fully verified.

Table of Content:

Initiate verification

Create a new Stripe verification session for the authenticated user. If the user already has a pending verification session, the previous Stripe session is canceled and a fresh one is created. If the user is already verified, the current status is returned.

Endpoint: https://apis.threatwinds.com/api/auth/v2/verify

Parameters

Parameter Location Type Required Description
Authorization header string Yes The bearer token for an active session.

To initiate verification, use a POST request, for example:

curl -X 'POST' \
  'https://apis.threatwinds.com/api/auth/v2/verify' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer fq6JoEFTsxiXAl1cVdPDnK4emIQCwaUBfq6JoEFTsxiXAl1cVxPDnK4emIQCwaUB'

Returns

New or reset verification — returns a Stripe session for the user to complete:

{
  "clientSecret": "vs_c_1234567890abcdef",
  "sessionId": "vs_1234567890abcdef",
  "status": "pending",
  "url": "https://verify.stripe.com/ixs_1234567890abcdef"
}

The clientSecret is passed to the Stripe Verify component in the frontend to render the document upload and selfie capture modal. Alternatively, the url field provides a Stripe-hosted verification page the user can be redirected to (similar to Stripe Checkout or Customer Portal). The URL expires after 48 hours and can only be used once.

Already verified — returns the current verification status with full KYC data:

{
  "status": "passed",
  "attempts": 1,
  "maxAttempts": 3,
  "verifiedAt": "2026-05-02T14:30:00Z",
  "expiresAt": "2026-06-15T10:23:41Z",
  "country": "US",
  "dateOfBirth": "1990-01-15T00:00:00Z",
  "addressLine1": "123 Main St",
  "addressLine2": "",
  "city": "New York",
  "state": "NY",
  "postalCode": "10001",
  "nationality": "USA",
  "attemptsLog": [
    {
      "createdAt": "2026-05-02T14:30:00Z",
      "status": "passed"
    }
  ]
}

Note: The attemptsLog includes up to 5 most recent attempts. The lastFailedReason field may also be present if there were recent failures.

Note: If the user’s verification status is failed and they have exhausted all attempts, the endpoint returns HTTP 403 Forbidden with a structured body:

{
  "code": "max_attempts_reached",
  "message": "You have used all verification attempts",
  "attempts": 3,
  "maxAttempts": 3,
  "lastFailedReason": "NameScan hit found: pep=1, sip=0"
}

Get verification status

Retrieve the current identity verification status for the authenticated user, including attempt count and expiration details.

Endpoint: https://apis.threatwinds.com/api/auth/v2/verify/status

Parameters

Parameter Location Type Required Description
Authorization header string Yes The bearer token for an active session.

To get the verification status, use a GET request, for example:

curl -X 'GET' \
  'https://apis.threatwinds.com/api/auth/v2/verify/status' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer fq6JoEFTsxiXAl1cVdPDnK4emIQCwaUBfq6JoEFTsxiXAl1cVxPDnK4emIQCwaUB'

Returns

A successful response will return a JSON object with verification status details:

No verification record exists:

{
  "status": "none",
  "attempts": 0,
  "maxAttempts": 3
}

Verification in progress:

{
  "status": "pending",
  "attempts": 1,
  "maxAttempts": 3,
  "lastFailedReason": "The document is expired.",
  "expiresAt": "2026-06-15T10:23:41Z",
  "verifiedAt": null,
  "attemptsLog": [
    {
      "createdAt": "2026-06-10T14:30:00Z",
      "status": "failed",
      "failedReason": "The document is expired."
    }
  ]
}

Verification completed with KYC data:

{
  "status": "passed",
  "attempts": 1,
  "maxAttempts": 3,
  "verifiedAt": "2026-05-02T14:30:00Z",
  "expiresAt": "2026-06-15T10:23:41Z",
  "country": "US",
  "dateOfBirth": "1990-01-15T00:00:00Z",
  "addressLine1": "123 Main St",
  "addressLine2": "",
  "city": "New York",
  "state": "NY",
  "postalCode": "10001",
  "nationality": "USA",
  "attemptsLog": [
    {
      "createdAt": "2026-05-02T14:30:00Z",
      "status": "passed"
    }
  ]
}

KYC fields

After the user completes Stripe Identity verification, the following additional fields are populated from the verified government document. These fields are empty (null or "") until verification is complete:

Field Type Description
country string Issuing country of the document (ISO 3166-1 alpha-2).
dateOfBirth string Date of birth from the document (RFC 3339). Nullable.
addressLine1 string First line of the address from the document.
addressLine2 string Second line of the address from the document.
city string City from the document.
state string State/province from the document.
postalCode string Postal/zip code from the document.
nationality string Nationality from the document (ISO 3166-1 alpha-3).

Status values

Status Description
none No verification session has been created for this user.
pending A verification session is active and awaiting document/selfie submission.
passed Stripe Identity check passed and NameScan cleared. User is fully verified.
failed Verification failed (too many attempts, NameScan hit, or revoked).
expired The verification expired after the validity period.

Attempt log

The attemptsLog array provides the history of recent verification attempts (up to 5 most recent, newest first). Each entry contains:

Field Type Description
createdAt string When the attempt was recorded (RFC 3339).
status string "passed", "failed", or "canceled".
failedReason string Why the attempt failed (present when status is "failed" or "canceled").

Common failure reasons:

Reason Cause
“The document is expired.” The submitted ID document has expired
“The selfie did not match the document.” The live selfie photo did not match the ID photo
“The document photo was unclear.” The document photo quality was insufficient
“NameScan hit found: pep=X, sip=Y” NameScan screening detected a PEP or sanctions match
“user canceled verification” The user canceled the verification before completing it

The lastFailedReason field is a convenience for the most recent failure, so you don’t need to scan the array.


Error Response Headers

For responses with status codes other than 200 and 202, the following headers are included:

Header Description
x-error Contains a description of the error that occurred
x-error-id Contains a unique identifier for the error for support

Error Codes

Status Code Description Possible Cause
400 Bad Request Invalid request parameters or malformed JSON
401 Unauthorized Missing or invalid authentication credentials
403 Forbidden Max verification attempts reached (body includes lastFailedReason)
404 Not Found The requested resource does not exist
500 Internal Server Error Server-side error; please contact support if persistent