curl -X POST https://verification.didit.me/v3/kyb/shareholders/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"kyb_response_id": "69aeeb95febb0f1704042259",
"vendor_data": "company-1234"
}'import os, time, requests
search = requests.post(
"https://verification.didit.me/v3/kyb/search/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"]},
json={"country_code": "GB", "name": "Tesco"},
timeout=60,
).json()
kyb_response_id = search["kyb_registry"]["companies"][0]["kyb_response_id"]
resp = requests.post(
"https://verification.didit.me/v3/kyb/shareholders/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"]},
json={"kyb_response_id": kyb_response_id, "vendor_data": "company-1234"},
timeout=90,
)
resp.raise_for_status()
data = resp.json()
request_id = data["request_id"]
print("Keep this request ID:", request_id)
company = data["kyb_registry"]
if resp.status_code == 202 or company.get("fetch_status") == "pending":
# This client wait limit does not cancel the report or create a new purchase.
deadline = time.monotonic() + 300
while company.get("fetch_status") != "resolved" and time.monotonic() < deadline:
time.sleep(5)
decision = requests.get(
f"https://verification.didit.me/v3/session/{request_id}/decision/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"]},
timeout=30,
)
decision.raise_for_status()
checks = decision.json().get("registry_checks") or []
if checks:
company = checks[0].get("company") or company
if company.get("fetch_status") == "resolved":
print(company["company_name"], company["registry_tier_delivered"])
else:
print("Still processing; retrieve this request later:", request_id)const res = await fetch('https://verification.didit.me/v3/kyb/shareholders/', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
kyb_response_id: '69aeeb95febb0f1704042259',
vendor_data: 'company-1234',
}),
});
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
const requestId = data.request_id;
console.log('Keep this request ID:', requestId);
let company = data.kyb_registry;
if (res.status === 202 || company.fetch_status === 'pending') {
// This client wait limit does not cancel the report or create a new purchase.
const deadline = Date.now() + 300000;
while (company.fetch_status !== 'resolved' && Date.now() < deadline) {
await new Promise(resolve => setTimeout(resolve, 5000));
const decisionResponse = await fetch(
`https://verification.didit.me/v3/session/${requestId}/decision/`,
{ headers: { 'x-api-key': 'YOUR_API_KEY' }, signal: AbortSignal.timeout(30000) },
);
if (!decisionResponse.ok) throw new Error(`Retrieval failed: ${decisionResponse.status}`);
const decision = await decisionResponse.json();
company = decision.registry_checks?.[0]?.company ?? company;
}
}
if (company.fetch_status === 'resolved') {
console.log(company.company_name, company.registry_tier_delivered);
} else {
console.log('Still processing; retrieve this request later:', requestId);
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/kyb/shareholders/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'kyb_response_id' => '69aeeb95febb0f1704042259',
'vendor_data' => '<string>',
'metadata' => [
],
'save_api_request' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/kyb/shareholders/"
payload := strings.NewReader("{\n \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n \"vendor_data\": \"<string>\",\n \"metadata\": {},\n \"save_api_request\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/kyb/shareholders/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n \"vendor_data\": \"<string>\",\n \"metadata\": {},\n \"save_api_request\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/kyb/shareholders/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n \"vendor_data\": \"<string>\",\n \"metadata\": {},\n \"save_api_request\": true\n}"
response = http.request(request)
puts response.read_body{
"request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
"kyb_registry": {
"uuid": "f1e2d3c4-b5a6-4789-9c0d-1e2f3a4b5c6d",
"node_id": "feature_kyb_registry",
"status": "In Review",
"registry_status": "active",
"data_resolved": true,
"company_name": "Tesco PLC",
"registration_number": "00445790",
"country_code": "GB",
"region": "",
"company_type": "Public Limited Company",
"incorporation_date": "1947-11-27",
"registered_address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
"tax_number": "GB412 8925 93",
"risk_level": "low risk",
"verification_status": "verified",
"is_from_registry": true,
"fetch_status": "resolved",
"alternative_names": "TESCO STORES (HOLDINGS) PUBLIC LIMITED COMPANY",
"nature_of_business": null,
"registered_capital": null,
"registered_capital_amount": null,
"registered_capital_currency": null,
"website": "https://www.tesco.com/",
"email": "customer.service@tesco.co.uk",
"phone": "03301231688",
"legal_entity_identifier": null,
"location_of_registration": null,
"financial_summary": {
"currency": "Pound (£)",
"total_number_of_shares": "8174378721",
"meta_detail": {
"Class_Of_Share": "Ordinary"
}
},
"officers": [
{
"uuid": "a1b2c3d4-e5f6-4789-9a0b-1c2d3e4f5a6b",
"name": "CHRISTOPHER JON TAYLOR",
"designation": "Secretary",
"role": "secretary",
"nationality": null,
"is_active": true,
"kyc_status": null,
"kyc_session_url": null
},
{
"uuid": "b2c3d4e5-f6a7-4890-8b1c-2d3e4f5a6b7c",
"name": "MELISSA BETHELL",
"designation": "Director",
"role": "director",
"nationality": "British",
"is_active": true,
"kyc_status": null,
"kyc_session_url": null
}
],
"beneficial_owners": [],
"addresses": [
{
"address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
"type": "legal_entity_registry_address",
"description": "registered office address"
}
],
"industries": null,
"accounts": {
"last_account": "26 February 2025",
"next_account": "26 February 2026",
"due_by_date": "26 August 2026"
},
"registry_data": {
"name": "Tesco PLC",
"registration_number": "00445790",
"status": "active",
"type": "Public Limited Company",
"incorporation_date": "1947-11-27",
"tax_number": "GB412 8925 93",
"country_code": "GB",
"fetch_status": "resolved",
"industries_detail": [
{
"code": "47110",
"name": "Retail Sale In Non-specialised Stores With Food, Beverages Or Tobacco Predominating",
"description": null,
"meta_detail": []
}
]
},
"user_provided_data": null,
"confirmed_by_user_at": null,
"last_console_edit_at": null,
"is_editable": true
},
"vendor_data": "company-1234",
"metadata": null,
"created_at": "2026-06-11T10:45:00.000000+00:00"
}KYB Registry Shareholders
Retrieve the Lite profile plus the direct shareholders (natural persons and corporate entities, with their ownership bands) of one candidate returned by POST /v3/kyb/search/.
Pairing with search. Pass the candidate’s kyb_response_id exactly as returned by a search of the same application. The search runs on the Lite registry chain; when the country’s ownership data lives at another registry Didit re-finds the company there by registration number, at no extra cost.
Billing. Billed at the country’s Shareholders price - see KYB registry pricing. When the registry holds no shareholder record for the company (or the country offers no ownership data at all) the Lite profile is delivered and billed instead: read registry_tier_delivered and registry_ownership_status. The balance is checked against the Shareholders price before any registry call (403 when short).
Availability. v3 only. Every call creates a business session (its id is the request_id).
Pending reports. When a report is still being prepared, or the ownership section has not been retrieved from the registry yet, the endpoint returns 202 Accepted, kyb_registry.fetch_status=pending, kyb_registry.registry_ownership_status=pending, and registry_tier_delivered=null. Keep request_id and retrieve GET /v3/session//decision/ until registry_checks[0].company.fetch_status is resolved. Didit completes the report automatically and charges the delivered tier once it is ready. Do not repeat the purchase while it is pending; every new POST creates a separate request.
curl -X POST https://verification.didit.me/v3/kyb/shareholders/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"kyb_response_id": "69aeeb95febb0f1704042259",
"vendor_data": "company-1234"
}'import os, time, requests
search = requests.post(
"https://verification.didit.me/v3/kyb/search/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"]},
json={"country_code": "GB", "name": "Tesco"},
timeout=60,
).json()
kyb_response_id = search["kyb_registry"]["companies"][0]["kyb_response_id"]
resp = requests.post(
"https://verification.didit.me/v3/kyb/shareholders/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"]},
json={"kyb_response_id": kyb_response_id, "vendor_data": "company-1234"},
timeout=90,
)
resp.raise_for_status()
data = resp.json()
request_id = data["request_id"]
print("Keep this request ID:", request_id)
company = data["kyb_registry"]
if resp.status_code == 202 or company.get("fetch_status") == "pending":
# This client wait limit does not cancel the report or create a new purchase.
deadline = time.monotonic() + 300
while company.get("fetch_status") != "resolved" and time.monotonic() < deadline:
time.sleep(5)
decision = requests.get(
f"https://verification.didit.me/v3/session/{request_id}/decision/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"]},
timeout=30,
)
decision.raise_for_status()
checks = decision.json().get("registry_checks") or []
if checks:
company = checks[0].get("company") or company
if company.get("fetch_status") == "resolved":
print(company["company_name"], company["registry_tier_delivered"])
else:
print("Still processing; retrieve this request later:", request_id)const res = await fetch('https://verification.didit.me/v3/kyb/shareholders/', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
kyb_response_id: '69aeeb95febb0f1704042259',
vendor_data: 'company-1234',
}),
});
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
const requestId = data.request_id;
console.log('Keep this request ID:', requestId);
let company = data.kyb_registry;
if (res.status === 202 || company.fetch_status === 'pending') {
// This client wait limit does not cancel the report or create a new purchase.
const deadline = Date.now() + 300000;
while (company.fetch_status !== 'resolved' && Date.now() < deadline) {
await new Promise(resolve => setTimeout(resolve, 5000));
const decisionResponse = await fetch(
`https://verification.didit.me/v3/session/${requestId}/decision/`,
{ headers: { 'x-api-key': 'YOUR_API_KEY' }, signal: AbortSignal.timeout(30000) },
);
if (!decisionResponse.ok) throw new Error(`Retrieval failed: ${decisionResponse.status}`);
const decision = await decisionResponse.json();
company = decision.registry_checks?.[0]?.company ?? company;
}
}
if (company.fetch_status === 'resolved') {
console.log(company.company_name, company.registry_tier_delivered);
} else {
console.log('Still processing; retrieve this request later:', requestId);
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/kyb/shareholders/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'kyb_response_id' => '69aeeb95febb0f1704042259',
'vendor_data' => '<string>',
'metadata' => [
],
'save_api_request' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/kyb/shareholders/"
payload := strings.NewReader("{\n \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n \"vendor_data\": \"<string>\",\n \"metadata\": {},\n \"save_api_request\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/kyb/shareholders/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n \"vendor_data\": \"<string>\",\n \"metadata\": {},\n \"save_api_request\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/kyb/shareholders/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n \"vendor_data\": \"<string>\",\n \"metadata\": {},\n \"save_api_request\": true\n}"
response = http.request(request)
puts response.read_body{
"request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
"kyb_registry": {
"uuid": "f1e2d3c4-b5a6-4789-9c0d-1e2f3a4b5c6d",
"node_id": "feature_kyb_registry",
"status": "In Review",
"registry_status": "active",
"data_resolved": true,
"company_name": "Tesco PLC",
"registration_number": "00445790",
"country_code": "GB",
"region": "",
"company_type": "Public Limited Company",
"incorporation_date": "1947-11-27",
"registered_address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
"tax_number": "GB412 8925 93",
"risk_level": "low risk",
"verification_status": "verified",
"is_from_registry": true,
"fetch_status": "resolved",
"alternative_names": "TESCO STORES (HOLDINGS) PUBLIC LIMITED COMPANY",
"nature_of_business": null,
"registered_capital": null,
"registered_capital_amount": null,
"registered_capital_currency": null,
"website": "https://www.tesco.com/",
"email": "customer.service@tesco.co.uk",
"phone": "03301231688",
"legal_entity_identifier": null,
"location_of_registration": null,
"financial_summary": {
"currency": "Pound (£)",
"total_number_of_shares": "8174378721",
"meta_detail": {
"Class_Of_Share": "Ordinary"
}
},
"officers": [
{
"uuid": "a1b2c3d4-e5f6-4789-9a0b-1c2d3e4f5a6b",
"name": "CHRISTOPHER JON TAYLOR",
"designation": "Secretary",
"role": "secretary",
"nationality": null,
"is_active": true,
"kyc_status": null,
"kyc_session_url": null
},
{
"uuid": "b2c3d4e5-f6a7-4890-8b1c-2d3e4f5a6b7c",
"name": "MELISSA BETHELL",
"designation": "Director",
"role": "director",
"nationality": "British",
"is_active": true,
"kyc_status": null,
"kyc_session_url": null
}
],
"beneficial_owners": [],
"addresses": [
{
"address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
"type": "legal_entity_registry_address",
"description": "registered office address"
}
],
"industries": null,
"accounts": {
"last_account": "26 February 2025",
"next_account": "26 February 2026",
"due_by_date": "26 August 2026"
},
"registry_data": {
"name": "Tesco PLC",
"registration_number": "00445790",
"status": "active",
"type": "Public Limited Company",
"incorporation_date": "1947-11-27",
"tax_number": "GB412 8925 93",
"country_code": "GB",
"fetch_status": "resolved",
"industries_detail": [
{
"code": "47110",
"name": "Retail Sale In Non-specialised Stores With Food, Beverages Or Tobacco Predominating",
"description": null,
"meta_detail": []
}
]
},
"user_provided_data": null,
"confirmed_by_user_at": null,
"last_console_edit_at": null,
"is_editable": true
},
"vendor_data": "company-1234",
"metadata": null,
"created_at": "2026-06-11T10:45:00.000000+00:00"
}POST /v3/kyb/search/ returns candidate companies when you need the direct shareholders on top of the Lite profile.
It is billed at the country’s Shareholders price (per-country prices). Where the registry holds no shareholder record for the company, or the country offers no ownership data at all, the Lite profile is delivered and billed instead: registry_tier_delivered is basic and registry_ownership_status is unavailable.
When the report is still being prepared, or the ownership section has not been retrieved from the registry yet, the endpoint returns 202 Accepted, kyb_registry.fetch_status: "pending", kyb_registry.registry_ownership_status: "pending", and registry_tier_delivered: null.
Keep the returned request_id and retrieve GET /v3/session/{request_id}/decision/ until registry_checks[0].company.fetch_status is resolved.
Didit completes the pending report automatically and charges the delivered tier once it is ready.
Do not repeat the purchase request while it is pending: each new POST creates a separate request.
Available on v3 only. POST /v2/kyb/select/ and POST /v3/kyb/select/ keep their contract and price.Authorizations
Your application's API key, from Developers -> API keys in the Business Console. The primary key has full access. A named key can be scoped: none, read or write per resource, limited to some workflows or to approved sessions, to a list of IP addresses, and to an expiry date. 401 means the key is missing, wrong, revoked or expired; 403 means the key has no access to this resource or action, or the request came from an address outside its IP list; 404 on a session route means the session is outside the key's workflows or statuses. A key without media access receives image, video and PDF URLs as null, and a key without sessions write receives session links and tokens as null. See https://docs.didit.me/console/api-keys.
Body
Candidate handle from POST /v3/kyb/search/ (kyb_registry.companies[].kyb_response_id). Ephemeral — use it shortly after the search that produced it.
255"69aeeb95febb0f1704042259"
Your identifier for this company; echoed back and stored with the business session.
Free-form JSON stored with the business session and echoed back.
Must be true (the default). KYB registry selects are always persisted so billing and retrieval can be tracked; false returns 400.
Response
Company report returned and billed at the delivered tier. Ownership reports still being prepared can return 202; keep request_id to retrieve their saved decision.
Id of the business session created for this retrieval. The stored record (visible in the console) keeps updating if the registry resolves after the response.
The tier this endpoint sells: basic (Lite) for select, shareholders, ubo.
basic, shareholders, ubo The tier actually delivered and billed. Lower than requested when the country's registries hold no ownership data, or the registry has no ownership record for this company.
basic, shareholders, ubo, null Full registry company profile.
Show child attributes
Show child attributes
Echo of the vendor_data you sent.
Echo of the metadata you sent.