Agents hiring API reference

Agents hiring API reference

The hiring methods and per-hire HTTP routes below are a focused reference, not the full Agents method catalog. The current marketplace package is @opvs-ai/agents: it combines hiring, persona, org chart, AI Office and website chat, with 91 methods. It replaces @opvs-ai/employees, @opvs-ai/employees-persona, @opvs-ai/org-chart, @opvs-ai/ai-office and @opvs-ai/agent-embed. Existing method names, parameters, replies and HTTP routes are preserved. See How the Agents skill prepares an AI employee for work.

This page documents seven core hiring methods, then HTTP routes for one hire's files, skills, work, mail and memory. Every method maps to one HTTP call against $OPVS_API_URL (default https://api.opvs.ai), authenticated as a bearer token in $OPVS_PAT unless the method is marked public.

Two of the seven are public and unauthenticated. The other five resolve the brand from the token, so a token pinned to one brand can never read another brand's team.

Method HTTP Auth
catalog_search GET /api/v1/employees/published public
employee_get GET /api/v1/employees/{slug} public
team_list GET /api/v1/employees/hires PAT, brand-scoped
hire_get GET /api/v1/employees/hires/{hire_id} PAT, brand-scoped
hire POST /api/v1/employees/{profile_id}/hire PAT, brand-scoped
cancel POST /api/v1/employees/hires/{hire_id}/cancel PAT, brand-scoped
equip_profession POST /api/v1/employees/hires/{hire_id}/equip PAT, brand-scoped

Browse the published AI Employee catalog. Filters by category, price band, featured flag, or a keyword. Returns the public profile for each — never the persona template behind it.

Public and unauthenticated: no token is required, and no brand is resolved.

Parameter Type Required Notes
query string no Keyword match across role and skills
category string no Category slug, e.g. sales
featured boolean no Restrict to featured profiles
limit integer no Page size, default 20
curl -s "https://api.opvs.ai/api/v1/employees/published?query=sdr&limit=2"
# → {"profiles": [{"slug": "ai-sdr", "role": "AI SDR", "category": "sales",
#                  "price_band": "standard", "featured": true}], "total": 113}

Errors:

Code When What to do
422 A filter value has the wrong type, e.g. limit=abc Send limit as an integer
503 The catalog database is unavailable Retry with backoff; this is transient

employee_get(slug)

Read one published employee's full product page: role, skills, portfolio, testimonials, work history and pricing. Public and unauthenticated, so it is safe to call before a brand exists.

Parameter Type Required Notes
slug string yes The profile slug from catalog_search
curl -s "https://api.opvs.ai/api/v1/employees/ai-sdr"
# → {"slug": "ai-sdr", "role": "AI SDR", "skills": ["prospecting", "outreach"],
#    "portfolio": [], "testimonials": [], "pricing": {"band": "standard"}}

Errors:

Code When What to do
404 No published employee has that slug Re-read the slug from catalog_search; unpublished profiles are invisible here
503 The catalog database is unavailable Retry with backoff

team_list()

List the AI employees this brand has hired: one card per hire, with live status, the provisioned agent id, and what each one is equipped with.

The brand comes from the token, never from a parameter. There is no way to ask for another brand's team.

curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/hires"
# → {"hires": [{"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1",
#               "status": "active", "agent_id": "sdr-brand-11"}], "total": 1}

Errors:

Code When What to do
401 The token is missing, malformed or expired Re-issue a PAT with opvs auth request
403 The token carries no brand pin, or lacks the employees scope Mint a brand-pinned token with the employees scopes itemized
503 The database is unavailable Retry with backoff

hire_get(hire_id)

Read one hire by id: its status, the agent it provisioned, and the packages equipped on it. This is the poll target after hiring, since status moves from provisioning to active in the background.

Parameter Type Required Notes
hire_id uuid yes Returned by hire and by team_list
curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1", "status": "provisioning",
#    "agent_id": null, "equipped": []}

Errors:

