A KYB case is the container for one merchant’s verification. You create it
with an external_id (your identifier for the merchant) and receive a
public_id to embed in the widget flow. Optionally, you can pre-fill form
fields you already know so the merchant does not re-enter them.
Create a case
POST /api/v4/kyb/cases — authenticated with your API key. The backend creates
(or reuses) the business applicant bound to external_id and returns the
public_id.
export API_KEY=<YOUR_API_KEY>
curl -H "ds-api-token: $API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://api.dataspike.io/api/v4/kyb/cases" \
--data '{ "external_id": "merchant-123" }'
Response:{
"id": "0195c1f0-1234-7000-8000-0123456789ab",
"public_id": "KYB0123456789abcdef",
"applicant_id": "0195c1f0-1234-7000-8000-0123456789ab",
"external_id": "merchant-123",
"status": "draft"
}
import requests
API_KEY = "<YOUR_API_KEY>"
BASE = "https://api.dataspike.io"
HEADERS = {"ds-api-token": API_KEY, "Content-Type": "application/json"}
resp = requests.post(
f"{BASE}/api/v4/kyb/cases",
headers=HEADERS,
json={"external_id": "merchant-123"},
)
public_id = resp.json()["public_id"]
If the merchant already has an in-flight case (draft / action_required),
that existing case is returned with 200 instead of creating a new one — so
the call is safe to retry.
Pass an optional fields object to pre-populate the widget. It is grouped by
section, then by field key:
fields: { "<section>": { "<field_key>": <value> } }
Keys must match the catalog. Unknown sections or fields are ignored, so a typo
never fails the request — it is simply skipped.
The example below pre-fills one field from each section to show the shape:
curl -H "ds-api-token: $API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://api.dataspike.io/api/v4/kyb/cases" \
--data '{
"external_id": "merchant-123",
"fields": {
"business": { "legal_name": "Acme Holdings Inc." },
"registration": { "registration_number": "16-1782204" },
"address_contact": { "reg_address_country": "US" },
"representative": { "rep_full_name": "Joe Marrano" },
"volume_banking": { "annual_volume": "$1,000,000 - $5,000,000" }
}
}'
resp = requests.post(
f"{BASE}/api/v4/kyb/cases",
headers=HEADERS,
json={
"external_id": "merchant-123",
"fields": {
"business": {"legal_name": "Acme Holdings Inc."},
"registration": {"registration_number": "16-1782204"},
"address_contact": {"reg_address_country": "US"},
"representative": {"rep_full_name": "Joe Marrano"},
"volume_banking": {"annual_volume": "$1,000,000 - $5,000,000"},
},
},
)
fields accepts scalar values only (string, number, boolean) — one value
per field key. Fields are flat within a section; there is no nested object.
- Addresses are flat sub-fields, not a nested object — e.g.
reg_address_street, reg_address_city, reg_address_state,
reg_address_postal, reg_address_country.
- Beneficial owners and documents are not part of
fields — they are
managed through their own widget endpoints, not pre-fill.
Field keys by section
The pre-fillable field keys, grouped by section.
| Section | Field keys |
|---|
business | legal_name, dba, entity_type, form_type |
registration | registration_type, registration_type_other, registration_number, industry_type, mcc, incorporation_date, website |
address_contact | reg_address_street, reg_address_city, reg_address_state, reg_address_postal, reg_address_country, operating_same_as_reg, op_address_street, op_address_city, op_address_state, op_address_postal, op_address_country |
representative | rep_full_name, rep_dob, rep_job_title, rep_email, rep_mobile, rep_citizenship, rep_ssn, rep_address_street, rep_address_city, rep_address_state, rep_address_postal, rep_address_country |
volume_banking | annual_volume, avg_transaction_volume, highest_transaction_value, bank_name, account_number, routing_number |