Data model

Candidates

A person in the hiring funnel. Carries identity (name, email, phone), source, location, links (LinkedIn / portfolio), tags, skills, GDPR consent + retention. One candidate can have multiple applications across different jobs.

Model name: candidate
Endpoints: 5
Max page size: 200

Fields

Per-field validation rules. Values that violate any constraint are rejected with 400 before they reach the database.

FieldTypeConstraints
citystring
max length120
namestring
max length200
tagstags-
colorstring
max length24
emailstring
max length320
phonestring
max length64
cv_urlurl
max length2048
githuburl
max length2048
skillstags
max count100item max160
streetstring
max length200
countrystring
max length120
summarystring
max length4000
currencystring
max length8
linkedinurl
max length2048
pronounsstring
max length32
languagestags
max count60item max80
last_namestring
max length120
portfoliourl
max length2048
source_idstring
max length64ref →sourceopt
avatar_urlurl
max length2048
cv_blob_idstring
max length64
first_namestring
max length120
salutationenum
enumherr | frau | divers | neutral
pool_statusenum
enumactive | talent_pool | blocked | withdrawn | anonymised
postal_codestring
max length32
current_rolestring
max length200
gdpr_consentbool-
source_labelstring
max length200
available_fromstring
max length32
avatar_blob_idstring
max length64
current_companystring
max length200
gdpr_consent_atstring
max length32
last_touched_atstring
max length32
preferred_localestring
max length16
years_experiencenumber-
gdpr_anonymised_atstring
max length32
salary_expectationnumber-
cover_letter_blob_idstring
max length64
gdpr_retention_untilstring
max length32

Mutability

Which fields can you send, and when? Anything without a marker is server-managed - sending it isn't an error, it's silently ignored.

Create-only - read from POST body.Patchable - read from PATCH body.Server-managed - ignored on the body.
FieldCreatePatch
city
name
tags
color
email
phone
cv_url
github
skills
street
country
summary
currency
linkedin
pronouns
languages
last_name
portfolio
source_id
avatar_url
cv_blob_id
first_name
salutation
pool_status
postal_code
current_role
gdpr_consent
source_label
available_from
avatar_blob_id
current_company
gdpr_consent_at
last_touched_at
preferred_locale
years_experience
gdpr_anonymised_at
salary_expectation
cover_letter_blob_id
gdpr_retention_until

Fields marked create-only but not patchable are immutable after creation. Server-managed fields include id, timestamps, ownership, and status.

Filtering & sorting

Combinable on list endpoints. Repeating a filter key produces an IN clause; prefixing a sort key with - reverses direction. Example: ?status=open&status=blocked&sort=-created_at.

Filter keys

emaildata__email
namedata__name
locationdata__location
countrydata__country
source_iddata__source_id
tagsdata__tags
skillsdata__skills
pool_statusdata__pool_status
gdpr_consentdata__gdpr_consent
statusstatus
is_archivedis_archived
owned_byowned_by
created_bycreated_by

Sort keys

created_atcreated_at
updated_atupdated_at
namedata__name
last_touched_atdata__last_touched_at

Default: created_at

Endpoints

Each endpoint below lists its HTTP method, path, and the PAT scope it needs. Code samples cover curl, JavaScript, TypeScript, Python, Rust, Java, and WebSocket.

GET/xapi2/data/candidatecandidate:list

List objects

Returns a paginated list of objects you can read. Default page size is 20; pass ?limit= to change (capped per type). Use ?after=<id> for keyset pagination on created_at-sorted lists, or ?offset= for offset paging.

curl -H "Authorization: Bearer pat_…" \
"https://ki-bewerber-management.de/xapi2/data/candidate?limit=20"
GET/xapi2/data/candidate/{id}candidate:read

Read one

Returns the object by id. 404 if it does not exist or you cannot read it (the two cases are intentionally conflated).

curl -H "Authorization: Bearer pat_…" \
https://ki-bewerber-management.de/xapi2/data/candidate/OBJECT_ID
POST/xapi2/data/candidatecandidate:create

Create

Creates a new object. Body is a flat JSON dict of field values. Server-side fields (id, timestamps, ownership) are filled automatically; only fields listed below as creatable are read from the body.

curl -H "Authorization: Bearer pat_…" \
-H "Content-Type: application/json" \
-X POST https://ki-bewerber-management.de/xapi2/data/candidate \
-d '{"name": "…"}'
PATCH/xapi2/data/candidate/{id}candidate:update

Update

Partial update. Only fields included in the body are touched; everything else is preserved. Same allow-list as create, minus the fields that are immutable post-create.

curl -H "Authorization: Bearer pat_…" \
-H "Content-Type: application/json" \
-X PATCH https://ki-bewerber-management.de/xapi2/data/candidate/OBJECT_ID \
-d '{"name": "…"}'
DELETE/xapi2/data/candidate/{id}candidate:delete

Delete

Removes the object. It vanishes from every default list immediately and stops being returned by read / list.

curl -H "Authorization: Bearer pat_…" \
-X DELETE https://ki-bewerber-management.de/xapi2/data/candidate/OBJECT_ID

Use in CLI

The same endpoints are also exposed via the KI BMS CLI. For scripts, CI, and bulk imports it's usually the faster path.

atscli candidate list --limit 5
atscli candidate get <id>
atscli candidate create --name "Hello"
atscli candidate upsert --unique name --csv items.csv
atscli candidate schema # fields & limits

Full command reference, profiles, CSV import, auto-retry, NDJSON streaming → /docs/cli