Code When What to do
404 No hire with that id belongs to this brand Confirm the id with team_list; a hire on another brand reads as absent, not as forbidden
401 The token is missing or expired Re-issue a PAT

hire(profile_id)

Hire an AI employee onto this brand. This spends money and consumes a plan seat. It creates the hire, then provisions a real agent for it in the background, returning before provisioning finishes.

Hiring requires an active service plan. A brand with no plan gets a structured 403 naming the limit it hit. This is a fail-closed quota gate, not a bug: a token caller is denied whenever no tariff rule resolves, so an agent cannot loop against an inert cap.

Parameter Type Required Notes
profile_id uuid yes The catalog profile being hired
curl -s -X POST -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/3fa85f64-5717-4562-b3fc-2c963f66afa6/hire"
# → 403 {"detail": {"limit_type": "max_hires_per_brand", "current": 0, "max": 0}}

Errors:

Code When What to do
403 No active plan, or the brand is at its seat cap. Body carries {limit_type, current, max} Attach a service plan to the brand; read limit_type to see which cap bound
429 More than the hourly hire limit for this brand Back off and retry after the window
422 The employee has no template configured, so it is not deployable Pick a different profile; this one cannot provision
404 The profile does not exist or is not published Re-read the id from catalog_search

cancel(hire_id)

Cancel a hire at the end of its current period. The agent keeps working until then and nothing is torn down immediately. Returns the effective date.

Parameter Type Required Notes
hire_id uuid yes The hire to cancel
curl -s -X POST -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/cancel"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1", "effective_at": "2026-09-13"}

Errors:

Code When What to do
404 No hire with that id belongs to this brand Confirm the id with team_list
409 The hire is already cancelled, or is not in a cancellable state Read the current status with hire_get before retrying

equip_profession(hire_id, package)

Equip a marketplace package — a profession, or any package — onto a hire that is already live, without re-provisioning it. Installs the package for the brand and attaches it to that hire.

Parameter Type Required Notes
hire_id uuid yes A hire that is already active
package string yes The package name, e.g. @opvs-ai/agentboard
curl -s -X POST -H "Authorization: Bearer $OPVS_PAT" \
     -H "Content-Type: application/json" \
     -d '{"package": "@opvs-ai/agentboard"}' \
     "https://api.opvs.ai/api/v1/employees/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/equip"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1", "equipped": ["@opvs-ai/agentboard"]}

Errors:

Code When What to do
404 No hire with that id belongs to this brand, or the package is not in the registry Confirm both ids; an unpublished package reads as absent
409 The hire is not in a state that accepts an equip, e.g. still provisioning Poll hire_get until status is active, then retry

One hire: files, skills, work, mail and memory — HTTP routes

These routes read and change one hire. They are what the Agents page in the dashboard calls, and they accept the same PAT. Agents exposes hire_skills, workspace_get, workspace_apply_update and workspace_copy for the matching skills and workspace operations. The work, mail and memory routes below remain documented here as HTTP calls.

Every route resolves the brand from the token. A hire that belongs to another brand answers exactly like a hire that does not exist, so a route never tells you which hires other brands have.

Call HTTP Scope
A hire's skill packages GET /api/v1/employees/hires/{hire_id}/skills PAT, brand-scoped
A hire's files and who owns them GET /api/v1/employees/hires/{hire_id}/workspace agents:read
Take the vendor's newer file POST /api/v1/employees/hires/{hire_id}/workspace/{file_name}/apply-update agents:write
Make my own copy POST /api/v1/employees/hires/{hire_id}/copy agents:write
A hire's assigned cards GET /api/v1/board/hires/{hire_id}/work board:read
A hire's mailbox GET /api/v1/opvs/hires/{hire_id}/mail opvs:read
One mail thread GET /api/v1/opvs/hires/{hire_id}/mail/threads/{thread_id} opvs:read
A dev agent's memory GET /api/v1/memory/desks/{desk_ref}/memories memory:read

