Getting Started
The Watchtower API lets your own software do what your staff do on the site. It can add and change parties, screen them, read the results and download certificates and reports.
The API comes with the Firm and Institution plans.
An administrator at your firm makes a key on the Account page. We show the key once, so copy it then. Your firm may hold five keys at a time, and an administrator can cancel a key at any moment.
Send the key with every call, in the Authorization header. Every call is made over HTTPS and answers in JSON.
curl https://watchtowerkyc.com/api/v1/usage \ -H "Authorization: Bearer wt_test_your_key"
Test Keys
A test key works on invented names. Use one to build and prove your integration before you send a client's name.
A test key answers from a book of five invented parties, one for each answer the service gives. Their identifiers begin test_pty_ and their references run from TEST-0001 to TEST-0005.
A party you add with a test key is checked and screened against an invented list and returned to you. We do not keep it, so you cannot fetch it afterwards.
Viktor Samplov Testovich, born 1961-04-02, returns a match. Viktor Samplov with no date of birth returns a review. Maria Example Fernandez, born in 1970, returns an office-holder match. Any other name returns clear.
Certificates and reports asked for with a test key are the samples from our website, marked SAMPLE on every page. Every answer to a test key carries test: true.
Parties
A party is a person or an entity you screen. The fields and the checks are those of the Add a Party form.
Lists come 200 to a page. When next_cursor is not null, send it back as cursor to get the next page. You may ask for a smaller page with limit.
The limit on parties in your plan applies to the API as it does to the site.
| Field | Meaning |
|---|---|
| kind | Person or Entity. Required. |
| name | The full name, of two words or more. Required. |
| former_names | A list of former names and aliases, ten at most. Each is screened as well. |
| date_of_birth | Written YYYY-MM-DD. Persons only. |
| nationality | Free text, 80 characters at most. |
| reference | Your own file or client reference, 80 characters at most. |
| role | The party's role or relationship, 120 characters at most. |
| POST /parties | Add one party. We screen it at once and return it with its result. |
| POST /parties/batch | Add up to 1,000 parties, sent as { "parties": [ ... ] }. We check every party first. If any has an error we add none and tell you which. |
| GET /parties | List your parties in the order they were added. Add ?reference= to find the parties filed under one of your references. |
| GET /parties/{id} | One party with its latest result. |
| PATCH /parties/{id} | Change a party. Send only the fields you are changing. A change to the name, date of birth or nationality screens the party again and reopens earlier decisions about it. |
| POST /parties/{id}/stop | Stop monitoring a party. We keep its history. |
| POST /parties/{id}/resume | Resume monitoring a party. |
curl https://watchtowerkyc.com/api/v1/parties \
-H "Authorization: Bearer wt_test_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7f1c2a9e-0001" \
-d '{"kind":"Person","name":"Jane Sample Doe","date_of_birth":"1985-03-14","reference":"C-1042"}'Screening
We screen a party when you add it and each time your schedule falls due. You can also screen on demand.
A run of your whole book answers when the run has finished. One run may be under way for your firm at a time.
| POST /parties/{id}/screen | Screen one party again now. |
| POST /screenings | Screen all your monitored parties now. |
| GET /screenings | Your runs, newest first, with the totals of each. |
| GET /screenings/{id} | One run: whether it has finished, its totals and the lists it ran against. |
| GET /screenings/{id}/results | The results of a run. Add ?flagged=true to keep only review and match. |
| GET /lists | The sanctions lists and rosters we screen against, with the date each was last updated. |
Results
A result gives the sanctions outcome and the office-holder outcome separately. Each is clear, review, match or not_completed.
Clear means we found no entry under that name. Review means a name matched and a person at your firm must decide. Match means the name and the year of birth both matched.
office_holders is null when no office-holder screen was made. That is the case for every entity.
Each match names the list, the name on the list, the list's own reference, whether the year of birth agrees and whether the match was reached through a difference in spelling.
Your compliance officer records the decision on a match on the site. The result then carries that decision, with the reviewer and the date.
| GET /results/{id} | One result in full. |
| GET /parties/{id}/results | Every result for one party, newest first. |
| GET /review | The results waiting for a decision. |
{
"id": "test_res_review",
"party_id": "test_pty_review",
"screening_id": "test_run_1",
"screened_at": "2026-01-01T12:00:00.000Z",
"screened": { "name": "Viktor Samplov", "kind": "Person", "date_of_birth": null },
"sanctions": {
"outcome": "review",
"matches": [
{
"list": "TEST-LIST",
"name": "Viktor Samplov Testovich",
"reference": "T-001",
"date_of_birth": "1961-04-02",
"birth_year_agrees": false,
"spelling_variant": false,
"ruled_out": false
}
]
},
"office_holders": { "outcome": "clear", "matches": [] },
"decision": null,
"test": true
}Certificates and Reports
These calls return a PDF. They are the documents the site produces, locked and digitally signed in the same way.
| GET /results/{id}/certificate | The Screening Certificate for one result. |
| GET /screenings/{id}/report | The Screening Report for one run. |
Your Plan
| GET /usage | Your plan, its limit on parties and the number you are monitoring. |
Sending a Call Twice
A network fault can leave you unsure whether a call arrived. When you add a party or a batch, send an Idempotency-Key header with a value of your own, such as a UUID.
If the same call arrives again within a day with the same key, we return the first answer and add nothing.
Pace
Your firm may make 600 calls a minute across all its keys. A call over that pace is refused with status 429, and the Retry-After header says how many seconds to wait.
Errors
A call that cannot be completed answers with an HTTP status of 400 or above and a body of this form: { "error": { "code": "...", "message": "..." } }. The code is fixed and your software can act on it. The message is for a person.
| Code | Status | Message |
|---|---|---|
| no_key | 401 | This call needs an API key. Send it in the Authorization header as a Bearer token. |
| bad_key | 401 | This API key is not valid. It may have been cancelled. |
| no_api_on_plan | 403 | The API comes with the Firm and Institution plans. |
| subscription_ended | 403 | This subscription has ended, and its API keys no longer work. Your records can be read and downloaded on the site until they are deleted. |
| too_many_calls | 429 | Too many calls. The limit is 600 a minute. Try again in a moment. |
| bad_json | 400 | The request body could not be read as JSON. |
| invalid | 422 | The request has errors. |
| batch_too_large | 422 | A batch holds at most 1,000 parties. |
| batch_empty | 422 | The batch holds no parties. |
| over_limit | 409 | The plan’s limit on parties has been reached. |
| key_reused | 409 | This Idempotency-Key was used for a different request. |
| party_not_found | 404 | That party does not exist. |
| result_not_found | 404 | That result does not exist. |
| screening_not_found | 404 | That screening does not exist. |
| not_monitored | 409 | This party is not being monitored. Resume monitoring to screen it. |
| nothing_to_screen | 409 | There are no monitored parties to screen. |
| screening_under_way | 409 | A screening is already under way. Try again in a few minutes. |
| lists_not_loaded | 503 | The sanctions lists are not loaded yet. Try again in a few minutes. |
| no_certificate | 404 | This result has no certificate, because the screening was not completed. |
| no_report | 404 | This screening has no report, because it has not finished. |
| bad_limit | 400 | The limit must be a number from 1 to 200. |
Changes
The address carries the version, v1. We may add calls and fields to v1. We will not rename or remove a field, or change what a call does, within v1.
Questions about the API go to support@watchtowerkyc.com, or to a ticket on the Support page.
