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

# Company Verification

> Verify a company end-to-end with registry checks, director screening, and UBO screening.

# Company Verification

Verify a company end-to-end with registry checks, director screening, and UBO screening. This guide covers submitting company data, retrieving results, and interpreting the compliance report.

## What Company Verification checks

When you submit a company for verification, Zenoo orchestrates four check types:

1. **Company Registry Verification**. Legal name, registration number, incorporation status, registered address, directors, and shareholders from official registries.
2. **Company Screening** (WorldCheck). PEP, sanctions, and adverse media screening on the company entity itself.
3. **Director Screening** (WorldCheck). Individual screening for each director you provide or that the registry returns.
4. **UBO Screening** (WorldCheck). Individual screening for each beneficial owner.

## Data tiers

You can submit three levels of data. More data produces better matching and richer risk scoring.

<Tip>
  Providing Standard tier or above is recommended for production. Minimum tier works for testing but produces less accurate risk scoring.
</Tip>

<AccordionGroup>
  <Accordion title="Tier 1: Minimum">
    The bare minimum to run a registry check and company screening.

    ```json theme={null}
    {
      "company_name": "Acme Holdings Ltd",
      "registration_number": "12345678",
      "country": "GB"
    }
    ```
  </Accordion>

  <Accordion title="Tier 2: Standard (recommended)">
    Adds directors, UBOs, and company details. This is the recommended minimum for production.

    ```json theme={null}
    {
      "company_name": "Acme Holdings Ltd",
      "registration_number": "12345678",
      "country": "GB",
      "company_type": "Private Limited Company (Ltd)",
      "incorporation_date": "2015-03-15",
      "industry": "Financial Services",
      "address_line_1": "123 High Street",
      "city": "London",
      "postcode": "EC1A 1BB",
      "directors": [
        {
          "first_name": "Jane",
          "last_name": "Smith",
          "date_of_birth": "1980-05-20",
          "nationality": "GB",
          "role": "Director"
        }
      ],
      "ubos": [
        {
          "first_name": "John",
          "last_name": "Doe",
          "date_of_birth": "1975-11-10",
          "nationality": "GB",
          "ownership_percentage": 75,
          "role": "UBO"
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="Tier 3: Full">
    Adds external reference for idempotency, financial data, and entity identifiers.

    ```json theme={null}
    {
      "company_name": "Acme Holdings Ltd",
      "registration_number": "12345678",
      "country": "GB",
      "company_type": "Private Limited Company (Ltd)",
      "incorporation_date": "2015-03-15",
      "industry": "Financial Services",
      "address_line_1": "123 High Street",
      "city": "London",
      "postcode": "EC1A 1BB",
      "external_reference": "YOUR-REF-2026-0042",
      "annual_revenue": 5000000,
      "employee_count": 45,
      "sic_codes": ["64110", "64205"],
      "status": "Active",
      "entity_id": "ent-abc-123",
      "directors": [
        {
          "first_name": "Jane",
          "last_name": "Smith",
          "date_of_birth": "1980-05-20",
          "nationality": "GB",
          "role": "Director",
          "entity_id": "ent-dir-456"
        }
      ],
      "ubos": [
        {
          "first_name": "John",
          "last_name": "Doe",
          "date_of_birth": "1975-11-10",
          "nationality": "GB",
          "ownership_percentage": 75,
          "role": "UBO",
          "entity_id": "ent-ubo-789"
        }
      ]
    }
    ```
  </Accordion>
</AccordionGroup>

## Field reference

| Field                 | Type      | Required | Description                                              |
| --------------------- | --------- | -------- | -------------------------------------------------------- |
| `company_name`        | string    | Yes      | Legal name of the company                                |
| `registration_number` | string    | Yes      | Official registration or incorporation number            |
| `country`             | string    | Yes      | ISO 3166-1 alpha-2 country code (e.g. `GB`, `US`, `DE`)  |
| `company_type`        | string    | No       | Legal entity type (e.g. `Private Limited Company (Ltd)`) |
| `incorporation_date`  | string    | No       | Date of incorporation in `YYYY-MM-DD` format             |
| `industry`            | string    | No       | Industry classification or description                   |
| `address_line_1`      | string    | No       | Registered office street address                         |
| `city`                | string    | No       | Registered office city                                   |
| `postcode`            | string    | No       | Registered office postal code                            |
| `external_reference`  | string    | No       | Your internal reference ID. Enables idempotency.         |
| `annual_revenue`      | number    | No       | Annual revenue in base currency units                    |
| `employee_count`      | number    | No       | Number of employees                                      |
| `sic_codes`           | string\[] | No       | Standard Industrial Classification codes                 |
| `status`              | string    | No       | Company status (e.g. `Active`, `Dissolved`)              |
| `entity_id`           | string    | No       | Your internal entity identifier                          |
| `directors`           | object\[] | No       | Array of director objects (see below)                    |
| `ubos`                | object\[] | No       | Array of beneficial owner objects (see below)            |

**Director and UBO fields:**

| Field                  | Type   | Required | Description                                                                        |
| ---------------------- | ------ | -------- | ---------------------------------------------------------------------------------- |
| `first_name`           | string | Yes      | First name                                                                         |
| `last_name`            | string | Yes      | Last name                                                                          |
| `date_of_birth`        | string | No       | Date of birth in `YYYY-MM-DD` format. Strongly recommended for screening accuracy. |
| `nationality`          | string | No       | ISO 3166-1 alpha-2 country code                                                    |
| `role`                 | string | No       | Role in the company (e.g. `Director`, `UBO`, `Secretary`)                          |
| `ownership_percentage` | number | No       | Beneficial ownership percentage (UBOs only)                                        |
| `entity_id`            | string | No       | Your internal entity identifier                                                    |

<Steps>
  <Step title="Submit company data">
    ### Sync mode (recommended for server-to-server)

    Results are returned directly in the response body. Add the `X-SYNC-TIMEOUT` header to set the maximum wait time in milliseconds.

    ```bash theme={null}
    curl -X POST \
      "https://instance.prod.onboardapp.io/api/gateway/execute/{project_hash}/api" \
      -H "Content-Type: application/json" \
      -H "X-API-KEY: your-api-key" \
      -H "X-SYNC-TIMEOUT: 60000" \
      -d '{
        "company_name": "Acme Holdings Ltd",
        "registration_number": "12345678",
        "country": "GB",
        "company_type": "Private Limited Company (Ltd)",
        "incorporation_date": "2015-03-15",
        "industry": "Financial Services",
        "address_line_1": "123 High Street",
        "city": "London",
        "postcode": "EC1A 1BB",
        "external_reference": "YOUR-REF-2026-0042",
        "directors": [
          {
            "first_name": "Jane",
            "last_name": "Smith",
            "date_of_birth": "1980-05-20",
            "nationality": "GB",
            "role": "Director"
          }
        ],
        "ubos": [
          {
            "first_name": "John",
            "last_name": "Doe",
            "date_of_birth": "1975-11-10",
            "nationality": "GB",
            "ownership_percentage": 75,
            "role": "UBO"
          }
        ]
      }'
    ```

    ### Async mode

    If you prefer non-blocking execution, call the `/init` endpoint without the `X-SYNC-TIMEOUT` header.

    ```bash theme={null}
    curl -X POST \
      "https://instance.prod.onboardapp.io/api/gateway/execute/{project_hash}/init" \
      -H "Content-Type: application/json" \
      -H "X-API-KEY: your-api-key" \
      -d '{
        "company_name": "Acme Holdings Ltd",
        "registration_number": "12345678",
        "country": "GB",
        "external_reference": "YOUR-REF-2026-0042",
        "directors": [
          {
            "first_name": "Jane",
            "last_name": "Smith",
            "date_of_birth": "1980-05-20",
            "nationality": "GB",
            "role": "Director"
          }
        ],
        "ubos": [
          {
            "first_name": "John",
            "last_name": "Doe",
            "date_of_birth": "1975-11-10",
            "nationality": "GB",
            "ownership_percentage": 75,
            "role": "UBO"
          }
        ]
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "tokens": {
        "pull": "eyJhbGciOiJIUzI1NiJ9.pull-token...",
        "start": "eyJhbGciOiJIUzI1NiJ9.start-token..."
      }
    }
    ```

    <Warning>
      Store the `pull` token immediately. It is the only way to retrieve results. If you lose it, you must reinitiate the verification.
    </Warning>
  </Step>

  <Step title="Retrieve results">
    ### Sync mode

    Results are returned directly in the response body. Skip to the next step.

    ### Async mode: poll for results

    ```bash theme={null}
    curl -X GET \
      "https://instance.prod.onboardapp.io/api/gateway/sharable-payload/{pull_token}"
    ```

    | Status               | Meaning                               |
    | -------------------- | ------------------------------------- |
    | `200` with JSON body | Results are ready                     |
    | `204` No Content     | Still processing, retry after a delay |
    | `404`                | Invalid or expired token              |

    **Polling strategy:**

    * First 2 minutes: poll every 10 seconds
    * After 2 minutes: poll every 30 seconds
    * Typical completion time: 30 seconds to 5 minutes

    ### Async mode: webhook notification

    Configure a webhook endpoint to receive a `verification.completed` event when processing finishes. See [Webhooks Guide](/guides/webhooks) for setup instructions.

    You can use both strategies together: webhooks for real-time notification, polling as a fallback.
  </Step>

  <Step title="Interpret the compliance report">
    A complete Company Verification response contains six sections: company details, screening results, beneficial owners, directors, risk assessment, and checks summary.

    ```json {5-6} theme={null}
    {
      "case_reference": "AML-2026-0042",
      "external_reference": "YOUR-REF-2026-0042",
      "processing_status": "complete",
      "overall_verdict": "Refer",
      "risk_tier": "Medium",
      "completed_at": "2026-01-15T14:32:00Z",

      "company": {
        "legal_name": "Acme Holdings Limited",
        "registration_number": "12345678",
        "jurisdiction": "GB",
        "company_status": "Active",
        "company_type": "Private Limited Company",
        "incorporation_date": "2015-03-15",
        "registered_address": "123 High Street, London, EC1A 1BB",
        "verification_status": "Verified",
        "verified_at": "2026-01-15T14:30:15Z"
      },

      "screening": {
        "pep_status": "No Hit",
        "sanctions_status": "No Hit",
        "adverse_media_status": "Hit",
        "adverse_media_count": 2,
        "screening_provider": "WorldCheck",
        "screening_completed_at": "2026-01-15T14:30:20Z"
      },

      "beneficial_owners": [
        {
          "name": "John Doe",
          "date_of_birth": "1975-11-10",
          "nationality": "GB",
          "ownership_percentage": 75,
          "pep_status": "No Hit",
          "sanctions_status": "No Hit",
          "adverse_media_status": "No Hit",
          "identity_verified": false
        }
      ],

      "directors": [
        {
          "name": "Jane Smith",
          "date_of_birth": "1980-05-20",
          "role": "Director",
          "pep_status": "No Hit",
          "sanctions_status": "No Hit",
          "adverse_media_status": "No Hit"
        }
      ],

      "risk_assessment": {
        "overall_score": 45,
        "tier": "Medium",
        "factors": [
          {
            "factor": "Adverse Media",
            "severity": "Medium",
            "detail": "2 adverse media articles found for company"
          }
        ]
      },

      "checks_summary": {
        "total": 5,
        "passed": 4,
        "referred": 1,
        "failed": 0,
        "checks": [
          {
            "type": "Company Registration",
            "status": "Pass",
            "provider": "Registry"
          },
          {
            "type": "Company Screening",
            "status": "Refer",
            "provider": "WorldCheck",
            "matches": 2
          },
          {
            "type": "Director Screening (Jane Smith)",
            "status": "Pass",
            "provider": "WorldCheck"
          },
          {
            "type": "UBO Screening (John Doe)",
            "status": "Pass",
            "provider": "WorldCheck"
          },
          {
            "type": "Directors Verification",
            "status": "Pass",
            "provider": "Registry"
          }
        ]
      },

      "compliance_metadata": {
        "cdd_completed": true,
        "cdd_completed_at": "2026-01-15T14:32:00Z",
        "edd_required": false,
        "reviewed_by": "system"
      }
    }
    ```

    Key fields to check:

    * `overall_verdict`. The top-level recommendation: `Pass`, `Refer`, or `Fail`.
    * `risk_tier`. Risk classification: `Low`, `Medium`, or `High`.
    * `screening.*_status`. Whether any screening category returned a match.
    * `checks_summary.checks[]`. Status of each individual check.

    Store the `case_reference` in your database. You will need it for support queries, audit trails, and linking future updates.
  </Step>

  <Step title="Decision logic">
    Use the `overall_verdict` and `risk_tier` together to drive your onboarding workflow.

    | Verdict | Risk Tier | Recommended Action                                |
    | ------- | --------- | ------------------------------------------------- |
    | `Pass`  | Low       | Auto-approve. Proceed with onboarding.            |
    | `Pass`  | Medium    | Auto-approve with enhanced monitoring.            |
    | `Refer` | Medium    | Route to compliance analyst for manual review.    |
    | `Refer` | High      | Route to senior compliance officer. Consider EDD. |
    | `Fail`  | Any       | Reject. Escalate to compliance team.              |

    <Warning>
      If `sanctions_status` is `"Hit"` on any entity (company, director, or UBO), halt onboarding immediately and escalate. Processing sanctioned entities may violate legal obligations in your jurisdiction.
    </Warning>
  </Step>
</Steps>

## How checks are orchestrated

When you submit a company for verification, the check framework automatically creates, executes, and tracks every verification requirement. Here is the orchestration flow:

```mermaid theme={null}
flowchart TD
    A[Entity added to case] --> B[Read Verification Type config]
    B --> C{Execution method?}
    C -->|API / Manual| D[Create Required Check]
    C -->|Document / FreeText / Dropdown| E[Create Document Requirement]
    C -->|Hybrid| F[Create Both with cross-links]
    D --> G{Auto-execute?}
    G -->|Yes| H[Execute via API adapter]
    G -->|No| I[Status: Pending]
    H --> J[Process result]
    J -->|Pass| K[Check Complete]
    J -->|Refer / Fail| L[Generate Alert]
