Applications in. Evidence report out.
A REST API with two intake modes, webhooks, and a sandbox that never touches a live source. Everything the product does is reachable over the API; the interface is one client of it.
The endpoints
| Method and path | Scope | What it does |
|---|---|---|
POST /v1/applications | applications:write | Takes an application in, in either of the two modes below. |
GET /v1/applications/{id} | reports:read | State of the application: waiting_confirmation, confirmed or checked. |
GET /v1/applications/{id}/claims | reports:read | The claims extracted from a CV, waiting for a person to confirm them. |
POST /v1/applications/{id}/claims/confirm | applications:write | Confirms the claims. Requires acting_user, so a person is on record. |
POST /v1/applications/{id}/checks | applications:write | Starts the check. Requires acting_user. |
GET /v1/applications/{id}/report | reports:read | The report: three blocks, every finding with its provenance. |
DELETE /v1/applications/{id} | applications:write | Deletes the candidate immediately. |
POST /v1/webhooks | webhooks:manage | Registers an endpoint and returns its signing secret once. |
GET /v1/webhooks | webhooks:manage | Lists active endpoints, without their secrets. |
DELETE /v1/webhooks/{id} | webhooks:manage | Revokes an endpoint. |
Authentication is a bearer key, cand_live_ or cand_test_, carrying the scopes above. The rate limit is 120 requests a minute per organisation; over that the API answers 429 with Retry-After.
Two ways an application comes in
Structured data
Claims a person already entered in your ATS arrive as JSON, written as confirmed under the identity in acting_user. The check can run straight away, because a person has already stood behind the claims.
A CV file
A PDF up to 10 MB arrives as multipart form data. The claims extracted from it wait for confirmation through the confirm endpoint: between extraction and checking there is a person, and the database lock enforces it rather than the documentation asking nicely.
Structured intake, the whole request
POST /v1/applications
Authorization: Bearer cand_test_...
{
"acting_user": "recruiter@firma.cz",
"positionTitle": "Backend Developer",
"applicationReceivedAt": "2026-08-01",
"externalRef": "ATS-1234",
"email": "kandidat@example.com",
"claims": [
{
"employerName": "Acme s.r.o.",
"employerCountry": "CZ",
"claimedDomain": "acme.cz",
"periodStart": "2020-01-01",
"periodEnd": "2022-01-01"
}
]
}How you connect
Three ways, and each one makes plain what you need for it.
API
An application arrives as JSON or as a file. The response carries findings with a source, a query time and a rule version.
The calls are described in the table above.
CSV import
When your ATS has no API, or you cannot reach it, you upload an export. Columns are mapped once and later imports follow that mapping.
We do not prescribe the export format; the mapping is on our side.
Tell us which ATS you use
Tell us what you run hiring in and we will say whether it goes through the API, through an export, or not yet at all.
You get a written answer, not an invitation to a call.
The shape of a report
Three blocks: mismatches, verified_without_finding and unverifiable. Every finding carries a statement in Czech and in English, the evidence, the source URL, the time of the query, the rule key and the rule version. The unverifiable block is part of the truth, not an error state: it says what could not be checked and why.
No response of this API ever contains a score, a risk value, a probability or a recommendation. A test in the codebase fails if one appears.
Webhooks
One event type today, check_run.completed, and further types are added the same way. Delivery is at-least-once and the payload carries an event_id for idempotency. The signature is an HMAC-SHA256 of the body in the X-Candora-Signature header. Retries go at 1, 5 and 25 minutes, then the delivery is marked failed. The endpoint has to be https and cannot point at a private address.
Sandbox
A cand_test_ key never calls a live source, and it behaves the same way every time, so an integration test can assert on the result:
- An employer whose name contains Fraud lands in mismatches.
- An employer with employerCountry outside CZ lands in unverifiable.
- Everything else lands in verified_without_finding.
Versioning
The path carries /v1 and changes are additive only. A breaking change means /v2, and the report response carries its schema_version, so a stored report says which shape it was written in.
The full reference is public
The OpenAPI reference is generated from the routes and is publicly available at app.getcandora.com/api/openapi.json, with no key and no scope. The sandbox key stays: a cand_test_ key still switches to fixture adapters and is available on request.