Quick Summary: Every change to the public REST API lands here with a date. Inside v1 every entry is additive — nothing here ever breaks an existing integration.
2026-09-02 — Pre-launch fixes, person skills, and skill retirement (pre-release)
Still ahead of the first public release, so the corrections below land before any integration can depend on the old shapes. Added- Additional skills:
GET/POST/DELETE /people/{personId}/skills— assign existing catalogue skills directly to a person, list them, remove them. This closes the gap where recording a training required an assignment the API could not create. Carriesskills:read/skills:write. - Skill retirement and delete:
POST /skills/{id}/archiveand/unarchive(reversible;isArchivednow on the Skill object), andDELETE /skills/{id}— a soft delete guarded by a 409 with dependency counts and a?confirm=trueremedy, matching the app’s library semantics. - Org value delete:
DELETE /org/{dimension}/{id}— removes a dimension value outright, completing the create/deactivate/delete story for all eleven dimensions. Guarded the same way: a 409 with dependency counts when people hold the value and a?confirm=trueremedy that removes the memberships; a value referenced by records outside the API (assessments, surveys, saved views) stays undeletable — deactivate it instead. - Scopes in the specification: every operation now declares its required
scopes machine-readably (
securityarray andx-required-scopes), and the security scheme lists the full catalogue — an admin can see exactly which scopes a key needs per endpoint. - A new
method-not-allowed(405) problem type: a wrong verb on a real path is now distinguishable from a wrong path, and lists the allowed methods.
- One name per concept across request bodies:
PATCH /people/{id}/access-leveltakesaccessLevel(previouslylevel, whilePOST /peoplealready saidaccessLevel); career sections and skill groups usenameon both create and read (previouslytitle— whilePOST /careerssaidname). - Flag names are capped at 100 characters (previously the contract said 200 while storage allowed 100 — the create appeared to work and then failed).
- Every response from any
/api/v*path is now an RFC 9457 problem document — including URL typos, unknown versions (410version-gone), and wrong verbs (405). No raw framework error body is reachable. - Three scopes with no endpoints behind them yet (
assessments:read,certifications:read,certifications:write) are no longer grantable; they return when their resources ship.
2026-08-31 — Contract corrections and security hardening (pre-release)
The API has not yet had its first public release, so the field renames below land before any integration can depend on the old names. This is the one window in which the contract gets corrected rather than versioned. Changed (pre-release corrections)- One column, one public name: the career-assignment person rows now use
externalIdandemail(previouslyemployeeId/emailAddress) — the same field names as the Person object. The bulk sync request field is likewiseexternalId(previouslyemployeeId), now capped at 20 characters to match what is actually stored. requirement.scopeisallorgoing_forward(previouslygoingForward) — the one enum value that had shipped outside the lowercase-snake convention.GET /people/{personId}/careersnow rejectslimitover 200 andoffsetover 10,000 with a validation error, as the reference always stated.- Malformed ids in career-assignment request bodies are now a
400validation error naming the field, instead of a generic404. - Every create operation is documented as returning
201(what it always did). - The reference now documents the
{data, meta}envelope on every response, every error status with theapplication/problem+jsonshape, the standard response headers (X-Request-Id,RateLimit-*,Idempotency-Replayed), theIdempotency-Keyrequest header on every write, and — on each operation — the scope it requires.
Idempotency-Keystorage is now scoped per credential, not per company: no credential can replay, collide with, or occupy a key another credential used. A retried write is only ever replayed to the credential that made it.- Deactivating a person disables every API credential acting as them on the
very next request — and that
401is now byte-identical to a revoked key’s, disclosing nothing about the acting person’s state. - Person-scoped training, learning-plan, flag and org reads are bounded by the
acting identity’s span of control, exactly like the people directory:
a manager-bound credential reads its span, an out-of-span person is a
404. POST /peopleand the email-change operation return a clean409when the address is already registered elsewhere in SkillsDB (the address is globally unique; the conflict names no holder).GET /org/manager-treeis bounded by the acting identity like every other person-scoped read: admin tiers get the full hierarchy, a manager-bound credential gets its own subtree, an employee-bound credential is refused.GET /skill-groups/{id}/trainer-countand bothrenew-trainingoperations return the uniform404for an id outside your company (previously a200with zero counts).
2026-08-27 — Postman collection
Added- A generated Postman collection covering every endpoint (154 requests across 14 folders). Authentication is Bearer at the collection level (
{{apiKey}}variable) and the common headers are applied by a collection pre-request script, so every request inherits both — import, paste your key once, and play. Bodies come prefilled with working examples; writes carry a one-click optionalIdempotency-Key. Regenerated with the OpenAPI artifact on every contract change.
2026-08-27 — Org structure and hardening
Added- Org structure (objects): the eleven dimensions at
GET|POST /api/v1/org/{dimension}andPATCH /org/{dimension}/{id}(rename or deactivate — values never delete),GET /org/{dimension}/{id}/usageand/people,GET /org/dimensions, andGET /org/manager-tree— the company’s reporting hierarchy as depth-ordered, company-scoped rows. New scopes:org:read,org:write.
- The system-admin bypass header (
nest-admin-secret) is now rejected outright on every/api/v1request — including alongside a valid API key — instead of being ignored. The public API authenticates by API key only.
2026-08-27 — Training data and flags
Added- Training records (object):
GET /api/v1/trainings(filter by person, skill, status, or expiry —expiredOnly=true/expiresWithinDays=N),GET /trainings/{id},GET /trainings/{id}/evidence(time-limited links),POST /trainings(withpreApprovedandnotApplicable),PATCH /trainings/{id}. - Training approval:
GET /training-approvals?status=across every decidable state,POST /trainings/{id}/approve|reject|cancel(reasons required to reject/cancel),GET /trainings/{id}/potential-approvers?expertsOnly=, and per personGET /people/{id}/approval-activity(what they decided — spans superseded records) and/approval-requests(what they submitted). Approver entitlement is evaluated point-in-time and not retained on past decisions. - Renewal:
POST /skills/{id}/renew-training(fans out — bulk bucket) withGET /skills/{id}/renew-training/preview, and the mergedGET /people/{personId}/skills/{skillId}/training-log— live and superseded records together, each flaggedisSuperseded. - Learning plans (object):
GET /people/{id}/learning-plans,GET|PATCH /learning-plans/{id}(due-date and state rules enforced),PUT /learning-plans/{id}/rating(three values, null clears — and only the plan’s owner can rate), andGET|POST|DELETE /learning-items/{id}/people. - Flags (objects) — two independent systems: people flags (CRUD, first-class enable/disable, reorder, dependencies, guarded delete, per-person assignment, the visibility setting) and skill flags (the same plus trainer designation, four-scope assignment at
/skill-flag-assignments/{scope}, andGET /skill-groups/{id}/trainer-count). Disabling a flag hides every existing assignment from reads without deleting anything — stated on the operations because reconciliation breaks otherwise. - New scopes:
training:read,training:write,flags:read,flags:write.
2026-08-27 — People management
Added- Person resource (object):
- Directory:
GET /api/v1/people(bounded by the acting identity’s access level, filterable by name/email/externalId),GET /people/count,GET /people/{id},GET /people/{id}/avatar(a resolved short-lived URL). - Record:
POST /people(creates the authentication identity too; duplicate email → conflict),PATCH /people/{id}— a true partial update: absent means unchanged, explicit null clears. Email, access level, manager, job title and people type each move through their own operation. - Access levels are slugs, never integers (
basic,manager,admin,fullaccess, plus three read-only legacy levels), and a grant can never exceed the acting identity’s own level (403). PATCH /people/{id}/managerrefuses a reporting loop with a conflict naming who and at what depth.- Lifecycle:
POST /people/{id}/deactivate(stamps the inactive date) and/activate. There is no delete — the product’s delete is an irreversible hard delete, so deactivation is the lifecycle operation. - Reporting structure:
GET /people/{id}/direct-reports,GET /people/{id}/span-of-control(subject included at level 0),GET /people/managers?excludeSubtreeOf=,GET /people/distribution. - Org schema:
GET/POST(additive)/DELETE /people/{id}/org-schema, andPUT /people/{id}/org-schema/{dimension}to replace one dimension exactly — the shape an HRIS sync needs.
- Directory:
- Person attributes:
GET|POST|PATCH|DELETE /api/v1/job-titlesand/api/v1/people-types(deletes refuse with a conflict and the holder count while people still hold them),GET /api/v1/access-levels,GET /api/v1/countries.
2026-08-27 — Skills management
Added- Skill resource (object):
GET /api/v1/skills— the company skill library, filterable bynameanddescription. Each entry carries itsusage: every career that includes it (attached directly or under a section, Required or not), how many people hold it, and whether any career including it has training dates enabled.GET /api/v1/skills/{id}— one skill: name, description, and whether it is a certification.POST /api/v1/skills/PATCH /api/v1/skills/{id}— create and update map exactlynameanddescription. There is deliberately no delete — no such operation exists in the product.GET /api/v1/skills/{id}/people— everyone who holds the skill, directly or through a career that includes it. Respects span of control.GET /api/v1/skills/{id}/versions— name/description snapshots with editor, date, change note and the baseline marker.GET /api/v1/skills/{id}/activity— a version log, not a change feed: exactly three event types (baseline,version_created,renew_training).
- Skill Request workflow (object):
GET/POST /api/v1/skill-requests,POST /api/v1/skill-requests/{id}/approveand/reject. Approving creates the library skill and assigns it to the requester; deciding an already-decided request returns a conflict.
- The career definition no longer carries certifications (
GET /api/v1/careers/{id}/certificationsand thecertificationsarray were removed) — certification data gets its own resource in a later release. - A career skill’s requirement fields were restructured into a single stored-configuration object:
requirement: { isRequired, scope, effectiveFrom, setBy }.scopeisallorgoing_forward. See the Career object for why this is a configuration, never a resolved boolean.
Both changes land before the API’s first general release, while no integration can depend on the old shape. After GA, changes of this kind would ship in a new major version instead.
2026-08-25 — Bulk people sync
AddedPOST /api/v1/bulk/people— create-or-update up to 500 people in one call, matched by email within your company. SetisActive: falseto deactivate (a soft delete: the person and their history are retained).
200 whenever it was processed — read each record’s status (created, updated, deactivated, failed) and the summary, not the HTTP code. One bad record never fails the rest of the batch.
Two things to design your sync around. Send an
Idempotency-Key — this is the endpoint where a retry matters most; a replayed request returns the original response instead of double-creating. And email addresses are unique across SkillsDB, not per company: an address already registered to another organization is reported as a failed record rather than silently attaching to it.2026-08-25 — Career assignment
Added- Career assignment: who holds a career, and the operations that change it.
GET /api/v1/careers/{id}/people— everyone holding the career, with their level, the server-stampedassignedAtand the caller-suppliedinitiationDate.GET /api/v1/careers/{id}/distribution— headcount grouped by level and by people-flag, aggregated server-side. A manager sees only their span of control.GET /api/v1/people/{personId}/careers— every career a person holds or previously held, each markedisPrevious. Previous assignments are included by default; pass?includePrevious=falseto exclude them.POST /api/v1/careers/{id}/people— assign people, each at their own level, with an optionalinitiationDate. Assigning is never an update: anyone already holding the career is skipped and their level is left unchanged.PATCH /api/v1/careers/{id}/people/{personId}— the only way to move someone between levels of a career they already hold.DELETE /api/v1/careers/{id}/people— unassign people. Career history is recorded before the live assignment is removed, so the career reappears on the person markedisPrevious.DELETE /api/v1/people/{personId}/careers— clear every career one person holds, in a single call. Scoped to the named person.
Two behaviours worth designing around. Assigning fans out: beyond the assignment row it grants the learnings attached to the target level and attaches the career’s skills, so one call against many people is a large write — budget it against your rate limit accordingly. Re-assigning will not correct a level: an integration that assumes it does will silently do nothing; use the change-level operation.
2026-08-20 — v1 initial surface
Added- Authentication and platform: API keys (
Authorization: Bearer sdb_live_...) with scopes, acting-person binding, rotation with overlap, immediate revocation.GET /api/v1/pingconnectivity check. RFC 9457 problem+json errors with the error catalogue.X-Request-Idon every response.RateLimit-*headers (measurement mode).Idempotency-Keysupport on writes. Unauthenticated spec downloads at/api/v1/openapi.jsonand/api/v1/openapi.yaml. - Career resource: list/get/create/update/delete (dependency-guarded with
?confirm=true), full definition read, levels, sections, skill groups, skills with per-level activation and resolved benchmarks, learnings, certifications, settings (with the assessments-requires-proficiency rule), and the activity feed. - Career Type resource: list/get/create/update/delete (delete refuses while in use).
- Grading Scale: read-only company scale — the rungs all benchmarks reference.