Quick Summary: An assignment links a person to a career at a level. Assigning grants that level’s learnings and attaches the career’s skills; unassigning records career history first, so a person’s past careers remain readable.
The assigned person
Returned byGET /api/v1/careers/{id}/people.
The two dates have different owners.
assignedAt is stamped by SkillsDB at the moment of the write and cannot be supplied; initiationDate is yours, and records when the person actually begins in the career.The person’s career
Returned byGET /api/v1/people/{personId}/careers. Previous (ended) assignments are included by default — pass ?includePrevious=false to exclude them.
The distribution
Returned byGET /api/v1/careers/{id}/distribution. Counted server-side — do not page through the assigned-people list to derive these numbers.
Each bucket is
{ id, label, count }, where id is null for the catch-all bucket (for example No Flag).
A credential bound to a manager sees only their span of control, so these counts reflect what the acting person is permitted to see — not necessarily the whole company.
Two rules that surprise integrations
Assigning is never an update.POST /api/v1/careers/{id}/people takes a list of people, each at their own level. Anyone already holding the career is skipped silently — no error, and no level change. If you need to move someone, use PATCH /api/v1/careers/{id}/people/{personId}; an integration that re-assigns expecting a correction will do nothing at all.
Assigning fans out. Beyond the assignment row, it grants every learning attached to the target level and attaches the career’s skills to the person. One call against a hundred people is a large write, not a small one — budget it against your rate limit.
Both assign and unassign accept at most 500 people per call — a larger array is rejected with a 400 validation-error before anything is written, so split bigger batches into chunks.