Certaby API · for property software
Certaby’s checks, inside your own software
Your software sends the people and the property. Certaby screens them against the sanctions lists, checks ID and Right to Rent by link, finds who owns a company, adds the property risk pack, and signs one certificate for the job.
Get your free test keyRead the reference
Already use Certaby? Sign in and open Developers.
- Checks from 9p
- Paid per check from your Certaby credit. No contract and no monthly fee.
- A free test key
- 50 real checks, with nothing charged.
- One base address
- api.certaby.com
- One certificate a job
- Signed, with a public page anyone can check it on.
Who it’s for
Agency CRMs and letting software
Run the tenant, landlord, buyer and seller checks from the record your users already have open, and keep the certificate with the let or sale.
Proptech and portals
Check the people behind an application or a listing before it goes further, with the property risk pack on the same job.
Property lenders and lending platforms
Onboard borrowers and the companies behind them: sanctions and PEP, the owners through every layer of companies, and ID by link. Each lender’s name can go on its own certificates.
What it covers
- Sanctions and PEP screeningEvery person and company checked against the UK, UN, EU and US sanctions lists, updated every morning. Add PEP and adverse media where the job needs it.
- ID and Right to Rent by linkThe person checks their ID on their own phone. For a tenant in England, the same link checks their right to rent too. The result and the report come back to the job.
- Company and owners (KYB)The Companies House record, the directors and the owners through every layer of companies, each one screened. The KYB package adds the FCA register, a business risk score and PEP on the people.
- Property risk packThe EPC and MEES verdict, flood risk and crime for the postcode, on the same job and the same certificate.
- Monitoring until completionEveryone in the job is screened again every morning until you mark it complete. The first 6 weeks are included.
- A signed certificate for each jobHash-bound, with a public page on certaby.com where anyone can check it. Your team sees the same job under Transactions on certaby.com.
- WebhooksSigned events when a run finds something to review, a certificate is re-issued, or the daily watch raises an alert.
Prices
Paid per check from your Certaby credit, the same balance your team uses on the website. The lower price applies from 1,000 checks of a kind a month on your account.
- Sanctions screen, a person or company9p
4p from 1,000 a month
Against the UK, UN, EU and US lists, updated every morning.
- PEP and adverse media, a person30p
20p from 1,000 a month
Added to the sanctions screen: whether the person is politically exposed (a PEP), and serious adverse news.
- Company and owners, a company£1.79
99p from 1,000 a month
The Companies House record, the directors and the owners through every layer of companies, each screened and checked against the register of disqualified directors (up to 30 people).
- KYB package, a company£3.99
The company and owners check, the company's own screen, the FCA register and Warning List, a business risk score, and PEP and adverse media on up to 4 of its people.
- Property risk pack, a property79p
49p from 1,000 a month
The EPC and MEES verdict, flood risk and crime for the property's postcode.
- ID check by link, a person£1.99
Their ID document and a live selfie, checked on their own phone. The report comes back to the job.
- ID and Right to Rent by link, a tenant£3.49
A certified check of a British or Irish passport, or their Home Office share code, with the ID check. For lets in England.
| Check | Price | From 1,000 a month |
|---|---|---|
| Sanctions screen, a person or companyAgainst the UK, UN, EU and US lists, updated every morning. | 9p | 4p |
| PEP and adverse media, a personAdded to the sanctions screen: whether the person is politically exposed (a PEP), and serious adverse news. | 30p | 20p |
| Company and owners, a companyThe Companies House record, the directors and the owners through every layer of companies, each screened and checked against the register of disqualified directors (up to 30 people). | £1.79 | 99p |
| KYB package, a companyThe company and owners check, the company's own screen, the FCA register and Warning List, a business risk score, and PEP and adverse media on up to 4 of its people. | £3.99 | Same price |
| Property risk pack, a propertyThe EPC and MEES verdict, flood risk and crime for the property's postcode. | 79p | 49p |
| ID check by link, a personTheir ID document and a live selfie, checked on their own phone. The report comes back to the job. | £1.99 | Same price |
| ID and Right to Rent by link, a tenantA certified check of a British or Irish passport, or their Home Office share code, with the ID check. For lets in England. | £3.49 | Same price |
- Monitoring until completion: the first 6 weeks are included; a longer job’s watch is extended at 10p a person a week.
- Starting, changing and reading transactions, quotes, the company lookup, records and webhooks have no charge, and each job’s certificate is included.
- A check that fails is not charged, and nothing runs without the credit for it.
- Credit tops up from £5 on the pricing page and never expires.
How to start
- 1
Sign up, or sign in
Use your firm’s Certaby account, or make one. Set your firm’s name in Settings: it is printed on every certificate.
- 2
Make your test key
In Settings, open Developers and make a test key. It runs 50 real checks free, so you can build against real answers.
- 3
Go live
Top up your credit and make your live key. Every reply tells you the credit left.
Signed in already? Open Settings, Developers. Your first call can be GET /v1/transactions: it lists your transactions and has no charge.
Reference
The Certaby API reference
Every example below runs against the live API. Put your key in an environment variable first (export CERTABY_KEY=certaby_test_...), and start with your test key: it runs real checks and charges nothing.
Your key and the base address
Every call goes to https://api.certaby.com and carries your key in the X-Certaby-Key header. A live key starts certaby_; a test key starts certaby_test_.
curl https://api.certaby.com/v1/transactions \
-H "X-Certaby-Key: $CERTABY_KEY"- Make your keys in Settings, Developers. An account has one live key and one test key. Each is shown once, when it is made; after that you see its last four characters.
- A new key stops the old one straight away, and so does revoking it. In a team, the account’s owner manages the keys.
- Keep the key on your server. Never put it in a web page or an app people can download.
- Requests and replies are JSON. Amounts are in pence; dates are ISO 8601 in UTC.
A job, from start to certificate
A transaction is one job: a let, a sale, or a finance case such as a loan. It holds the people and the property, the checks chosen for them, their results and one signed certificate. It is an ordinary Certaby transaction, so your team also sees it under Transactions on certaby.com.
- 1
Start it
curl -X POST https://api.certaby.com/v1/transactions \ -H "X-Certaby-Key: $CERTABY_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "sale" }'typeisletting,saleorfinance(clients, borrowers and companies, with no property). The reply (201) gives thetxnIdyou use from now on. - 2
Add the people, the property and the checks
curl -X PATCH https://api.certaby.com/v1/transactions/$TXN_ID \ -H "X-Certaby-Key: $CERTABY_KEY" \ -H "Content-Type: application/json" \ -d '{ "reference": { "matterRef": "SALE-2208" }, "property": { "postcode": "LS1 5HN", "addressLine1": "12 Park Row" }, "parties": [ { "partyId": "buyer-1", "role": "buyer", "kind": "individual", "name": "Jordan Ellis", "dob": "1991-04-12" }, { "partyId": "seller-1", "role": "seller", "kind": "individual", "name": "Morgan Hale" } ], "selectedCheckKeys": ["sanctions", "pepAdverseMedia", "propertyPack", "monitoring"] }'parties- Everyone in the job:
role,kind(individualorcorporate),name, and for a company itscompanyNumber. A date of birth (dob, YYYY-MM-DD) helps tell people with the same name apart. The list replaces the last one sent, so send everyone each time, each with the samepartyId. property- The
postcodeand first line (addressLine1). The postcode also sets which UK nation’s rules apply. selectedCheckKeys- The checks to run, from the list below.
reference- Your own reference (
matterRef), printed on the certificate. issuerName- The firm this job’s certificate names, up to 200 characters. A platform that serves several firms (a lending platform with many lenders, say) puts each firm’s name on its own jobs.
nullgoes back to your account’s firm name.
Roles in each kind of job
- Letting:
tenant(tenant),landlord(landlord),guarantor(guarantor),payer(payer),rep(representative) - Property sale:
buyer(buyer),seller(seller),payer(payer),rep(representative) - Finance and business:
client(client),donor(donor or funder),director(director or owner),counterparty(counterparty),payer(payer),rep(representative)
Check keys
sanctions- Sanctions screen of every named person and company.
pepAdverseMedia- PEP and adverse media, added to the sanctions screen (for a company, also its directors and owners). Brings in sanctions if it isn't chosen.
pscWalk- Company and owners, for each company with a companyNumber.
kyb- The KYB package, for each company with a companyNumber, in place of company and owners.
propertyPack- The property risk pack, for the property (it needs a postcode).
idv- The ID check: by link with idMethods { "idv": "link" }, or recorded by your firm.
rightToRent- Right to Rent, for tenants on a let in England.
monitoring- Monitoring until completion: everyone named, from the run.
riskRecord- The customer's risk and source of funds record, filled in with POST /risk.
- 3
See the price before anything runs
curl https://api.certaby.com/v1/transactions/$TXN_ID/quote \ -H "X-Certaby-Key: $CERTABY_KEY"The reply lists each check (
lineItems), thetotalPenceand yourbalancePence. The total assumes every check runs; a run charges only checks that are new, changed or failed since the last run. - 4
Run it
curl -X POST https://api.certaby.com/v1/transactions/$TXN_ID/run \ -H "X-Certaby-Key: $CERTABY_KEY"ok- True when the run went ahead. Check it on every reply.
totalChargedPence- What this run took from your credit. A check that fails is not charged.
balanceAfterPence- Your credit after the run.
certHash- The certificate’s reference (see step 6).
transaction- The whole transaction, with its results.
more- A big job can run in parts: when the reply says
"more": true, call run again with{ "continue": true }until it doesn’t.
Run it again after a change and only what is new or changed is checked and charged. Send
{ "recheck": true }to check everyone again, charged in full. - 5
Read the results
transaction.resultshas one row per check and person:checkKey,partyId,checkId,status(success,partial,pendingorerror),costPence,ranAt, and for a screenfindings, the number of possible matches by kind. Apendingrow is a step for your firm, such as a Right to Rent check to record.The full answer behind one row curl https://api.certaby.com/v1/transactions/$TXN_ID/checks/$CHECK_ID \ -H "X-Certaby-Key: $CERTABY_KEY"GET /v1/transactions/{id}/results.csvgives every name and what each check found, as a spreadsheet for your records. - 6
The certificate
Each run issues one signed certificate for the whole job. Anyone can check it at
https://certaby.com/verify/{certHash}, which shows the verdict, the lists checked and the date, and no personal details.transaction.cert.summaryVerdictisPASS,REVIEWorFAIL.The certificate is re-issued, with a new
certHash, when a record is added or the watch changes. Your team can download the PDF from the transaction on certaby.com. The firm it names comes from your account; set it once:curl -X PUT https://api.certaby.com/v1/transactions/firm \ -H "X-Certaby-Key: $CERTABY_KEY" \ -H "Content-Type: application/json" \ -d '{ "firmName": "Oakwood Lettings" }'
A job in one call
A suite starts the job, chooses its checks from what you send, runs it and issues the certificate, all in one call. After that it is an ordinary transaction, with a txnId like any other.
curl -X POST https://api.certaby.com/v1/suites/letting/check \
-H "X-Certaby-Key: $CERTABY_KEY" \
-H "Content-Type: application/json" \
-d '{
"reference": {
"matterRef": "LET-1042"
},
"property": {
"postcode": "LS1 5HN",
"addressLine1": "Flat 3, 12 Park Row"
},
"parties": [
{
"role": "tenant",
"kind": "individual",
"name": "Jordan Ellis",
"dob": "1991-04-12"
},
{
"role": "landlord",
"kind": "corporate",
"name": "Park Row Homes Ltd",
"companyNumber": "12345678"
}
],
"pep": true
}'{suite}isletting,saleorfinance, with the roles listed in step 2 above, and up to 50 parties.- Everyone named gets the sanctions screen.
- PEP and adverse media:
"pep": trueorfalse. Without it, PEP is on for a property sale and on for a finance and business and off for a letting. - A company with a
companyNumbergets the company and owners check; in a finance job,"kyb": truegives it the KYB package instead. - A letting or sale with a
property.postcodegets the property risk pack ("propertyPack": falseleaves it out). referenceandissuerNamework as in step 2 above.- The reply is the run’s reply, plus
txnIdand thecheckschosen. Short of credit, the job is kept as a draft: top up and run it by itstxnId.
GET /v1/suites lists each suite, what it runs and the price of its usual job.
ID and Right to Rent by link
The person checks their own ID on their phone, from a link. For a tenant on a let in England, the same link can also check their right to rent. The result and the identity service’s PDF report come back to the transaction.
- 1
Choose “by link” on the transaction
For a tenant, ID and Right to Rent together:
curl -X PATCH https://api.certaby.com/v1/transactions/$TXN_ID \ -H "X-Certaby-Key: $CERTABY_KEY" \ -H "Content-Type: application/json" \ -d '{ "selectedCheckKeys": ["sanctions", "rightToRent"], "idMethods": { "rightToRent": "link" } }'For anyone else (a buyer, a landlord, a borrower), the ID check:
{"selectedCheckKeys":["sanctions","idv"],"idMethods":{"idv":"link"}}. For a tenant’s ID alone, use"idMethods": { "rightToRent": "self", "tenantId": "link" }.The link’s page names your firm, so your firm’s name must be set first (
PUT /v1/transactions/firm, or Settings on certaby.com). - 2
Make the link
curl -X POST https://api.certaby.com/v1/transactions/$TXN_ID/digital-id \ -H "X-Certaby-Key: $CERTABY_KEY" \ -H "Content-Type: application/json" \ -d '{ "partyId": "tenant-1", "email": "jordan.ellis@example.com" }'The reply (201) has the
digitalId: itsrequestId,status(waiting), thestartUrlfor the person,expiresAtandchargedPence. The price is taken from your credit now and given back if the check ends without a result. Asking again for the same person while their link is open gives the same link ("already": true) and charges nothing more. Add"kind": "id"to check a tenant’s ID alone. - 3
The person checks their ID
Certaby emails the person their link, in your firm’s name.
startUrlis the same link, if you also want to show it in your product: it opens a page on certaby.com in your firm’s name, then the check itself. The link works for 7 days. - 4
Follow it
Read where each link stands with
GET /v1/transactions/{id}/digital-id, or ask the identity service for the latest withPOST .../digital-id/{requestId}/refresh.waiting- Link sent, waiting for them
processing- Finished, results being checked
verified- Verified
review- Needs your review
locked_out- Could not verify them (too many attempts). No charge
expired- Not finished in time. No charge
cancelled- Cancelled. No charge
blocked- The identity service refused this person. No charge
No charge for locked out, expired, cancelled and blocked: the price goes back to your credit.
- 5
Finish it
review: read the report (GET .../report), then accept it with a sentence on why:POST .../accept { "note": "..." }.- Right to Rent: the Home Office asks you to make sure the photo and date of birth in the report are the tenant’s. Confirm it with
POST .../photo { "confirmed": true }; the Right to Rent is recorded then. - A link not finished can be cancelled (
DELETE .../digital-id/{requestId}), and the charge comes back.
Monitoring until completion
Add monitoring to the checks and the run puts everyone named on a daily watch: they are screened against the sanctions lists again every morning until you mark the job complete. The first 6 weeks are included. A new match is a watch.alert webhook event.
POST /v1/transactions/{id}/monitorstarts the watch now, or adds anyone new to it.- Longer jobs: extend by 2, 4, 8 and 12 weeks at 10p a person a week, up to 52 weeks in all.
DELETE /v1/transactions/{id}/monitorwhen the job completes: the watch stops.
curl -X PUT https://api.certaby.com/v1/transactions/$TXN_ID/monitor \
-H "X-Certaby-Key: $CERTABY_KEY" \
-H "Content-Type: application/json" \
-d '{
"weeks": 4
}'Webhooks
Give us one https address and we post each event to it as it happens. Set it in Settings, Developers, or with the API:
curl -X PUT https://api.certaby.com/v1/webhooks \
-H "X-Certaby-Key: $CERTABY_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example/webhooks/certaby"
}'A new address, or "rotateSecret": true, returns the signing secret once. POST /v1/webhooks/test sends a test event, and GET /v1/webhooks/deliveries shows how the newest ones went.
transaction.matches- A run found something to review: the rows, with their checkId.
certificate.reissued- A certificate has a new version: certHash, previousCertHash and verifyUrl.
watch.alert- The daily watch found a new match for someone in a job: txnId, entityName and what is new.
ping- A test event.
{
"id": "evt_6f1c0a9b2e4d4c7a8b3e5f10",
"type": "transaction.matches",
"createdAt": "2026-10-28T14:05:12.000Z",
"data": {
"txnId": "b7e3c2a0-5d1f-4e8a-9c6b-2f4d8a1e0c37",
"type": "letting",
"reference": "LET-1042",
"matches": [
{ "checkId": "3b8f2c1e-9a4d-4f7b", "checkKey": "sanctions", "partyId": "party-1", "findings": { "sanctions": 1 } }
],
"certHash": "9c41d2e07ab35f6e1d88",
"detail": "GET /v1/transactions/b7e3c2a0-5d1f-4e8a-9c6b-2f4d8a1e0c37/checks/{checkId} for each match"
}
}Check that an event came from us
Each event comes with Certaby-Event-Id and Certaby-Event-Type headers (the same id and type as in the body), from the user agent Certaby-Webhooks/1.0, and a Certaby-Signature header: t=<unix seconds>,v1=<signature>, where the signature is the HMAC-SHA256, in hex, of the time, a full stop and the body, with your signing secret as the key. Check it against the body exactly as it arrived, before you parse it:
import { createHmac, timingSafeEqual } from 'node:crypto';
// header: the Certaby-Signature header, "t=<unix seconds>,v1=<hex>"
// raw: the request body exactly as it arrived (a string), before JSON.parse
// secret: your signing secret from Settings, Developers
export function isFromCertaby(header, raw, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')));
const t = Number(parts.t);
// Refuse anything signed more than five minutes ago (each try is signed when it is sent).
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = createHmac('sha256', secret).update(`${t}.${raw}`).digest();
const given = Buffer.from(parts.v1 ?? '', 'hex');
return given.length === expected.length && timingSafeEqual(given, expected);
}- Answer with any 2xx status within 10 seconds. We don’t follow redirects.
- Anything else is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours, then marked as not delivered. Events are kept for 30 days.
- An event can arrive more than once: use its
idto skip repeats. Events from the test key say"test": true.
Errors
Every refusal says what to do in plain words. Most look like { "ok": false, "reason": "...", "message": "..." }; the key and creating or reading a transaction answer { "error": { "code": "...", "message": "..." } }. Read reason or error.code, and show message to your user if it helps.
| Status | What it means |
|---|---|
| 400 | Something in the request needs fixing; message says what. |
| 401 | No key (missing_key), a key we don’t know (invalid_key), or one that was replaced or revoked (revoked_key). |
| 402 | Not enough credit (insufficient_credit). Nothing ran and nothing was charged. The reply has topUpUrl, https://certaby.com/pricing#credit-packs; a run also says neededPence and balancePence. |
| 403 | The key can’t do this: a route outside the Certaby API (certaby_key), or a live key before paid calls are open (not_open_yet). |
| 404 | No such route, or no transaction, check or link with that id on your account. |
| 409 | Not in this state: a test transaction run with the live key or the other way round, a link before your firm’s name is set, or a check that has already moved on. |
| 429 | The test key’s free real checks are used up, or too few are left for this run (test_limit). |
| 502, 503 | A service we rely on didn’t answer just now. Try again in a minute. |
Credit
Checks are paid from your Certaby credit, the same balance your team uses on the website. Every reply carries X-Certaby-Credit-Balance-Pence: the credit left, in pence. Top up at certaby.com/pricing#credit-packs. Nothing runs without the credit for it, so a job is never half charged.
The test key
- Real checks on real data, with nothing charged: 50 free real checks for your account, once.
- PEP and adverse media give a labelled test answer.
- Certificates name the issuer as TEST, not for compliance.
- A test key runs the transactions it made; your live key runs its own.
- ID links go to the identity service’s practice service: nobody is checked or emailed, and nothing is charged.
- Monitoring is for live jobs.
Every route
All under https://api.certaby.com. Routes marked “paid” take credit at the prices above; the rest have no charge.
Transactions
- POST/v1/
transactionsStart a transaction: { "type": "letting" | "sale" | "finance" }. - GET/v1/
transactionsYour transactions, newest first (?limit=1-200, ?after=nextCursor). - GET/v1/
transactions/ {id}One transaction, with its results and certificate. - PATCH/v1/
transactions/ {id}Set the parties, property, reference, checks and how ID is done. - GET/v1/
transactions/ {id}/ quoteWhat the chosen checks cost, and your balance. - POST/v1/
transactions/ {id}/ runRun the checks and issue the certificate.paid - GET/v1/
transactions/ {id}/ checks/ {checkId}The full answer behind one result row. - GET/v1/
transactions/ {id}/ results.csvEvery name and what each check found, as a spreadsheet. - GET/v1/
transactions/ company-lookupA company and the people its check would screen (?number=), free.
Suites (a job in one call)
- GET/v1/
suitesEach suite, what it runs and its usual price. - POST/v1/
suites/ {suite}/ checkStart, fill in and run a letting, sale or finance job in one call.paid
ID and Right to Rent by link
- POST/v1/
transactions/ {id}/ digital-idMake a link for a person: { partyId, email }.paid - GET/v1/
transactions/ {id}/ digital-idWhere each link on the transaction stands. - POST/v1/
transactions/ {id}/ digital-id/ {requestId}/ refreshRead the latest from the identity service now. - DELETE/v1/
transactions/ {id}/ digital-id/ {requestId}Cancel a link the person has not finished (the charge comes back). - GET/v1/
transactions/ {id}/ digital-id/ {requestId}/ reportThe PDF report (a redirect to a download link that lasts 5 minutes). - POST/v1/
transactions/ {id}/ digital-id/ {requestId}/ acceptAccept a check that needs review: { "note": "why" }. - POST/v1/
transactions/ {id}/ digital-id/ {requestId}/ photoConfirm the photo is the tenant's (Right to Rent): { "confirmed": true }. - POST/v1/
transactions/ {id}/ digital-id/ {requestId}/ report/ deleteDelete the report once you have filed your own copy: { "confirmed": true }.
Monitoring until completion
- POST/v1/
transactions/ {id}/ monitorStart the daily watch now, or add anyone new to it. - PUT/v1/
transactions/ {id}/ monitorExtend the watch: { "weeks": 2 | 4 | 8 | 12 }.paid - DELETE/v1/
transactions/ {id}/ monitorThe job is complete: stop the watch.
Records kept with the job
- POST/v1/
transactions/ {id}/ idvRecord an ID check your firm did itself, free. - POST/v1/
transactions/ {id}/ right-to-rentRecord a Right to Rent check your firm did itself, free. - POST/v1/
transactions/ {id}/ riskA customer's risk and source of funds record, free. - POST/v1/
transactions/ {id}/ evidenceA link to upload an evidence file for a record. - GET/v1/
transactions/ {id}/ evidence/ {fileId}Download an evidence file.
Your firm and webhook
- GET/v1/
transactions/ firmThe firm name your certificates print. - PUT/v1/
transactions/ firmSet it: { "firmName": "...", "firmAddress": "..." }. - GET/v1/
webhooksYour endpoint (the secret’s last four characters) and the events. - PUT/v1/
webhooksSet it: { "url": "https://..." }; add "rotateSecret": true for a new secret. - DELETE/v1/
webhooksStop sending. - POST/v1/
webhooks/ testSend a test event. - GET/v1/
webhooks/ deliveriesThe newest 50 events and how each went.
Questions while you build?
Write to hello@certaby.com with what you are building, and we’ll answer in plain words.