Skip to main content

End-to-End Onboarding

This guide walks you through a complete company onboarding lifecycle using the Zenoo CLM API. By the end you will have created an entity, opened an onboarding case, executed compliance checks, reviewed generated alerts, and closed the case.

Prerequisites

  • A valid API key (see Authentication)
  • Base URL: https://api.zenoo.com/v1

What happens during onboarding

When you create an onboarding case, Zenoo automatically:
  1. Creates verification requirements based on entity type and role
  2. Executes API-based checks (screening, registry, identity)
  3. Generates alerts for any hits (PEP, sanctions, adverse media)
  4. Calculates a 4-dimension risk score
1

Create a company entity

Register the company you want to onboard. The response includes the entity token used in all subsequent calls.
curl -X POST https://api.zenoo.com/v1/entities \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "company",
    "name": "Acme Holdings Ltd",
    "registration_number": "12345678",
    "country": "GB",
    "incorporation_date": "2015-03-15",
    "industry": "Financial Services",
    "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"
      }
    ]
  }'
import requests

response = requests.post(
    "https://api.zenoo.com/v1/entities",
    headers={
        "Authorization": "Bearer your-api-key",
        "Content-Type": "application/json",
    },
    json={
        "type": "company",
        "name": "Acme Holdings Ltd",
        "registration_number": "12345678",
        "country": "GB",
        "incorporation_date": "2015-03-15",
        "industry": "Financial Services",
        "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",
            }
        ],
    },
)
entity = response.json()
print(entity["token"])  # ent_abc123
const response = await fetch("https://api.zenoo.com/v1/entities", {
  method: "POST",
  headers: {
    Authorization: "Bearer your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    type: "company",
    name: "Acme Holdings Ltd",
    registration_number: "12345678",
    country: "GB",
    incorporation_date: "2015-03-15",
    industry: "Financial Services",
    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",
      },
    ],
  }),
});
const entity = await response.json();
console.log(entity.token); // ent_abc123
Response:
{
  "token": "ent_abc123",
  "type": "company",
  "name": "Acme Holdings Ltd",
  "status": "active",
  "created_at": "2026-02-16T10:00:00Z",
  "related_entities": [
    { "token": "ent_dir456", "name": "Jane Smith", "role": "Director" },
    { "token": "ent_ubo789", "name": "John Doe", "role": "UBO" }
  ]
}
2

Create an onboarding case

Open an onboarding case linked to the entity. Zenoo automatically creates verification requirements and begins executing API-based checks.
curl -X POST https://api.zenoo.com/v1/cases \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "Onboarding",
    "entity_token": "ent_abc123",
    "priority": "Medium",
    "external_reference": "YOUR-REF-2026-0042"
  }'
response = requests.post(
    "https://api.zenoo.com/v1/cases",
    headers={
        "Authorization": "Bearer your-api-key",
        "Content-Type": "application/json",
    },
    json={
        "type": "Onboarding",
        "entity_token": "ent_abc123",
        "priority": "Medium",
        "external_reference": "YOUR-REF-2026-0042",
    },
)
case = response.json()
print(case["token"])  # cas_xyz789
const caseRes = await fetch("https://api.zenoo.com/v1/cases", {
  method: "POST",
  headers: {
    Authorization: "Bearer your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    type: "Onboarding",
    entity_token: "ent_abc123",
    priority: "Medium",
    external_reference: "YOUR-REF-2026-0042",
  }),
});
const caseData = await caseRes.json();
console.log(caseData.token); // cas_xyz789
Response:
{
  "token": "cas_xyz789",
  "type": "Onboarding",
  "status": "New",
  "priority": "Medium",
  "entity_token": "ent_abc123",
  "due_date": "2026-03-02T10:00:00Z",
  "created_at": "2026-02-16T10:01:00Z"
}
The due_date is automatically calculated from SLA configuration based on case type and priority. An Onboarding/Medium case defaults to 14 calendar days.
3

List checks created for the case

Zenoo auto-creates checks based on entity type and role. List them to track progress.
curl -X GET "https://api.zenoo.com/v1/cases/cas_xyz789/checks" \
  -H "Authorization: Bearer your-api-key"
response = requests.get(
    "https://api.zenoo.com/v1/cases/cas_xyz789/checks",
    headers={"Authorization": "Bearer your-api-key"},
)
checks = response.json()
for check in checks["data"]:
    print(f"{check['type']} - {check['status']}")
const checksRes = await fetch(
  "https://api.zenoo.com/v1/cases/cas_xyz789/checks",
  { headers: { Authorization: "Bearer your-api-key" } }
);
const checks = await checksRes.json();
checks.data.forEach((c) => console.log(`${c.type} - ${c.status}`));
Response:
{
  "data": [
    { "token": "chk_001", "type": "PEP Screening", "category": "Screening", "entity": "Acme Holdings Ltd", "status": "In Progress" },
    { "token": "chk_002", "type": "Sanctions Screening", "category": "Screening", "entity": "Acme Holdings Ltd", "status": "In Progress" },
    { "token": "chk_003", "type": "Company Registry", "category": "Company", "entity": "Acme Holdings Ltd", "status": "Queued" },
    { "token": "chk_004", "type": "PEP Screening", "category": "Screening", "entity": "Jane Smith", "status": "Queued" },
    { "token": "chk_005", "type": "PEP Screening", "category": "Screening", "entity": "John Doe", "status": "Queued" },
    { "token": "chk_006", "type": "Identity Verification", "category": "Identity", "entity": "John Doe", "status": "Pending" }
  ],
  "meta": { "total": 6 }
}
4

