API
Verifications
API reference for submitting verification requests and tracking their holder-authorised results.
Updated
On this page
A verification request asks Arrota to compare what a candidate told you with a record in their Vault. The record holder must authorise the check, the issuing organisation's disclosure policy applies, and you receive a result for each claim. You never receive the record's stored values.
Who can use it
- Your organisation must be an active verifier organisation on a plan with API access.
- Your key needs the
verifications:writescope.
Other organisations receive 403 even with the scope.
How a request moves
- You submit claims about a record. The request starts as
authorisation_required, and Arrota emails the holder. - The holder approves or denies it in their Vault. Nothing is compared until they approve.
- If they approve, the issuing organisation's policy decides: the result is released immediately, or held for the organisation's review (
pending_review). - The request becomes
resolvedwith anoutcomeand per-claimfields.
There is no webhook for your own requests; poll the request until it is resolved.
Submit a verification request
POST/api/v1/verifications
Body
| Field | Type | Required | Description |
|---|---|---|---|
record_id | string (UUID) | Yes | The record to check. The holder can share its Record ID from their Vault. |
submitted_claims | object | Yes | The facts to compare, as field: "value" strings of up to 500 characters. Only fields for the record's type are accepted. |
authorisation_proof_url | string | No | An https link to the candidate's consent form. |
| Record type | Fields you can submit |
|---|---|
| Employment | employer_name, job_title, employment_type, start_date, end_date |
| Education, Transcript | institution_name, qualification, field_of_study, graduation_year, start_date, end_date |
| Other types | start_date, end_date |
Example request
curl -X POST "https://app.arrota.com/api/v1/verifications" \
-H "Authorization: Bearer $ARROTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"record_id": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c6b",
"submitted_claims": {
"job_title": "Operations Manager",
"start_date": "2021-01-15"
}
}'const response = await fetch("https://app.arrota.com/api/v1/verifications", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ARROTA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
record_id: "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c6b",
submitted_claims: { job_title: "Operations Manager", start_date: "2021-01-15" },
}),
});
const { request_id } = await response.json();Response
{
"ok": true,
"request_id": "2c4e6a8b-0d1f-4a3c-b5e7-9a1c3e5b7d9f",
"status": "Authorisation Required",
"message": "The record holder must authorise this verification before any comparison runs. Poll GET /api/v1/verifications/{request_id} for the outcome."
}In the live response, {request_id} in message is replaced by the request's own ID.
Errors
| Status | code | When |
|---|---|---|
| 400 | none | record_id is not a UUID, submitted_claims is empty, a claim field or value is not accepted, or authorisation_proof_url is not https. |
| 403 | RECORD_NOT_ELIGIBLE | Only active records issued by an organisation can be checked. |
| 403 | DISCLOSURE_REFUSED | The issuing organisation does not answer verification requests for this record type. |
| 403 | none | Missing scope, or your organisation is not an eligible verifier. |
| 404 | none | The record could not be checked. Arrota gives the same answer for a record that does not exist. |
| 500 | none | The request was created, but the holder could not be notified. The body includes request_id. |
Each accepted call creates a new request and emails the holder, so do not resubmit a request that was accepted.
Get a verification request
GET/api/v1/verifications/{id}
Returns the current state of a request your organisation submitted. Requests from other organisations return 404.
curl "https://app.arrota.com/api/v1/verifications/2c4e6a8b-0d1f-4a3c-b5e7-9a1c3e5b7d9f" \
-H "Authorization: Bearer $ARROTA_API_KEY"{
"ok": true,
"request_id": "2c4e6a8b-0d1f-4a3c-b5e7-9a1c3e5b7d9f",
"status": "resolved",
"outcome": "Partially Matched",
"fields": [
{ "field": "job_title", "verdict": "match" },
{ "field": "start_date", "verdict": "mismatch" }
],
"created_at": "2026-09-21T09:30:12.004511+00:00",
"resolved_at": "2026-09-22T16:04:51.918220+00:00"
}Status
status | Meaning |
|---|---|
authorisation_required | Waiting for the holder to approve. |
pending_review | The holder approved; the issuing organisation is reviewing the result. |
Payment Required | The holder approved, but your organisation's free verification allowance is used up. Complete payment in the verifier workspace to release the result. |
resolved | Finished. outcome and fields are present. |
outcome and fields appear only when status is resolved.
Outcome
outcome | Meaning |
|---|---|
Matched | Every claim matched. |
Partially Matched | Some claims matched. |
Not Matched | No claims matched. |
Refused | The holder declined, or the issuing organisation's policy refuses disclosure. fields is empty. |
Each entry in fields has a verdict of match, mismatch or not_applicable. A mismatch never reveals the stored value.