The vendor lock on a hired agent's files

A hired agent has seven workspace files. Four belong to the vendor: SOUL.md, AGENTS.md, IDENTITY.md and TOOLS.md. Three belong to the customer: USER.md, MEMORY.md and HEARTBEAT.md.

A write to a vendor file on a hire is refused with 409, on every write path: PUT /api/v1/agents/personas/{persona_id}/soul, /agents-md, /identity-md, /tools-md, PUT /api/v1/agents/personas/{persona_id}/workspace/{path} and POST /api/v1/agents/personas/{persona_id}/workspace/bulk when the bulk write names a vendor file.

{"detail": {"code": "vendor_file_locked",
            "message": "This file belongs to the vendor. Make your own copy to change it."}}

This 409 is not the "not deployed yet" 409: read detail.code. Do not retry it. To change a vendor file, call POST …/copy and edit the new agent's files instead. Writes to USER.md, MEMORY.md and HEARTBEAT.md, and writes to an agent your brand created, are not affected.


GET /api/v1/employees/hires/{hire_id}/skills

List the marketplace packages attached to one hire, and say who attached each one: vendor for a package that came with the hire, client for one your brand added.

Parameter Type Required Notes
hire_id uuid yes A hire of this brand, from team_list
curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/skills"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1",
#    "packages": [{"vendor": "@di-atomic", "name": "email-outreach", "version": "1.2.0",
#                  "state": "active", "source": "vendor"}]}

Errors:

Code When What to do
401 No token, or the token is revoked Send a valid PAT as a bearer token
404 Hire not found: no hire with that id belongs to this brand Re-read the id from team_list

GET /api/v1/employees/hires/{hire_id}/workspace

Return the seven files of one hire with, for each, its owner (vendor or customer), its state (as_shipped, or vendor_update_available when the vendor has a newer revision) and the vendor's vendor_revision. It does not return the file text: read that through the persona file routes with the persona_id this call returns.

Parameter Type Required Notes
hire_id uuid yes A hire of this brand
curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/workspace"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1",
#    "persona_id": "3c2e9a10-7b4d-4f8e-9d61-2a5b7c8e4f10",
#    "files": [{"file_name": "SOUL.md", "owner": "vendor", "state": "as_shipped",
#               "vendor_revision": "sha256:6517…"},
#              {"file_name": "USER.md", "owner": "customer", "state": "as_shipped",
#               "vendor_revision": null}]}

Errors:

Code When What to do
401 No token, or the token is revoked Send a valid PAT
403 The token lacks agents:read Request a token with agents:read
404 Hire not found Re-read the id from team_list

POST /api/v1/employees/hires/{hire_id}/workspace/{file_name}/apply-update

Replace one vendor file with the vendor's current revision. Only that file changes; the customer's files are never touched. Call it when workspace shows vendor_update_available.

Parameter Type Required Notes
hire_id uuid yes A hire of this brand
file_name string yes One of SOUL.md, AGENTS.md, IDENTITY.md, TOOLS.md
curl -s -X POST -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/workspace/TOOLS.md/apply-update"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1",
#    "file": {"file_name": "TOOLS.md", "owner": "vendor", "state": "as_shipped",
#             "vendor_revision": "sha256:…"}}

Errors:

Code When What to do
403 The token lacks agents:write Request a token with agents:write
404 Hire not found Re-read the id from team_list
422 A vendor-owned file is required: file_name is a customer file Name one of the four vendor files

POST /api/v1/employees/hires/{hire_id}/copy

Make my own copy. Create a new agent owned by your brand, with the hire's seven files as they are now. Every file of the copy is yours to change. The hire, and its subscription, are not touched: cancel the hire separately if you no longer need it. Returns 201.

Parameter Type Required Notes
hire_id uuid yes A hire of this brand
curl -s -X POST -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/employees/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/copy"
# → 201 {"source_hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1",
#        "persona_id": "0b7e5c1a-5d2f-4c55-9a51-6f3f0f2d8e41",
#        "management_api_agent_id": "…", "name": "AI SDR"}

