> For the complete documentation index, see [llms.txt](https://docs.tylt.money/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tylt.money/tylt-crossramp-fiat-crypto-solutions/user-kyc-verification-apis/kyc-module-endpoint.md).

# KYC Module Endpoint

KYC verification modules are initiated through the following endpoint:

```http
POST /common/initiateKyc
```

The verification operation is selected using the `module` field.

Supported modules include:

| **Module** | **Purpose**                    |
| ---------- | ------------------------------ |
| `POI`      | Proof of Identity verification |
| `POA`      | Proof of Address verification  |
| `AML`      | AML screening                  |
| `Liveness` | Liveness verification          |

***

### Proof of Identity — POI

Use the `POI` module to submit the user's identity document for verification.

#### Request Parameters

| **Field**                  | **Type** | **Required** | **Description**                                  |
| -------------------------- | -------- | ------------ | ------------------------------------------------ |
| `emailId`                  | String   | Yes          | Email address of the user                        |
| `module`                   | String   | Yes          | Must be `POI`                                    |
| `payload`                  | Object   | Yes          | Proof-of-identity document information           |
| `payload.poiImageFrontUrl` | String   | Yes          | Secure URL of the front of the identity document |
| `payload.poiImageBackUrl`  | String   | Conditional  | Secure URL of the back of the identity document  |

The back image is not required for single-sided documents such as passports.

#### JavaScript Example

```javascript
const requestBody = {
  emailId: "joe@example.com",
  module: "POI",
  payload: {
    poiImageFrontUrl:
      "https://merchant.example.com/documents/id-front.jpg",
    poiImageBackUrl:
      "https://merchant.example.com/documents/id-back.jpg"
  }
};
```

#### Document URL Requirements

Document URLs should:

* Use HTTPS
* Be accessible by Tylt's verification service
* Point directly to the relevant document image
* Remain valid long enough for verification processing
* Not require an interactive login
* Not expose unrelated user documents
* Use short-lived or restricted-access URLs where supported

The merchant should not use public image-hosting services for production identity documents.

#### Response

```json
{
  "msg": "Didit POI initiation started.",
  "data": {
    "userId": 20413,
    "module": "POI",
    "status": "approved",
    "sessionUrl": null,
    "requestId": "512f270b-e604-40ce-84df-db3063a5c72a",
    "overallKycStatus": "incomplete"
  }
}
```

***

### Proof of Address — POA

Use the `POA` module to submit a proof-of-address document for verification.

#### Request Parameters

| **Field**                | **Type** | **Required** | **Description**                             |
| ------------------------ | -------- | ------------ | ------------------------------------------- |
| `emailId`                | String   | Yes          | Email address of the user                   |
| `module`                 | String   | Yes          | Must be `POA`                               |
| `payload`                | Object   | Yes          | Proof-of-address document information       |
| `payload.poaDocumentUrl` | String   | Yes          | Secure URL of the proof-of-address document |

#### Common Proof-of-Address Documents

Subject to the applicable verification policy, acceptable documents may include:

* Bank statement
* Utility bill
* Government-issued residence document
* Tax document
* Credit-card statement
* Official correspondence showing the user's residential address

Supported document types and document-age requirements are determined by the applicable KYC policy.

#### JavaScript Example

```javascript
const requestBody = {
  emailId: "joe@example.com",
  module: "POA",
  payload: {
    poaDocumentUrl:
      "https://merchant.example.com/documents/address-document.jpg"
  }
};
```

#### Response

```json
{
  "msg": "Didit POA initiation started.",
  "data": {
    "userId": 20413,
    "module": "POA",
    "status": "approved",
    "sessionUrl": null,
    "requestId": "25eb2bf7-3bba-49e3-afa7-bab12d9c5531",
    "overallKycStatus": "incomplete"
  }
}
```

***

### AML Screening

Use the `AML` module to initiate AML screening for the user.

#### Request Parameters

| **Field** | **Type** | **Required** | **Description**           |
| --------- | -------- | ------------ | ------------------------- |
| `emailId` | String   | Yes          | Email address of the user |
| `module`  | String   | Yes          | Must be `AML`             |

No additional `payload` is required for this operation.

#### JavaScript Example

```javascript
const requestBody = {
  emailId: "joe@example.com",
  module: "AML"
};
```

#### Response

```json
{
  "msg": "Didit AML initiation started.",
  "data": {
    "userId": 20413,
    "module": "AML",
    "status": "approved",
    "sessionUrl": null,
    "requestId": "961e0dc6-d035-4a95-aed0-7027b8bcb968",
    "overallKycStatus": "incomplete"
  }
}
```

Depending on the screening result, AML verification may be completed immediately or may require additional review.

#### Possible AML Outcomes

| **Status**        | **Description**                              |
| ----------------- | -------------------------------------------- |
| `approved`        | AML screening has been approved              |
| `pending`         | Screening is still being processed           |
| `requires_review` | Screening requires manual review             |
| `rejected`        | The user did not pass the AML screening      |
| `failed`          | The screening request could not be completed |

> The supported status values should correspond to the statuses returned by the deployed Tylt API.

***

### Liveness Verification

Use the `Liveness` module to initiate a liveness-verification session for the user.

The API returns a user-specific session URL that should be provided to the user to complete the liveness check.

#### Security Requirements

The merchant should:

* Only provide the session link to the relevant user
* Treat the link as sensitive and user-specific
* Avoid logging the complete session URL
* Avoid forwarding the session URL to analytics or third-party tracking services
* Respect the link's expiry period
* Request a new session where the existing session has expired
* Prevent one user from accessing another user's verification session

***

### JavaScript Helper

The following helper can be used to submit signed requests for all supported KYC modules.

```javascript
const axios = require("axios");
const crypto = require("crypto");

const baseUrl = "https://dev-api.tylt.money";

const merchantApiKey = process.env.TYLT_API_KEY;
const merchantApiSecret = process.env.TYLT_API_SECRET;

async function sendSignedRequest(endpoint, requestBody) {
  if (!merchantApiKey || !merchantApiSecret) {
    throw new Error("Missing TYLT API credentials.");
  }

  const rawPayload = JSON.stringify(requestBody);

  const signature = crypto
    .createHmac("sha256", merchantApiSecret)
    .update(rawPayload)
    .digest("hex");

  try {
    const response = await axios.post(
      `${baseUrl}${endpoint}`,
      rawPayload,
      {
        headers: {
          "Content-Type": "application/json",
          "x-tlp-apikey": merchantApiKey,
          "x-tlp-signature": signature
        },
        timeout: 30000
      }
    );

    return response.data;
  } catch (error) {
    const status = error.response?.status;
    const responseData = error.response?.data;

    throw new Error(
      `Tylt API request failed${
        status ? ` with status ${status}` : ""
      }: ${responseData?.msg || error.message}`
    );
  }
}
```

#### Submit POI

```javascript
const result = await sendSignedRequest(
  "/common/initiateKyc",
  {
    emailId: "joe@example.com",
    module: "POI",
    payload: {
      poiImageFrontUrl:
        "https://merchant.example.com/documents/id-front.jpg",
      poiImageBackUrl:
        "https://merchant.example.com/documents/id-back.jpg"
    }
  }
);
```

#### Submit POA

```javascript
const result = await sendSignedRequest(
  "/common/initiateKyc",
  {
    emailId: "joe@example.com",
    module: "POA",
    payload: {
      poaDocumentUrl:
        "https://merchant.example.com/documents/address-document.jpg"
    }
  }
);
```

#### Run AML Screening

```javascript
const result = await sendSignedRequest(
  "/common/initiateKyc",
  {
    emailId: "joe@example.com",
    module: "AML"
  }
);
```

***

### Recommended Verification Sequence

A typical individual KYC flow should follow this sequence:

1. Create or update the user through `/common/initiateUser`.
2. Submit the user's proof of identity using the `POI` module.
3. Submit proof of address using the `POA` module, where required.
4. Run AML screening using the `AML` module.
5. Initiate a liveness-verification session.
6. Ask the user to complete the liveness verification.
7. Retrieve the user's KYC status.
8. Enable regulated wallet or transaction functionality only after all required verification modules have been successfully completed.

***

### Error Handling

A failed request follows the standard response structure:

```json
{
  "msg": "Description of the error",
  "data": {}
}
```

For example:

```json
{
  "msg": "Invalid signature.",
  "data": {}
}
```

Merchants should handle the following HTTP response categories:

| **HTTP Status** | **Description**                                          |
| --------------- | -------------------------------------------------------- |
| `400`           | Missing, malformed, or unsupported request parameters    |
| `401`           | Missing or invalid API authentication                    |
| `403`           | Merchant, user, or requested operation is not authorized |
| `404`           | User or requested resource was not found                 |
| `409`           | Conflicting user or verification data                    |
| `422`           | Submitted verification data could not be processed       |
| `429`           | Too many requests                                        |
| `500`           | Unexpected processing error                              |
| `503`           | Verification service temporarily unavailable             |
