快速入門
本快速入門指南會在約十分鐘內,帶您在免費沙盒環境中從零開始完成一次公司驗證案例。您將申請存取權限、取得權杖(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:涵蓋每個端點、參數及回應。