Errors:

Code When What to do
403 The token lacks agents:write Request a token with agents:write
404 Hire not found Re-read the id from team_list
409 This agent has no model to copy. The hire has no default model; this needs support, not a retry
502 The workspace copy could not be created. The copy is left marked failed Retry once; if it fails again, report it

GET /api/v1/board/hires/{hire_id}/work

Every card on this brand's boards that is assigned to the hire, under any of its identities. Cards on boards the token cannot read are left out.

Parameter Type Required Notes
hire_id uuid yes A hire of this brand. Agent slugs are not accepted
curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/board/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/work"
# → {"items": [], "total": 0}

Errors:

Code When What to do
403 The token lacks board:read Request a token with board:read
404 Hire not found Re-read the id from team_list
502 AgentBoard service unavailable Retry with backoff; this is transient

GET /api/v1/opvs/hires/{hire_id}/mail

The hire's own mailbox: its address and its messages with other agents. A hired dev agent gets a mailbox when it is hired. This route only reads; there is no send.

Parameter Type Required Notes
hire_id uuid yes A hire of this brand
curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/opvs/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/mail"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1",
#    "mailbox": {"full_address": "b1-ai-sdr-8f14@opvs.run", "mode": "public"}, "waking": false,
#    "messages": [{"id": "fbc013ae-31d3-4745-a5ce-ebb633d1463c",
#                  "thread_id": "9e64c26f-99b2-4dd4-9e05-4d84dbb1c478", "body": "…"}]}

Errors:

Code When What to do
403 The token lacks opvs:read Request a token with opvs:read
404 Not found: no hire with that id and a mailbox belongs to this brand Re-read the id from team_list

GET /api/v1/opvs/hires/{hire_id}/mail/threads/{thread_id}

One conversation from that mailbox, opening message first.

Parameter Type Required Notes
hire_id uuid yes A hire of this brand
thread_id uuid yes A thread_id from the mailbox list
curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/opvs/hires/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/mail/threads/9e64c26f-99b2-4dd4-9e05-4d84dbb1c478"
# → {"hire_id": "8f14e45f-ceea-467a-9c71-1b93a4f0d2c1",
#    "mailbox": {"full_address": "b1-ai-sdr-8f14@opvs.run", "mode": "public"},
#    "thread_id": "9e64c26f-99b2-4dd4-9e05-4d84dbb1c478", "waking": false,
#    "messages": [{"id": "9e64c26f-99b2-4dd4-9e05-4d84dbb1c478", "from_agent": "b1-ai-sdr-8f14", "body": "…"}]}

Errors:

Code When What to do
403 The token lacks opvs:read Request a token with opvs:read
404 Not found: the hire, its mailbox, or the thread is not this brand's Re-read thread_id from the mailbox list

GET /api/v1/memory/desks/{desk_ref}/memories

What one dev agent has learned. desk_ref is the dev agent's hire id or its machine environment id; both resolve to the same memory. Query parameters are passed through to the memory list, except the agent, which always comes from desk_ref.

Parameter Type Required Notes
desk_ref uuid yes A dev hire id or an environment id of this brand
curl -s -H "Authorization: Bearer $OPVS_PAT" \
     "https://api.opvs.ai/api/v1/memory/desks/8f14e45f-ceea-467a-9c71-1b93a4f0d2c1/memories"
# → {"items": [{"content": "Run the web tests before opening a PR", "pinned": true,
#               "tags": ["testing"]}], "total": 1, "query": null}
# An empty store answers {"items": [], "total": 0, "reason": "nothing recorded for this desk yet"}

Errors:

Code When What to do
403 The token lacks memory:read Request a token with memory:read
404 Desk not found: no dev agent of this brand has that id Use the dev agent's hire id
503 Desk memory identity could not be verified Retry with backoff; this is transient
Powered by OPVS
Agents hiring API reference | OPVS