Credential Ownership
A credential belongs to the person it was issued to, and that person may be an applicant during recruitment and a worker after they're hired. Ownership is what carries the credential — and its verification history — across that boundary without re-verifying it.
Most integrations never touch these endpoints: creating a credential with owners set, as the
Workers & Credentials tutorial does, is enough.
You need this page when ownership has to change after the fact — the applicant-to-worker hire
flow above all.
Link, unlink, transfer
owners is immutable on PATCH/PUT — attempting it returns 400. Change ownership through
the dedicated endpoints instead. Each owner reference is a type plus exactly one of id
or externalId. A credential holds at most one worker and one applicant slot at a time.
# Link an additional owner to one credential
curl -sS -X POST "$OHO_BASE/credentials/$CRED/link" \
-H "Authorization: Bearer $OHO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "to": { "type": "applicant", "id": "app_Qz7yT2mB" } }'
# Transfer an owner — the canonical applicant -> worker hire flow
curl -sS -X POST "$OHO_BASE/credentials/$CRED/transfer" \
-H "Authorization: Bearer $OHO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "from": { "type": "applicant", "id": "app_Qz7yT2mB" }, "to": { "type": "worker", "id": "'"$WKR"'" } }'
# Unlink an owner (refuses if it would leave the credential with no owners)
curl -sS -X POST "$OHO_BASE/credentials/$CRED/unlink" \
-H "Authorization: Bearer $OHO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ownerType": "applicant" }'
References: Link · Transfer · Unlink.
Linking a slot that already holds a different id returns 409 with code ALREADY_LINKED — use
transfer to replace it. Transferring a credential not currently owned by from returns 409
with code OWNER_MISMATCH.
Bulk ownership
POST /credentials/link and POST /credentials/transfer (no
{id} in the path) operate on many credentials at once. Omit credentialIds to process every
credential currently linked to from; the response reports a per-item status. Best-effort batch,
capped at 500.
curl -sS -X POST "$OHO_BASE/credentials/transfer" \
-H "Authorization: Bearer $OHO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": { "type": "applicant", "externalId": "ATS-55021" },
"to": { "type": "worker", "externalId": "WD-100482", "sourceSystem": "workday" }
}'
{
"data": [
{ "credentialId": "cred_8x2Kf9aQ4mN7pLrT", "status": "transferred" },
{
"credentialId": "cred_bad1",
"status": "skipped",
"error": {
"code": "OWNER_MISMATCH",
"message": "not owned by applicant ..."
}
}
],
"meta": { "total": 2, "succeeded": 1, "failed": 1, "requestId": "..." }
}
Related
- Workers & Credentials Tutorial — the core create → verify → read flow
- Screening an Applicant — the recruitment flow these transfers complete
- Linking & ownership — the concept, without the API
- Errors, Retries & Idempotency — recovering from
ALREADY_LINKEDandOWNER_MISMATCH