Wait for checks to complete

Checks execute asynchronously. Use webhooks (recommended) or poll the case status.Option A: WebhookConfigure a webhook endpoint to receive check.completed and check.failed events. See Webhook Events.Option B: Poll
curl -X GET "https://api.zenoo.com/v1/cases/cas_xyz789" \
  -H "Authorization: Bearer your-api-key"
import time

while True:
    response = requests.get(
        "https://api.zenoo.com/v1/cases/cas_xyz789",
        headers={"Authorization": "Bearer your-api-key"},
    )
    case = response.json()
    if case["checks_summary"]["pending"] == 0:
        break
    time.sleep(10)
async function waitForChecks(caseToken) {
  while (true) {
    const res = await fetch(
      `https://api.zenoo.com/v1/cases/${caseToken}`,
      { headers: { Authorization: "Bearer your-api-key" } }
    );
    const data = await res.json();
    if (data.checks_summary.pending === 0) return data;
    await new Promise((r) => setTimeout(r, 10000));
  }
}
5

Review alerts generated

After checks complete, any screening hits generate alerts that require analyst review.
curl -X GET "https://api.zenoo.com/v1/cases/cas_xyz789/alerts" \
  -H "Authorization: Bearer your-api-key"
response = requests.get(
    "https://api.zenoo.com/v1/cases/cas_xyz789/alerts",
    headers={"Authorization": "Bearer your-api-key"},
)
alerts = response.json()
for alert in alerts["data"]:
    print(f"{alert['category']} - {alert['status']} (score: {alert['priority_score']})")
const alertsRes = await fetch(
  "https://api.zenoo.com/v1/cases/cas_xyz789/alerts",
  { headers: { Authorization: "Bearer your-api-key" } }
);
const alerts = await alertsRes.json();
alerts.data.forEach((a) =>
  console.log(`${a.category} - ${a.status} (score: ${a.priority_score})`)
);
Response:
{
  "data": [
    {
      "token": "alt_alert01",
      "type": "Screening",
      "category": "PEP Match",
      "title": "PEP Match: John Doe",
      "status": "Open",
      "priority": "High",
      "priority_score": 78,
      "match_score": 92,
      "entity_name": "John Doe",
      "sla_due_date": "2026-02-18T10:00:00Z"
    }
  ],
  "meta": { "total": 1 }
}
6

Resolve each alert

Review the alert details and resolve it with an action and justification.
curl -X POST https://api.zenoo.com/v1/alerts/alt_alert01/resolve \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "Approve",
    "notes": "PEP match confirmed as former local councillor (2010-2014). Low risk position, no current exposure. EDD not required."
  }'
response = requests.post(
    "https://api.zenoo.com/v1/alerts/alt_alert01/resolve",
    headers={
        "Authorization": "Bearer your-api-key",
        "Content-Type": "application/json",
    },
    json={
        "action": "Approve",
        "notes": "PEP match confirmed as former local councillor (2010-2014). Low risk position, no current exposure. EDD not required.",
    },
)
print(response.json()["status"])  # Resolved
const resolveRes = await fetch(
  "https://api.zenoo.com/v1/alerts/alt_alert01/resolve",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer your-api-key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      action: "Approve",
      notes:
        "PEP match confirmed as former local councillor (2010-2014). Low risk position, no current exposure. EDD not required.",
    }),
  }
);
const resolved = await resolveRes.json();
console.log(resolved.status); // Resolved
Response:
{
  "token": "alt_alert01",
  "status": "Resolved",
  "resolution_action": "Approve",
  "resolved_at": "2026-02-16T11:30:00Z"
}
A case cannot be closed while it has open alerts. Resolve or escalate every alert before closing.
7

Close the case

Once all alerts are resolved, close the case with a summary.
curl -X POST https://api.zenoo.com/v1/cases/cas_xyz789/close \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "resolution_notes": "Company verified. Registry check passed. One PEP match on UBO (former local councillor) reviewed and approved. Risk tier: Medium."
  }'
response = requests.post(
    "https://api.zenoo.com/v1/cases/cas_xyz789/close",
    headers={
        "Authorization": "Bearer your-api-key",
        "Content-Type": "application/json",
    },
    json={
        "resolution_notes": "Company verified. Registry check passed. One PEP match on UBO (former local councillor) reviewed and approved. Risk tier: Medium.",
    },
)
print(response.json()["status"])  # Closed
const closeRes = await fetch(
  "https://api.zenoo.com/v1/cases/cas_xyz789/close",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer your-api-key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      resolution_notes:
        "Company verified. Registry check passed. One PEP match on UBO (former local councillor) reviewed and approved. Risk tier: Medium.",
    }),
  }
);
const closed = await closeRes.json();
console.log(closed.status); // Closed
Response:
{
  "token": "cas_xyz789",
  "status": "Closed",
  "risk_tier": "Medium",
  "risk_score": 45,
  "completed_at": "2026-02-16T11:35:00Z",
  "checks_summary": { "total": 6, "passed": 5, "referred": 1, "failed": 0 }
}

Next steps