# How matching works

Fivexer continuously matches **tasks** to **workers** based on tags, skills, priority, and business rules. Unlike queue-based routers, there are no static queues — matching is declarative and reruns every time something changes.

## Core entities

- **Task** — a unit of work (ticket, case, job). It carries `tags`, an optional `priority`, geo constraints, and rich data (context, comments, attachments).
- **Worker** — an agent or automaton that can accept tasks. Workers carry `tags`, skills with proficiency, availability status, and a tentative queue of matched tasks.
- **Decision** — the platform's explainable match record: who was considered, who won, and why.

## Matching lifecycle

1. A task is created with `POST /tasks`. Its status is `queued`.
2. The matcher evaluates every available worker against the task's tags and constraints.
3. The best worker(s) receive the task in their **tentative queue** (`GET /workers/{id}/queue`).
4. The platform emits a `task.matched` webhook.
5. The worker (or an operator) calls `POST /tasks/{id}/accept` to move it to `accepted`, or `reject` to requeue it.
6. When done, `POST /tasks/{id}/complete` finishes the task.

## What decides the winner

- **Tag overlap** — task tags must be satisfied by the worker's tags/skills.
- **Priority** — higher-priority tasks are matched first.
- **Hard vetoes** — rules you define can forbid a match regardless of score (e.g., "agent_1 cannot take billing tasks on Fridays").
- **Fairness mode** — choose whether to prefer first-come, best-match, balanced load, or spread-work.
- **Learning layer** — optional feedback-driven weights that retune themselves from real outcomes.

To see the exact reasoning for any task, call `GET /decisions?taskId=...`.
