A claim (clm_...) is a typed data point on a person. Each has a claim_type, a status, and the fields defined for that type, validated against a strict schema. Applications validate against claims.
Lifecycle
Every claim row carries a status plus two retirement timestamps — archived_at (pending-only) and superseded_at (verified-only) — plus a convenience lifecycle discriminator derived from them.
status
| Value | Description |
|---|
pending | Submitted, not yet confirmed by compliance. |
verified | Confirmed by compliance. verified_at is set. |
Retirement timestamps
| Field | Set on | Meaning |
|---|
archived_at | pending rows only | Stamped when a subsequent POST /persons/{id}/claims for the same (person, claim_type) replaces this pending row. |
superseded_at | verified rows only | Stamped when compliance approves a newer pending and displaces this verified row as the authoritative value. |
At most one row per (person, claim_type) is “current” for each status — the current pending (status=pending AND archived_at IS NULL) and the current verified (status=verified AND superseded_at IS NULL).
lifecycle
lifecycle is a convenience discriminator that tells you, in one field, where a claim sits.
| Value | Meaning |
|---|
active | The most recent verified claim for its type — the currently authoritative value. |
in_flight | A pending claim waiting for compliance to verify it. |
historical | A claim (pending or verified) that’s been replaced by a newer one. Kept for audit. |
State transitions
| From | To | Trigger |
|---|
| (none) | pending | POST /persons or POST /persons/{person_id}/claims. The new row is in_flight. If a current pending for the same claim_type already exists, its archived_at is stamped in the same transaction and it becomes historical. Verified rows are not touched. |
pending | verified | Compliance review. If a prior active verified of the same type exists, its superseded_at is stamped in the same step and it becomes historical. Not self-service. |
A person can have more than one claim of the same claim_type. The current value is the row whose lifecycle is active. Submitting a new claim of the same type archives the current pending (if any) atomically and inserts a fresh in_flight pending. That new row takes over as active once compliance verifies it — which also stamps superseded_at on the prior active row.
Updating a claim value
Post a new claim of the same type. Any current pending for that type is archived atomically (its archived_at is stamped; its status stays pending and it remains retrievable). The new row starts as pending with lifecycle: in_flight, and becomes the current active value once compliance verifies it.
curl -X POST https://api.engine.usesophic.com/persons/per_m4k7r9s2/claims \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"claim_type": "residence",
"line1": "42 New Street",
"postal_code": "EC2A 4RQ",
"city": "London",
"country_code": "GB"
}'
Creating a claim
POST /persons/{person_id}/claims with the claim as the body. claim_type tells us which claim you’re sending.
import requests
response = requests.post(
"https://api.engine.usesophic.com/persons/per_m4k7r9s2/claims",
headers={
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json",
},
json={
"claim_type": "pep_status",
"is_pep": False,
"has_pep_association": False,
},
)
claim = response.json()
The response is the full claim:
{
"id": "clm_abc123",
"person": "per_m4k7r9s2",
"created_at": "2026-04-18T09:30:00Z",
"status": "pending",
"lifecycle": "in_flight",
"verified_at": null,
"superseded_at": null,
"archived_at": null,
"claim_type": "pep_status",
"is_pep": false,
"has_pep_association": false,
"pep_role": null,
"pep_role_start_date": null,
"pep_role_end_date": null,
"pep_associate_name": null,
"pep_associate_relationship": null
}
| Field | Description |
|---|
id | The claim’s unique ID, prefix clm_. |
person | ID of the person this claim belongs to. |
created_at | ISO-8601 timestamp of when the claim was submitted. |
status | pending or verified. See lifecycle. |
lifecycle | active, in_flight, or historical. Derived per row — tells you whether this is the current value, the current pending update, or history. See lifecycle. |
verified_at | ISO-8601 timestamp of verification, or null if still pending. |
superseded_at | ISO-8601 timestamp stamped by compliance when a newer verified claim of the same type displaces this verified row. null while this is the current active verified. Only ever set on verified rows. |
archived_at | ISO-8601 timestamp stamped when a subsequent POST /persons/{id}/claims for the same claim_type replaces this pending row. null while this is the current in_flight pending. Only ever set on pending rows. |
claim_type | The claim’s type. Determines which other fields are present. |
| other fields | Depend on claim_type (e.g. is_pep, pep_role, …). See claim type reference. |
Listing and retrieving claims
List a person’s claims, optionally filtered by type or status. By default the endpoint returns every row for the person — current and historical — newest-first by created_at (with id as a tiebreaker). This gives you an audit-ready view without a second request. Pass ?include_history=false to collapse to at most two rows per claim_type: the current active verified (if any) and the current in_flight pending (if any).
Breaking change. include_history previously defaulted to false (bare GET returned only current rows). It now defaults to true (bare GET returns full history). If you were relying on the old behavior, pass ?include_history=false explicitly.
curl "https://api.engine.usesophic.com/persons/per_m4k7r9s2/claims?claim_type=residence" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
| Query parameter | Values | Notes |
|---|
claim_type | Any claim_type | Optional. |
status | pending, verified | Optional. status=pending on the default view returns every pending (current + archived); status=verified returns every verified (current + superseded). Combine with include_history=false to get just the current pending or current verified per type. |
include_history | true, false | Optional, default true. Set to false to collapse to the current rows only (active + in_flight). |
Retrieve a specific claim by ID via GET /persons/{person_id}/claims/{claim_id}. This always returns the exact claim you asked for — including archived pendings and superseded verifieds — with lifecycle on the response.
Claim type reference
Unknown fields are rejected. Dates are ISO-8601, country codes ISO-3166-1 alpha-2.
Most claim types are specific to natural or legal persons; contact_details is valid on both. Creating a claim whose claim_type isn’t valid for the target’s person_type returns 400 invalid_request (e.g. Claim type 'relationships' is not allowed on natural persons.). See claim creation errors.
Natural-person claims
Acceptable when person_type is natural.
identity
| Field | Type | Required | Notes |
|---|
first_name | string | yes | |
last_name | string | yes | |
date_of_birth | date | yes | ISO-8601. |
nationalities
| Field | Type | Required | Notes |
|---|
nationalities | array of objects | yes | Non-empty. |
Each nationalities entry:
| Field | Type | Required | Notes |
|---|
country_code | string | yes | ISO-3166-1 alpha-2. |
basis | enum | null | no | One of birth, naturalisation, descent, marriage, investment_programme, other. |
residence
| Field | Type | Required | Notes |
|---|
line1 | string | yes | |
line2 | string | null | no | |
line3 | string | null | no | |
district_county | string | null | no | |
postal_code | string | yes | |
city | string | yes | |
country_code | string | yes | ISO-3166-1 alpha-2. |
tax_residencies
| Field | Type | Required | Notes |
|---|
tax_residencies | array of objects | yes | Non-empty. |
Each tax_residencies entry:
| Field | Type | Required | Notes |
|---|
country_code | string | yes | ISO-3166-1 alpha-2. |
tin | string | null | no | Tax identification number. Free-form string; we don’t validate format at the claim layer. |
tin_exemption_reason | enum | null | no | One of not_issued, pending_application, not_required. |
Supply a tin or tin_exemption_reason for each tax residency. The claim layer accepts either, but an onboarding application is expected to carry a tin where available.
fatca_status
| Field | Type | Required |
|---|
is_us_person | boolean | yes |
pep_status
| Field | Type | Required | Notes |
|---|
is_pep | boolean | yes | |
pep_role | string | null | conditional | Required when is_pep is true. |
pep_role_start_date | date | null | conditional | Required when is_pep is true. |
pep_role_end_date | date | null | no | |
has_pep_association | boolean | yes | |
pep_associate_name | string | null | conditional | Required when has_pep_association is true. |
pep_associate_relationship | string | null | conditional | Required when has_pep_association is true. |
education_level
| Field | Type | Required | Values |
|---|
education_level | enum | yes | none, secondary, bachelors, masters, doctorate, professional |
employment
| Field | Type | Required | Notes |
|---|
employment_status | enum | yes | employed, self_employed, retired, student, unemployed. |
industry | enum | null | conditional | Required when employment_status is employed or self_employed. See industry values. |
industry_other | string | null | conditional | Required when industry is other. |
financial_profile
| Field | Type | Required | Notes |
|---|
annual_income_eur | enum | yes | See EUR amount bands. |
income_sources | array of enum | yes | Non-empty. Values: salary, business_income, investments, pension, inheritance, other. |
net_worth_eur | enum | yes | Same bands as annual_income_eur. |
wealth_sources | array of enum | yes | Non-empty. Values: savings, business_sale, investments, inheritance, property_sale, gift, other. |
investment_experience
| Field | Type | Required | Notes |
|---|
has_prior_experience | boolean | yes | |
asset_classes | array of enum | conditional | Non-empty when has_prior_experience is true. Values: equities, bonds, funds, derivatives, crypto, other. |
expected_activity
| Field | Type | Required | Notes |
|---|
funding_currency | string | yes | ISO-4217 code (EUR, USD, GBP…). |
asset_classes | array of string | yes | The asset classes the customer expects to trade. |
annual_transactions | string | yes | Band value: 1_10, 11_20, 21_50, gt_50. |
investment_amount | string | yes | See EUR amount bands. |
Shared claim types
Acceptable on both natural and legal persons.
How to reach the person. Required on every POST /persons.
| Field | Type | Required |
|---|
phone_number | string | yes |
email | string | null | no |
Legal-person claims
Acceptable when person_type is legal.
registration
| Field | Type | Required | Notes |
|---|
legal_name | string | yes | |
trading_name | string | null | no | |
registration_number | string | yes | |
date_of_incorporation | date | yes | |
country_of_incorporation | string | yes | ISO-3166-1 alpha-2. |
entity_type | enum | yes | private_limited_company, public_limited_company, partnership, llp, sole_proprietorship, trust, foundation, nonprofit, other. |
lei
| Field | Type | Required | Notes |
|---|
identifier | string | yes | 20 alphanumeric characters. We normalise it to uppercase. |
expiry_date | date | yes | |
registered_address
The legal registration address.
| Field | Type | Required | Notes |
|---|
line1 | string | yes | |
line2 | string | null | no | |
line3 | string | null | no | |
district_county | string | null | no | |
postal_code | string | yes | |
city | string | yes | |
country_code | string | yes | ISO-3166-1 alpha-2. |
operating_address_is_same | boolean | no | Defaults to false. Set true if the entity operates from its registered address — in that case the operating_address claim and proof_of_operating_address evidence aren’t required on an application. |
operating_address
Where the business trades from. Same shape as residence. Send this claim only when the legal owner’s registered_address has operating_address_is_same set to false (the default). See conditional requirements.
business_nature
| Field | Type | Required | Notes |
|---|
business_activity | enum | yes | See industry values. |
business_activity_other | string | null | conditional | Required when business_activity is other. |
annual_turnover_eur | enum | yes | See EUR amount bands. |
is_regulated | boolean | yes | |
license_number | string | null | no | |
issues_bearer_shares | boolean | yes | |
has_nominee_shareholders | boolean | yes | When true, an onboarding application for this entity also needs a nominee_agreement evidence file attached to the legal owner. See conditional requirements. |
has_shell_bank_relationships | boolean | yes | |
relationships
Legal-person-only. Declares directors, shareholders, UBOs, trustees, settlors, and authorised signatories.
| Field | Type | Required | Notes |
|---|
relationships | array | yes | Non-empty. See entry fields below. |
Each relationship entry:
| Field | Type | Required | Notes |
|---|
related_person | string | yes | ID of an existing person. Unknown IDs fail the request with 400. |
relationship_type | enum | yes | director, shareholder, beneficial_owner, trustee, settlor, authorised_signatory. |
control_type | enum | null | no | ownership, voting, other. |
ownership_percentage | decimal (string) | null | no | E.g. "25.50". |
appointment_date | date | null | no | |
end_date | date | null | no | |
Different relationship_type values carry different onboarding requirements. director and authorised_signatory also need a board_resolution evidence file authorising them to act on the entity; the others don’t. See related-person requirements.
Reference values
EUR amount bands
| Value | Range |
|---|
lt_50k | Under €50,000 |
50k_100k | €50,000 – €100,000 |
100k_250k | €100,000 – €250,000 |
250k_500k | €250,000 – €500,000 |
500k_1m | €500,000 – €1,000,000 |
1m_3m | €1,000,000 – €3,000,000 |
gt_3m | Over €3,000,000 |
Industry values
agriculture, mining, manufacturing, utilities, construction, wholesale_retail, transport_logistics, hospitality, media_telecoms, technology, financial_services, insurance, real_estate, professional_services, education, healthcare, arts_entertainment, public_administration, defence, non_profit, gambling, extractives, precious_metals, cryptocurrency, other.
Pair other with the _other text field on the same claim (employment.industry_other, business_nature.business_activity_other).