Free screeningYour first screening is free, on any type. No monthly fee until you choose a plan.See pricing →
Developers
Yezda API and webhooks
Invite candidates to screening from your ATS or HR system, read their results back, and get told the moment anything changes.
LAST UPDATED · 10 November 2026EN-GB
Overview
The Yezda API is a JSON REST API. Use it to start screenings without opening the portal, keep your own records in step with each candidate's progress, and fetch certificates and reports when they're issued. Webhooks push each change to you as it happens, so you don't have to poll.
Base URL:https://api.yezda.co.uk/api/v1/public
Plan: the API and webhooks are part of our top plan.
Credits: inviting through the API is paid for exactly as inviting from the portal is.
Format: JSON in and out, UTF-8, dates in ISO 8601 (UTC).
Quick start
As the account owner, turn on two-factor sign-in (Profile → Settings). Keys carry your access, so we ask for it before you can create one.
Go to Admin Settings → Developers and create a key. Limit it to your servers' IP addresses if you can. The key is shown once: store it in your secret manager.
Send your key on every request in the Authorization header: Bearer yz_live_…. Requests without a valid key are refused before they reach our servers.
Live and test keys. Live keys start yz_live_ and work on real screenings. Test keys start yz_test_ and work against a sandbox; see Test mode.
Keep keys on your server. A key acts with the account owner's access. Never put one in a browser, a mobile app or source control.
Allowed addresses. A key can be limited to IP addresses or ranges. Calls from anywhere else are refused with 403.
Expiry. Keys can expire after 30, 90 or 180 days, or a year. Create the replacement before the old key expires, then revoke the old one.
Revoking. Revoked keys stop working immediately. Keys also stop working if their creator is no longer the account owner.
Notifications. The account owner is emailed whenever a key or webhook endpoint is created, changed or revoked.
Test mode
Build and test your integration with a test key before you go live. A test key (yz_test_…) works exactly like a live one, but everything it does stays in a sandbox:
Invites send no email or SMS, use no credits and never appear in the portal.
A test key only sees test screenings, and a live key never sees them.
Test screenings don't move on by themselves. Move them through each step with simulate, which fires the matching webhook.
Test events only go to webhook endpoints you added in Test mode. Every webhook and /me carry livemode, which is false in test mode.
Test screenings have no certificate or report files, and are deleted after 30 days.
curl
# 1. Invite a test candidate (nothing is sent)
curl -X POST "https://api.yezda.co.uk/api/v1/public/screenings" \
-H "Authorization: Bearer $YEZDA_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{"first_name":"Jordan","last_name":"Patel","email":"jordan@example.com","mobile_number":"+447123456789"}'
# 2. Walk it through, firing screening.started, .completed and .certificate_issued
for event in started completed certificate_issued; do
curl -X POST "https://api.yezda.co.uk/api/v1/public/screenings/$SCREENING_ID/simulate" \
-H "Authorization: Bearer $YEZDA_TEST_KEY" \
-H "Content-Type: application/json" \
-d "{\"event\":\"$event\"}"
done
completed takes an optional outcome (clear, refer or not_clear; default clear), and stage_changed an optional stage name. Steps must happen in order. When it all works, swap in a live key and a live endpoint.
Limits and retries
Limit
Value
Requests per key
60 a minute
Request body
JSON only, up to 16 KB
Page size
Up to 100 screenings
Keys per account
10 live keys
Webhook endpoints per account
25
Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Past the limit you get 429 with a Retry-After header in seconds. An address that keeps sending invalid keys is blocked from trying more for 15 minutes; valid keys from it keep working.
Idempotency. Send an Idempotency-Key header (any unique string, such as a UUID) when you invite a candidate. If the request times out, send it again with the same key: within 24 hours you get the original screening back instead of a second invite and a second credit used.
Sends the candidate their invite by email and SMS and uses one screening credit for the type, exactly as inviting from the portal does. Send an Idempotency-Key header to retry safely: a repeat within 24 hours returns the first screening instead of inviting again.
Parameters
Name
In
Notes
Idempotency-Key
header
string
Request body
Field
Type
Notes
first_name
string
Required. Up to 120 characters.
middle_name
string
Up to 120 characters.
last_name
string
Required. Up to 120 characters.
email
email
Required. Up to 254 characters.
mobile_number
string
Required. International format, e.g. +447123456789. Up to 20 characters.
job_role
string
Up to 100 characters.
dob
date
ni_number
string
Up to 50 characters.
nationality
string
Up to 100 characters.
screening_type
string
A code from GET /screening-types. Defaults to your account default.
Add a webhook endpoint from your code (how Zapier and similar tools subscribe). It receives this key's mode of events, and is removed when the key is revoked; while the key is expired it receives nothing. The account owner is emailed. The signing secret is returned once.
Request body
Field
Type
Notes
url
string
Required. A public https:// URL. Up to 2000 characters.
Test keys only. Moves a test screening on as if the candidate and screener had acted, and fires the matching webhook to your test endpoints: started (invite accepted), stage_changed (optional stage name), completed (optional outcome: clear, refer or not_clear; default clear), certificate_issued (after a clear outcome). Steps must happen in order.
Parameters
Name
In
Notes
id
path
Required. The screening id.
Request body
Field
Type
Notes
event
string
Required. One of started, stage_changed, completed, certificate_issued.
outcome
string
With completed. Default clear. One of clear, refer, not_clear.
stage
string
With stage_changed: the stage name to report. Up to 80 characters.
Add an endpoint in Admin Settings → Developers: an https:// URL on the public internet, and the events to send to it. You'll be shown a signing secret once; store it alongside your API key. Use Send test to check your endpoint receives a ping.
You can also add and remove endpoints from your code with POST /webhooks and DELETE /webhooks/{id}. That's how tools like Zapier subscribe. An endpoint added with a key gets that key's events (live or test), and is removed when the key is revoked.
Events
Event
Sent when
screening.invited
A candidate was invited (from the portal or the API).
screening.started
The candidate accepted the invite and started their screening.
screening.stage_changed
The screening moved to a new stage. Carries data.stage.
screening.completed
A screener decided the outcome (clear, refer or not clear), or you decided on a referral.
screening.certificate_issued
The screening certificate was issued.
screening.cancelled
An invite was cancelled before the candidate started.
Payload
Each event is a POST with a JSON body. data.screening has the same shape as Screening.
Every request carries Yezda-Signature: t=<unix seconds>,v1=<hex>. v1 is an HMAC-SHA256 of <t>.<raw body> with your endpoint's secret. Recompute it, compare in constant time, and reject requests whose t is more than five minutes old. Use the raw body: parsing and re-serialising JSON changes the bytes.
import crypto from "node:crypto";
// rawBody: the request body exactly as received, before JSON parsing.
export function verifyYezdaSignature(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Two more headers help with logging: Yezda-Event (the event type) and Yezda-Delivery (unique per delivery attempt record).
Delivery and retries
Answer with any 2xx status within 10 seconds. Do slow work after you've answered.
Anything else is retried after 1, 5, 15, 60, 180, 360 and 720 minutes. After five events in a row fail every retry, the endpoint is turned off and the account owner is emailed. Turn it back on in the portal once it's fixed.
Events can arrive more than once or out of order. Use the event id to ignore duplicates, and screening.updated_at to keep the newest state.
Every delivery is listed in the portal, where you can resend it.
Security
HTTPS only, behind a web application firewall.
Keys are stored only as a hash; signing secrets are encrypted.
Every call is logged with its key and address, for your audit trail and ours.
Webhooks are only sent to public internet addresses and never follow redirects, so they can't be pointed at private networks.