Skip to main content

Hire an AI Employee

Hire a published AI Employee for a brand. The hire is created immediately and the agent is provisioned in the background — there is no payment step in this flow.

POST /api/v1/employees/{profile_id}/hire

profile_id is the UUID of a published catalog profile (an "AI Employee").

Who can call it​

The same endpoint serves two callers. The endpoint detects which one you are from your credentials.

Active-brand self-serve. A signed-in brand user hires for their own brand. The brand must have an active subscription. The brand is always taken from your session — you cannot hire on another brand's behalf.

Admin grant. A platform super-admin grants a hire for any brand, optionally recording a reason (for a comped / free hire). Authenticate with an admin API key (X-Admin-Key) or an admin dashboard session, and name the target brand in the body.

Request​

Self-serve​

The body is empty — the brand comes from your session.

curl -X POST https://api.opvs.ai/api/v1/employees/$PROFILE_ID/hire \
-H "Cookie: $SESSION_COOKIE" \
-H "Content-Type: application/json" \
-d '{}'

Admin grant​

curl -X POST https://api.opvs.ai/api/v1/employees/$PROFILE_ID/hire \
-H "X-Admin-Key: $OPVS_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"brand_id": 11, "comp_reason": "Beta partner — comped"}'

Body fields​

FieldTypeNotes
brand_idintegerAdmin only, required. The brand to hire for. Ignored on the self-serve path.
comp_reasonstringAdmin only, optional. Rationale for a comped hire. Ignored on the self-serve path.

Response​

{
"hire_id": "f1e2d3c4-0000-4444-8888-aaaabbbbcccc",
"status": "provisioning",
"onboarding_url": "/dashboard/agents/onboarding?hire=f1e2d3c4-0000-4444-8888-aaaabbbbcccc"
}

The hire starts in provisioning. The agent (marketplace skills installed, persona deployed) is built out-of-band; poll the hire or open onboarding_url to watch it become active.

Status codes​

CodeMeaning
200Hire created; provisioning started.
401Not authenticated.
402Self-serve path: the brand's subscription is not active. Ask an admin to grant the hire, or activate a subscription.
404No published employee with that profile_id.
409This brand already holds an active hire of this employee. The body's detail.existing_hire_id points at it.
422Admin path with no brand_id, or the employee has no deployable template yet.
429Rate limit exceeded (5 hires/brand/hour self-serve, 50 grants/admin/hour).

Cancel a hire​

Two endpoints end a hire. They differ in when it ends, and in how much of the agent actually goes away.

POST /api/v1/employees/hires/{hire_id}/cancel
POST /api/v1/employees/hires/{hire_id}/cancel-immediate

An admin may cancel any hire; a brand user may cancel only a hire their own brand holds.

Cancel at period end​

The agent keeps running until current_period_end. Nothing is disabled at call time — the reconcile loop performs the marketplace disable once the date passes.

{
"hire_id": "f1e2d3c4-0000-4444-8888-aaaabbbbcccc",
"status": "canceled",
"cancel_at_period_end": true,
"effective_at": "2026-10-07T00:00:00Z",
"marketplace_disable_at": "2026-10-07T00:01:00Z"
}

Cancel immediately​

The hire flips to canceled now and its marketplace installs are ref-counted disabled: an install turns off only if no other active hire of the same brand still references it. Tools disappear within the gateway's 60-second grant-cache TTL, which is why marketplace_disable_at is a minute after effective_at.

{
"hire_id": "f1e2d3c4-0000-4444-8888-aaaabbbbcccc",
"status": "canceled",
"effective_at": "2026-09-07T12:00:00Z",
"marketplace_disable_at": "2026-09-07T12:01:00Z",
"installs_disabled": 2,
"installs_retained": 1,
"management_record_deleted": true,
"gateway_entry_removed": false,
"agent_torn_down": false
}

Read the teardown fields separately​

Cancelling revokes an employee's tools. It does not unregister the agent.

FieldMeaning
management_record_deletedThe agent's config.yaml entry and workspace directory were removed. Best-effort.
gateway_entry_removedWhether the gateway's own registration was removed. Always false from a cancel — removing it needs a separate call plus a gateway restart, which a cancel deliberately does not perform.
agent_torn_downDeprecated. Always false. Read the two fields above instead.

While gateway_entry_removed is false, the persona stays reachable and can still be messaged, with its marketplace tools disabled. If you are cancelling in order to stop an agent answering, cancelling is not sufficient on its own.

agent_torn_down previously returned true on the Management API delete alone, reporting a teardown that had not happened. It now means what it says: true only when the agent is fully gone, which a cancel cannot achieve.

Status codes​

CodeMeaning
200Cancelled.
401Not authenticated.
403The hire belongs to another brand.
404No such hire.
409The hire is not in a state that can be cancelled.