Match
POST /sanctions/match screens a person or company against sanctions and PEP data and returns a score per candidate. Request, response, batch of 100, and errors.
POST /sanctions/matchmatch takes one subject — a person or a company with everything you know about it — and returns the records that could be the same subject, each with a score from 0 to 1 and a match flag.
This is the endpoint for automatic screening. Use search when a person reads a list.
Full field list: matchSanctions in the reference.
The request
Prop
Type
Company, Organization and LegalEntity read the same group of records, so a company found as an Organization is returned for all three.
An array in properties holds up to 20 values, and each value up to 300 characters.
The properties that count
Everything you send is kept, but only these keys change the score:
| Key | Example | Effect on the score |
|---|---|---|
name | ["Vladimir Puttin"] | The base of the score. Send every spelling you have. |
birthDate | ["1952-10-07"] | Same date, same year or a conflict. |
citizenship, country | ["ru"] | An overlap or a conflict. Use two-letter codes. |
gender | ["male"] | A conflict costs a little. |
idNumber, taxNumber, innCode, registrationNumber, leiCode, swiftBic, imoNumber | ["7323006644"] | An equal identifier makes the result a match. A conflicting one of the same kind pushes it down. |
Read Reading a score for the exact numbers.
Send every field you have
A name alone gives you long lists to review. A name with a birth date and a country gives a clean decision. An identifier gives near certainty. The fields you leave out are never held against the candidate: an absent field is not compared.
A worked example
The subject has a typo in the surname, and a birth date and a citizenship.
curl -s -X POST "https://api.linkinlegal.com/v1/sanctions/match" \
-H "Authorization: Bearer $LINKINLEGAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema": "Person",
"properties": {
"name": ["Vladimir Puttin"],
"birthDate": ["1952-10-07"],
"citizenship": ["ru"]
},
"threshold": 0.8,
"limit": 2
}'{
"results": [
{
"id": "Q7747",
"caption": "Vladimir Putin",
"schema": "Person",
"score": 1,
"match": true,
"features": {
"name": 0.9806,
"birthDate": 0.1,
"country": 0.05,
"identifier": null,
"gender": null
},
"datasets": ["eu_fsf", "us_ofac_sdn", "gb_fcdo_sanctions"],
"target": true,
"properties": {
"name": ["Vladimir Vladimirovich Putin"],
"birthDate": ["1952-10-07"],
"country": ["ru"]
}
},
{
"id": "usgsa-941a678fce498dfde69459519fccb211a970b95a",
"caption": "Vladimir Vladimirovich PUTIN",
"schema": "Person",
"score": 0.9652,
"match": true,
"features": {
"name": 0.9152,
"birthDate": null,
"country": 0.05,
"identifier": null,
"gender": null
},
"datasets": ["us_sam_exclusions"],
"target": true,
"properties": {
"name": ["Vladimir Vladimirovich PUTIN"],
"country": ["ru"]
}
}
]
}The typo cost almost nothing: the name alone scored 0.9806. The same birth date added 0.10 and the same country added 0.05, so the first result is at the maximum of 1. The second record carries no birth date, so features.birthDate is null and nothing was added or taken away.
The response
| Field | Type | What it is |
|---|---|---|
id | string | The id of the candidate record. |
caption | string | The display name of the candidate. |
schema | string | The kind of candidate. |
score | number | 0 to 1, four decimals. |
match | boolean | true when score is at or above your threshold. |
features | object | The parts the score is built from: name, birthDate, country, identifier, gender. A null means the field was not compared. |
datasets | array | The source lists of the candidate. |
target | boolean | Always true: only listed entities are candidates. |
properties | object | The properties of the candidate, so you can show the evidence to a reviewer. |
results is sorted by score, highest first, and it is cut at limit. It also holds candidates below your threshold, with match: false. That is deliberate: a reviewer wants to see the near misses. Read match, not the length of results.
An empty results array means nothing came near the subject.
Screen many subjects in one call
POST /sanctions/match/batchSend 1 to 100 subjects under queries. You choose the key of each item; it comes back on the answer.
curl -s -X POST "https://api.linkinlegal.com/v1/sanctions/match/batch" \
-H "Authorization: Bearer $LINKINLEGAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queries": {
"cust-1": {
"schema": "Person",
"properties": { "name": ["Marina Gulina"] },
"limit": 1
},
"cust-2": {
"schema": "Company",
"properties": {
"name": ["Wrong Name LLC"],
"innCode": ["7323006644"]
},
"limit": 1
}
}
}'{
"responses": {
"cust-1": {
"results": [
{
"id": "ru-inn-381205591080",
"caption": "МАРИНА КОНСТАНТИНОВНА ГУЛИНА",
"schema": "Person",
"score": 0.9333,
"match": true,
"features": {
"name": 0.9333,
"birthDate": null,
"country": null,
"identifier": null,
"gender": null
},
"datasets": ["ann_graph_topics", "ext_ru_egrul"],
"target": true,
"properties": { "name": ["МАРИНА КОНСТАНТИНОВНА ГУЛИНА"] }
}
]
},
"cust-2": {
"results": [
{
"id": "ru-inn-7323006644",
"caption": "АКЦИОНЕРНОЕ ОБЩЕСТВО \"СПЕКТР-АВИА\"",
"schema": "Company",
"score": 0.95,
"match": true,
"features": {
"name": 0,
"birthDate": null,
"country": null,
"identifier": 1,
"gender": null
},
"datasets": ["ann_graph_topics", "ext_ru_egrul"],
"target": true,
"properties": {
"name": ["АКЦИОНЕРНОЕ ОБЩЕСТВО \"СПЕКТР-АВИА\""],
"innCode": ["7323006644"]
}
}
]
}
}
}Two things to know:
- Every item follows the rules of
POST /sanctions/match, and every item can carry its ownthreshold,limit,includeanddatasets. - A batch call costs one request against your rate limit, whether it holds one subject or 100.
A bad item does not fail the batch
The call stays 200. The bad item gets an error object in place of its results:
{
"responses": {
"cust-1": { "results": [] },
"cust-3": {
"error": {
"code": "invalid_request",
"message": "Invalid request fields: properties."
}
}
}
}The item code is invalid_request (the item was wrong) or internal_error (the item failed on our side; send it again). Walk every key of responses and check for error first.
Errors
| Status | Code | Cause | What to do |
|---|---|---|---|
| 400 | invalid_request | schema is not one of the six values, properties.name is empty, threshold is out of 0–1, limit is out of 1–25, or a batch holds 0 or more than 100 items. | Fix the body. |
| 400 | unknown_parameter | A field name that does not exist in the body. | Check it against the reference. |
| 503 | index_unavailable | The match index is not ready. | Retry in a few minutes. |
When match is not available
match needs its name index. While that index is rebuilt or not yet ready, the endpoint answers 503 index_unavailable and the message asks you to try again in a few minutes.
For a batch, this is the one error that fails the whole call, and not each of the 100 items. Retry the whole batch.
search and the entity endpoints do not use this index and keep working.
Practical advice
- One subject per call, or a batch. Do not loop 100 single calls: one batch is one request against your limit, and it is faster.
- Use one stable key per subject in a batch (your customer id). Then you can write the answers straight back to your records.
- Send every spelling of a name you hold, in
properties.name. The best one counts; extra names never lower the score. - Store the
idand thescoreof every hit with your decision. When you rescreen, you can then show what changed. - Keep the default
thresholdof 0.8 until you have measured on your own data. Read Thresholds.
Last updated on
Search
GET /sanctions/search finds records by text in the caption. Every parameter, the filters, sorting, paging, and what the contains match means for you.
Reading a score
How the LinkinLegal match score is built from the name, the birth date, the country, the gender and the identifiers, with measured examples.