> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# The skill catalog: the canonical list of skills routing accepts

> How the tenant-owned skill catalog governs skill-based ACD routing — the CRUD endpoints, the validation boundary on queue and agent writes, enforceable certifications, and the proficiency decay policy.

# The skill catalog

Skills drive ACD routing: a queue declares the tags it needs, an agent carries the tags they hold, and the dispatcher only bridges a waiting call onto a member whose skills cover the queue's requirement. That matching only works if every skill label means the same thing everywhere. The skill catalog is the tenant-scoped list of skills that routing accepts — queues and agents are configured against it, so a misspelled tag is rejected at write time instead of silently deadlocking your queue.

Catalog rows scoped to your organization live under one API group, [`/api/v1/voice/skill-catalog`](/api-reference/voice). The dispatcher treats any tag not on the active list as unmatchable, and the write paths treat it as an error. This page covers the validation boundary, the endpoints that manage the list, and the two lifecycle layers on top of it: certifications and proficiency decay.

## 1. Why routing needs a canonical list

Without a catalog, any submitted skill string is accepted into a queue's or agent's `skills[]` array. The dispatcher intersects tags purely on string equality, so a queue that requires `spainsh` never matches an agent tagged `spanish` — the caller waits untouched until overflow routes them out, and nothing raises an error.

The catalog closes that class of failure at the configuration boundary. Define the skill universe once per organization; every queue or agent write that names an unknown tag fails with a 422 validation error. Soft-delete a skill and queued writes that still name it fail the same way. Skills are validated — not attracted through a global list — so each tenant governs its own vocabulary.

## 2. Where the validation boundary sits

Two parts of the write surface check `skills[]` against the active catalog before persisting:

* **Queue configuration** — creating a queue or updating its skill set validates every tag. An unknown or soft-deleted slug returns `422 UNKNOWN_SKILL` with the rejected tags named in the error, and the queue is not written.
* **Agent skill assignment** — updating an agent's skill list applies the same check, so a typo never reaches the dispatcher's eligibility filter.

A queue or agent with an empty `skills[]` array is valid — it is the wildcard "any skill" membership the dispatch model describes (see [The ACD queue model](/concepts/acd-queue-model)). The gate only rejects unknown tags, never an empty list.

The error response identifies the exact rejected tags (capped at ten in the message, with the full set in the error details) so the setup toast or API client can name them inline:

```json theme={null}
{
  "code": "UNKNOWN_SKILL",
  "message": "These skills are not registered in this tenant's skill catalog: spainsh. Register them in the skill catalog before assigning them to a queue or agent."
}
```

If you see a 422 when saving a queue or an agent's skills, register the missing tag in the catalog (or fix the spelling) and retry.

## 3. Managing the catalog

Four endpoints under `/api/v1/voice/skill-catalog`:

| Method   | Path                              | What it does                                                                                                                                                                                             |
| -------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET`    | `/api/v1/voice/skill-catalog`     | List skills, ordered by slug. `?includeInactive=true` also returns soft-deleted rows for the admin view.                                                                                                 |
| `POST`   | `/api/v1/voice/skill-catalog`     | Create a skill: `slug` (lowercase ASCII letters, digits, `_`, `-`; normalized lowercase), `label`, optional `description`. Returns 201. A duplicate active slug returns 409.                             |
| `PATCH`  | `/api/v1/voice/skill-catalog/:id` | Edit `label`, `description`, or flip `isActive`. At least one field is required; `description: null` clears the field.                                                                                   |
| `DELETE` | `/api/v1/voice/skill-catalog/:id` | Soft-delete: the row is kept for analytics and audit and flagged inactive. Routing accepts a re-created row with the same slug because only active rows occupy the (organization, slug) uniqueness slot. |

Example — register a skill:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/skill-catalog \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"slug": "spanish", "label": "Spanish", "description": "Spanish-language support"}'
```

The catalog answers the softphone autocomplete and the queue + agent edit forms on every page load, so list reads are cheap and the tag set stays consistent across the operator surfaces. Create, edit, and soft-delete actions are recorded in the audit log with the previous and next values.

## 4. Skill certifications — enforceable windows

Certifications put a time bound on a skill membership: regulated queues (HIPAA handling, financial-services licensing, insurance producer lines) must only dispatch to agents whose certification for the required skill is still current.

The endpoints under `/api/v1/voice/skill-certifications`:

| Method   | Path                                     | What it does                                                                                                                                  |
| -------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET`    | `/api/v1/voice/skill-certifications`     | List and filter certification windows — the supervisor's "who's about to expire" sweep.                                                       |
| `POST`   | `/api/v1/voice/skill-certifications`     | Issue or renew a certification. One active row per (agent, skill) pair — a renew overwrites the window. `certifiedUntil: null` never expires. |
| `PATCH`  | `/api/v1/voice/skill-certifications/:id` | Extend or amend the window.                                                                                                                   |
| `DELETE` | `/api/v1/voice/skill-certifications/:id` | Revoke: lapse the window immediately so the agent falls out of eligibility for queues that require the skill at the next dispatch.            |

Every certification names a skill that must already exist in the catalog — a certificate for an unregistered slug is meaningless, so it is rejected with the same 422 the queue and agent writes raise. Certify the tag, then configure certification.

## 5. Proficiency decay — skill atrophy as a policy

Agents carry a 1–5 proficiency level per skill. If a proficiency decays — an agent sits off-shift or rotates to other queues — the skill's routing weight should fall below its certified peak until the agent is recertified. The decay policy automates that: a scheduled sweep reads the tenant policy and steps each drifting level down through configurable bands.

Read the current policy with `GET /api/v1/voice/skill-proficiency-decay` and replace it with `PUT` on the same path:

```json theme={null}
{
  "enabled": true,
  "bands": [
    { "remainingFractionAtMost": 0.5, "cap": 4 },
    { "remainingFractionAtMost": 0.25, "cap": 3 },
    { "remainingFractionAtMost": 0.1, "cap": 2 }
  ],
  "exemptSkills": ["hipaa"]
}
```

* **`enabled`** — opt-in toggle, default off. Nothing decays until you turn it on.
* **`bands`** — the step-down schedule. When a level's remaining fraction of its validity window falls at or below a band bound, its cap applies. Omit `bands` to use the defaults shown on GET.
* **`exemptSkills`** — slugs the sweep never decays (regulated skills whose proficiency must stay pinned at the certified level).

Recertifying the skill restores the agent's full level; the sweep only ever lowers a level, never raises one. A malformed policy stored by an older client falls back to the safe defaults rather than decaying everything.

## 6. Dashboard surfaces

The catalog is managed from the dashboard under **Voice → Skill catalog**: register tags, edit labels, and soft-delete from one screen; the same list feeds the queue and agent skill pickers so operators can only pick registered tags. Certification windows are tracked on the sibling voice surfaces, and the decay policy's current values are returned by the GET endpoint above.

The dispatch-time effects of skill configuration — eligibility filtering, minimum levels, wildcard membership — are modelled on [The ACD queue model](/concepts/acd-queue-model); the setup walk-through lives on the [voice queues guide](/guides/voice-queues).
