> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rinne.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# KYC Verification

> How Rinne automatically verifies merchant identity data and reports the results to your organization via the kyc.completed webhook

Rinne runs Know Your Customer (KYC) checks automatically whenever a merchant company is created or has its identification data updated. The checks compare the merchant's registration data against trusted data sources and evaluate a set of verification rules. Results are delivered to the parent organization through the `kyc.completed` webhook.

<Info>
  KYC results are **informational**. They never block company creation or updates—the merchant resource is created or updated regardless of the outcome. Your organization decides how to act on the findings (for example, pausing onboarding or requesting corrected data).
</Info>

## When KYC runs

There are no KYC endpoints to call. Checks are triggered automatically for **merchant** companies:

* **On creation**: every new merchant is checked.
* **On update**: a new check runs only when a KYC-relevant field changes—the tax document type, the legal/full name, or the contact information. Other updates do not trigger a re-check.

Organization-type companies are not checked. Each qualifying create or update produces a new, independent check and its own `kyc.completed` webhook.

```mermaid theme={null}
graph LR
    C[Merchant created or updated] --> K[KYC rules evaluated]
    K --> W[kyc.completed webhook]
    W --> O[Organization endpoint]

    style C fill:#7B89FF,color:#fff
    style K fill:#5B68EB,color:#fff
    style W fill:#4A56D9,color:#fff
    style O fill:#7B89FF,color:#fff
```

## Check types

The set of rules evaluated depends on the merchant's document type, reported as `kyc_type` in the webhook:

* `NATURAL_PERSON_COMPANY`: the merchant is an individual (CPF).
* `LEGAL_PERSON_COMPANY`: the merchant is a legal entity (CNPJ). Rules also cover the registered contact person and the company's ownership structure.

## Rule results

Each rule execution reports a `status`:

| Status         | Meaning                                                                                                                                                             |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PASSED`       | The data source confirms the merchant's data for this rule.                                                                                                         |
| `ISSUES_FOUND` | A discrepancy or risk signal was found—review it and decide how to proceed.                                                                                         |
| `FAILED`       | The rule could not be evaluated (for example, the data source did not return the needed information). Treat it as inconclusive, not as a problem with the merchant. |

Every rule execution includes the `expected` values required to pass and, unless the underlying data was unavailable, the `received` values actually observed. A human-readable `description` is included whenever the rule does not pass.

### Rules for natural persons

| Rule                    | Verifies                                                     |
| ----------------------- | ------------------------------------------------------------ |
| `DOCUMENT_NUMBER_VALID` | The CPF exists                                               |
| `DOCUMENT_STATUS_VALID` | The CPF is in a regular status                               |
| `FULL_NAME_CORRECT`     | The provided name matches the document holder                |
| `DATE_OF_BIRTH_CORRECT` | The provided date of birth matches the document holder       |
| `IS_ALIVE`              | The document holder is not deceased                          |
| `HAS_SANCTIONS`         | The document holder is not sanctioned or politically exposed |

### Rules for legal entities

| Rule                           | Verifies                                                 |
| ------------------------------ | -------------------------------------------------------- |
| `LEGAL_DOCUMENT_NUMBER_VALID`  | The CNPJ exists                                          |
| `LEGAL_DOCUMENT_STATUS_VALID`  | The CNPJ is in a regular status                          |
| `LEGAL_NAME_CORRECT`           | The provided legal name matches the registration         |
| `LEGAL_HAS_SANCTIONS`          | The entity is not sanctioned                             |
| `COMPANY_TYPE_CORRECT`         | The declared company type matches the registration       |
| `IS_CONTACT_REPRESENTATIVE`    | The registered contact is a representative of the entity |
| `NO_SHAREHOLDERS_RESTRICTIONS` | No restrictions found on the entity's shareholders       |

For legal entities, the registered contact person (CPF) is also verified with contact-scoped counterparts of the natural-person rules: `CONTACT_DOCUMENT_NUMBER_VALID`, `CONTACT_DOCUMENT_STATUS_VALID`, `CONTACT_FULL_NAME_CORRECT`, `CONTACT_DATE_OF_BIRTH_CORRECT`, `CONTACT_IS_ALIVE`, and `CONTACT_HAS_SANCTIONS`.

<Note>
  The exact set of rules executed comes from the KYC policy applied to the check, identified by `policy_id` and `policy_name` in the webhook payload. Handle the `rule_executions` array dynamically rather than expecting a fixed list.
</Note>

## The `kyc.completed` webhook

The webhook is delivered to the parent organization using the same envelope, Svix signatures, and retry behavior as every other Rinne event (see [Webhooks](/guides/webhooks)). In the envelope, `company_id` is the **merchant** that was checked and `correlation_id` equals the `kyc_check_id`.

```json theme={null}
{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "type": "kyc.completed",
  "version": 1,
  "timestamp": "2025-01-15T10:30:00.000Z",
  "source": "kyc",
  "company_id": "889fd9b3-1634-429a-b54f-eaa0004345cd",
  "correlation_id": "d01c7832-b63c-4cb6-90b0-74e821f7123e",
  "payload": {
    "kyc_check_id": "d01c7832-b63c-4cb6-90b0-74e821f7123e",
    "company_id": "889fd9b3-1634-429a-b54f-eaa0004345cd",
    "policy_id": "cb350742-a9b8-4a3c-9d7a-02aa8cbb24cb",
    "policy_name": "rinne-default-natural-person",
    "kyc_type": "NATURAL_PERSON_COMPANY",
    "rule_executions": [
      {
        "rule_name": "DOCUMENT_NUMBER_VALID",
        "status": "PASSED",
        "expected": { "document_exists": true },
        "received": { "document_exists": true }
      },
      {
        "rule_name": "HAS_SANCTIONS",
        "status": "ISSUES_FOUND",
        "expected": { "is_sanctioned": false, "is_pep": false },
        "received": { "is_sanctioned": true, "is_pep": false },
        "description": "Document holder is currently sanctioned"
      }
    ]
  }
}
```

### Payload fields

* `kyc_check_id`: Unique ID of this check run
* `company_id`: The merchant company that was checked
* `policy_id` / `policy_name`: The KYC policy that defined the rules
* `kyc_type`: `NATURAL_PERSON_COMPANY` or `LEGAL_PERSON_COMPANY`
* `rule_executions`: One entry per rule in the policy—`rule_name`, `status`, `expected`, and `received` (omitted only if the underlying data was unavailable); `description` is included when the rule does not pass

<Tip>
  Delivery is at-least-once. Use the event `id` for idempotency, and `kyc_check_id` to group rule results belonging to the same check when a merchant is checked more than once.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/guides/webhooks">
    Endpoint setup, Svix signature verification, and retries
  </Card>

  <Card title="Organizations and merchants" icon="sitemap" href="/concepts/organizations-and-merchants">
    How merchants relate to your organization
  </Card>

  <Card title="Affiliations" icon="link" href="/concepts/affiliations">
    Provider onboarding and document requirements
  </Card>

  <Card title="API reference" icon="code" href="/api-reference/introduction">
    Full kyc.completed event schema under Webhooks → Events
  </Card>
</CardGroup>