```

For Company Verification, all four check types (registry, company screening, director screening, UBO screening) are API-based and auto-execute immediately after case creation. You do not need to trigger them manually.

Checks that return `Refer` or `Fail` automatically generate alerts in the case management system. Alerts for sanctions hits are always marked Critical priority.

## Verdict mapping

The full Company Verification verdict mapping combines `overall_verdict` and `risk_tier` to determine the appropriate action across all scenarios:

| Verdict | Risk Tier | Recommended Action                                                     |
| ------- | --------- | ---------------------------------------------------------------------- |
| Pass    | Low       | Auto-approve. Proceed with onboarding.                                 |
| Pass    | Medium    | Auto-approve with enhanced monitoring. Schedule periodic re-screening. |
| Refer   | Low       | Quick manual review. Likely a minor data issue.                        |
| Refer   | Medium    | Manual review required. Assign to a compliance analyst.                |
| Refer   | High      | Senior compliance review. Consider enhanced due diligence (EDD).       |
| Fail    | Low       | Investigate the specific failure. May be a data quality issue.         |
| Fail    | Medium    | Reject or request corrected information.                               |
| Fail    | High      | Reject. Escalate to compliance team for review.                        |

### Auto-approve criteria

You can safely auto-approve a Company Verification when ALL of the following are true:

* `overall_verdict` is `"Pass"`.
* `risk_tier` is `"Low"`.
* `sanctions_status` is `"No Hit"` on ALL entities (company, directors, UBOs).
* `pep_status` is `"No Hit"` on ALL entities.
* `adverse_media_status` is `"No Hit"`.

```javascript decision-handler.js theme={null}
function canAutoApprove(result) {
  if (result.overall_verdict !== "Pass") return false;
  if (result.risk_tier !== "Low") return false;

  // Check all screening statuses
  const screening = result.screening || {};
  if (screening.pep_status !== "No Hit") return false;
  if (screening.sanctions_status !== "No Hit") return false;
  if (screening.adverse_media_status !== "No Hit") return false;

  // Check directors and UBOs
  const entities = [
    ...(result.directors || []),
    ...(result.beneficial_owners || [])
  ];
  for (const entity of entities) {
    if (entity.pep_status !== "No Hit") return false;
    if (entity.sanctions_status !== "No Hit") return false;
  }

  return true;
}
```

<Note>
  Any other combination should go to manual review. Do not attempt to auto-approve verifications that do not meet every criterion above.
</Note>

## Idempotency

<Tip>
  Always include `external_reference` in production requests to prevent duplicate verifications. If you submit the same reference twice, Zenoo returns the existing case tokens without creating a duplicate.
</Tip>

```json theme={null}
{
  "company_name": "Acme Holdings Ltd",
  "registration_number": "12345678",
  "country": "GB",
  "external_reference": "YOUR-REF-2026-0042"
}
```

## Country codes

Use ISO 3166-1 alpha-2 codes for all country fields. Common codes:

| Country        | Code            |
| -------------- | --------------- |
| United Kingdom | `GB` (not `UK`) |
| United States  | `US`            |
| Ireland        | `IE`            |
| Germany        | `DE`            |
| France         | `FR`            |
| Netherlands    | `NL`            |
| Switzerland    | `CH`            |

The `country` field determines which registry Zenoo queries and which screening jurisdiction applies.

<Note>
  Using `UK` instead of `GB` will return an error. Always use the ISO 3166-1 alpha-2 standard code `GB` for United Kingdom.
</Note>

## Next steps

* [Person Verification](/use-cases/kyc-verification). Verify directors and UBOs individually with document and biometric checks.
* [Screening](/use-cases/screening). Run standalone screening for ongoing monitoring.
* [Sync vs Async](/guides/sync-vs-async). Choose the right execution model for your integration.
