快速入门
本快速入门指南会在约十分钟内,带您在免费沙盒环境中从零开始完成一次公司验证案例。您将申请存取权限、取得权杖(token)、建立公司案例、轮询直至完成,并读取包含股权结构在内的验证结果。
有关每个步骤背后的概念,请参阅指南。如需完整的端点参考,请参阅API Reference。
开始之前
您需要沙盒凭证:一组client_id与一组client_secret。如果您尚未拥有,请申请存取权限。您需签署沙盒测试协议,并会在画面上及透过电邮收到凭证。
沙盒基础网址为https://api.knowyourcustomer.dev。本快速入门指南中的所有内容均为免费,并使用合成资料及公开登记资料。
步骤一:取得权杖
验证采用 OAuth2 client-credentials 方式。请以您的client_id及client_secret换取具有范围PublicApi的持有人权杖(bearer token)。此权杖有效期约十分钟;请在每次请求中以Authorization: Bearer <token>。
# Exchange client credentials for a bearer token (~10 min TTL)
TOKEN=$(curl -fsS -X POST "$BASE_URL/connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "scope=PublicApi" | jq -r '.access_token')
# Send it on every request:
# -H "Authorization: Bearer $TOKEN"import requests
BASE_URL = "https://api.knowyourcustomer.dev" # free Sandbox
resp = requests.post(
f"{BASE_URL}/connect/token",
data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"scope": "PublicApi",
},
timeout=30,
)
resp.raise_for_status()
token = resp.json()["access_token"] # ~10 min TTL
headers = {"Authorization": f"Bearer {token}"}const BASE_URL = "https://api.knowyourcustomer.dev"; // free Sandbox
const body = new URLSearchParams({
grant_type: "client_credentials",
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
scope: "PublicApi",
});
const res = await fetch(`${BASE_URL}/connect/token`, { method: "POST", body });
if (!res.ok) throw new Error(`token failed: ${res.status}`);
const { access_token } = await res.json(); // ~10 min TTL
const headers = { Authorization: `Bearer ${access_token}` };成功的回应会包含一个access_token。请保留此项以供后续呼叫使用。
步骤二:搜寻公司
找出准确的登记记录,以便据此建立案例。可依名称或注册编号搜寻,并可选择性地按国家缩小范围。
可尝试CROPWELL BISHOP CREAMERY LIMITED,这是一个良好的多层股权结构范例:搜寻cropwell bishop于GB。您亦可尝试SC ENGINEERING PRIVATE LIMITED(新加坡,UEN200815219G)或Ubizense Limited(香港,商业登记号码69293323)。
POST /v2/Companies/search
# Search the registry; pick the exact result.
curl -fsS -X POST "$BASE_URL/v2/Companies/search" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"codeiso31662":"GB","query":"CROPWELL BISHOP"}' \
| jq '.companySearch.searchResults[0]'
# -> note the exact .rawname and the registration number (00364890)r = requests.post(
f"{BASE_URL}/v2/Companies/search",
headers=headers,
json={"codeiso31662": "GB", "query": "CROPWELL BISHOP"},
timeout=30,
)
r.raise_for_status()
results = r.json()["companySearch"]["searchResults"]
rawname = results[0]["rawname"] # exact name to create the case withconst search = await fetch(`${BASE_URL}/v2/Companies/search`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ codeiso31662: "GB", query: "CROPWELL BISHOP" }),
}).then((r) => r.json());
const rawname: string = search.companySearch.searchResults[0].rawname;
// exact name to create the case with选取您的结果,并记下其准确名称及注册编号(00364890,即 Cropwell Bishop 的资料)。
步骤三:建立案例
使用与搜寻结果相符的名称建立公司案例。请提供国家及注册编号,以便准确比对登记记录。
POST /v2/Companies,并带有rawname、codeiso31662及externalCode。
# Create the company case using the exact rawname from search.
CASE_ID=$(curl -fsS -X POST "$BASE_URL/v2/Companies" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"rawname\":\"$RAWNAME\",\"codeiso31662\":\"GB\",\"externalCode\":\"00364890\"}" \
| jq -r '.caseDetail.details.common.caseCommonId')
echo "caseCommonId: $CASE_ID" # the case now builds in the backgroundr = requests.post(
f"{BASE_URL}/v2/Companies",
headers=headers,
json={"rawname": rawname, "codeiso31662": "GB", "externalCode": "00364890"},
timeout=30,
)
r.raise_for_status()
case_id = r.json()["caseDetail"]["details"]["common"]["caseCommonId"]
print("caseCommonId:", case_id) # the case now builds in the backgroundconst created = await fetch(`${BASE_URL}/v2/Companies`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ rawname, codeiso31662: "GB", externalCode: "00364890" }),
}).then((r) => r.json());
const caseId = created.caseDetail.details.common.caseCommonId;
console.log("caseCommonId:", caseId); // the case now builds in the background回应会返回一个caseCommonId。案例现正于背景中建立。
步骤四:轮询直至完成
建立过程为非同步。请轮询该案例并读取其status,直至其状态为3(就绪)。请每隔数秒轮询一次,并采用递增等待间隔;部分司法管辖区可能需时数分钟。
GET /v2/Companies/{caseCommonId}
# Poll until status is 3 (Ready). Some jurisdictions take minutes.
for i in $(seq 1 60); do
STATUS=$(curl -fsS "$BASE_URL/v2/Companies/$CASE_ID" \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.caseDetail.details.common.statusId')
echo "statusId=$STATUS"
if [ "$STATUS" = "3" ]; then break; fi
sleep 5
doneimport time
for _ in range(60):
r = requests.get(f"{BASE_URL}/v2/Companies/{case_id}", headers=headers, timeout=30)
r.raise_for_status()
status = r.json()["caseDetail"]["details"]["common"]["statusId"]
print("statusId=", status)
if status == 3: # Ready
break
time.sleep(5) # poll with a backoff; do not tight-loopconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
for (let i = 0; i < 60; i++) {
const c = await fetch(`${BASE_URL}/v2/Companies/${caseId}`, { headers })
.then((r) => r.json());
const status = c.caseDetail.details.common.statusId;
console.log("statusId=", status);
if (status === 3) break; // Ready
await sleep(5000); // poll with a backoff; do not tight-loop
}只要状态并非3,即应持续轮询。状态会依序经过0 -> 50 -> 51 ->,实际经过的子集因案例而异,涵盖{53, 54, 9, 100, 107} -> 3。
步骤五:读取验证结果
一旦状态为3,即可读取该案例。您将取得已验证的公司属性(名称、注册编号、司法管辖区)以及股权资料:controllingEntitiesAndIndividuals以及递回式组织架构图(shareholders,按memberType)。
# Read members + the recursive org-chart (the ownership tree).
curl -fsS "$BASE_URL/v2/Companies/$CASE_ID/members" \
-H "Authorization: Bearer $TOKEN" \
| jq '{controlling: (.controllingEntitiesAndIndividuals | length),
shareholders: (.shareholdersAndBeneficialOwners | length)}'
curl -fsS "$BASE_URL/v2/Companies/$CASE_ID/org-chart" \
-H "Authorization: Bearer $TOKEN" \
| jq '{root: .name, shareholders: [.shareholders[]?.name]}'
# Each individual member has its own caseCommonId, addressable at
# GET /v2/Individuals/{caseCommonId}members = requests.get(
f"{BASE_URL}/v2/Companies/{case_id}/members", headers=headers, timeout=30).json()
controlling = members.get("controllingEntitiesAndIndividuals", [])
org = requests.get(
f"{BASE_URL}/v2/Companies/{case_id}/org-chart", headers=headers, timeout=30).json()
def walk(node, depth=0):
print(" " * depth + f"- {node.get('name')} ({node.get('effectivePercentage')}%)")
for child in (node.get("shareholders") or []):
walk(child, depth + 1)
walk(org) # recurse the multi-level tree; memberType is "Company" or "Individual"const members = await fetch(`${BASE_URL}/v2/Companies/${caseId}/members`, { headers })
.then((r) => r.json());
const controlling = members.controllingEntitiesAndIndividuals ?? [];
const org = await fetch(`${BASE_URL}/v2/Companies/${caseId}/org-chart`, { headers })
.then((r) => r.json());
const walk = (node: any, depth = 0): void => {
console.log(`${" ".repeat(depth)}- ${node.name} (${node.effectivePercentage}%)`);
for (const child of node.shareholders ?? []) walk(child, depth + 1);
};
walk(org); // recurse the multi-level tree; memberType is "Company" or "Individual"以 Cropwell Bishop 为例,您会看到一个多层架构树:企业母公司位于个人拥有者之上。请走访shareholders阵列以建立完整结构,并读取各个个人成员的caseCommonId,以便在/v2/Individuals/{caseCommonId}。
后续步骤
- 端对端公司验证:深入的完整流程说明。
- 实益拥有权与个人:走访组织架构图、处理门槛设定、验证个人身分。
- 文件:收集并预先验证身分及登记文件。
- 反洗钱与持续监控:筛查、警示及覆核日期。
- API Reference:涵盖每个端点、参数及回应。
