Workspace settings

How-toUpdated 12 min read
View as Markdown
On this page

The calls behind Settings in the dashboard: which optional features a workspace uses, the people in it, your own OPVS address, and updates for your machines. The dashboard uses the same routes. For what each settings page does, see Settings: where each setting lives.

Before you call

Every route takes a personal access token, Authorization: Bearer $OPVS_PAT, and acts on the workspace the token belongs to. {brand_id} in a path must be that same workspace.

Group

Who may call

Token scope

Read feature switches

any active member

brand:read

Change a feature switch, members and guests

a workspace admin

brand:admin

Your OPVS address

the token's own person

any

Machine updates

a workspace admin

any

brand:read is in every workspace's default scope ceiling. brand:admin is not: a platform admin has to widen your workspace's policy first (see Authentication). Without it, make these changes in the dashboard.

A token that lacks a route's scope gets 403 with a detail that names the missing scope and says whether your workspace allows it.

Feature switches

A workspace has four optional features: skills, feed, machines and crm. Turning one off hides it from the dashboard and deletes nothing. See Turn a feature on or off.

GET /api/v1/brands/{brand_id}/features

Returns every switch with its current state and what the feature holds.

curl "https://api.opvs.ai/api/v1/brands/1/features" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200, application/json (two of the four switches shown)
# {"new_navigation": true,
#  "switches": {
#    "skills": {"on": true, "locked_by_plan": false, "source": "data_default",
#               "changed_by": null, "changed_at": null,
#               "holds": {"installed_packages": 59}},
#    "feed":   {"on": true, "locked_by_plan": false, "source": "data_default",
#               "changed_by": null, "changed_at": null,
#               "holds": {"feed_sources": 8}}}}

# Without a token the route returns a 401 error.

Add ?format=yaml or ?format=md for a smaller answer.

Response

Field

Type

Meaning

new_navigation

boolean

Whether the workspace uses the current sidebar and Settings

switches.<key>.on

boolean

Whether the feature is on

switches.<key>.locked_by_plan

boolean

true when the plan does not include the feature; it cannot be turned on

switches.<key>.source

string

Why it has this value: plan_default, data_default (the workspace already had data for it) or admin (an admin set it)

switches.<key>.changed_by

object or null

{user_id, name} of the admin who last set it

switches.<key>.changed_at

string or null

When an admin last set it

switches.<key>.holds

object

Counts of what the feature holds, such as installed_packages, feed_sources, machines or crm_boards

Errors

Status

When

Resolution

401

no token, or the token is not valid

send Authorization: Bearer $OPVS_PAT with a live token

403

the token lacks brand:read

request a token with brand:read

404 Brand not found

{brand_id} is not a workspace you belong to

use the token's own workspace id

422

format is not yaml or md

drop format, or use one of the two values

PUT /api/v1/brands/{brand_id}/features/{key}

Turns one feature on or off for everyone in the workspace, and returns every switch as it now stands. {key} is skills, feed, machines or crm.

curl -X PUT "https://api.opvs.ai/api/v1/brands/1/features/feed" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"on": false}'

# Response 200: the same shape as GET /features, with
#   switches.feed.on = false, source = "admin" and changed_by naming you.
# A feature your plan does not include returns a 409 error when you turn it on.

Request body: on (boolean, required).

Errors

Status

When

Resolution

401

no token, or the token is not valid

send a live token

403

the token lacks brand:admin

change the switch in the dashboard, or have your workspace's policy widened to allow brand:admin

403 Brand admin access required

you are not an admin of this workspace

ask an admin

404 Brand not found

{brand_id} is not a workspace you belong to

use the token's own workspace id

409 This feature is not included in the workspace plan

turning on a feature with locked_by_plan: true

change plan under Billing & plans first

422

{key} is not one of the four, or on is missing

send one of the four keys and {"on": true} or {"on": false}

Members

Every route in this group needs brand:admin and an admin of the workspace. {user_id} must be an active member.

PATCH /api/v1/brands/{brand_id}/members/{user_id}

Changes a person's role or position in the workspace.

curl -X PATCH "https://api.opvs.ai/api/v1/brands/1/members/482" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"role": "admin", "position": "Head of Sales"}'

# Response 200
# {"success": true}

# Making the only admin a member returns a 409 error.

Request body: role (string, optional): admin or member. position (string, optional): free text; send null to clear it. Send at least one.

Errors

Status

When

Resolution

400 Role must be 'admin' or 'member'

another role value

send admin or member

400 No fields to update

the body has neither field

send role, position or both

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

404 Member not found

the person is not an active member

check {user_id} against Members

409 The last workspace admin cannot be changed to a member

demoting the only admin

make someone else an admin first

POST /api/v1/brands/{brand_id}/members/{user_id}/photo

Uploads a picture for a member. Send the file as multipart field file: PNG, JPG or GIF, up to 5 MB.

curl -X POST "https://api.opvs.ai/api/v1/brands/1/members/482/photo" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -F "file=@portrait.png"

# Response 200
# {"photo": "https://files.opvs.ai/…/portrait.png"}

# A file over 5 MB returns a 400 error.

Errors

Status

When

Resolution

400 File must be PNG, JPG or GIF

another file type

convert the image

400 File too large (max 5MB)

the file is over 5 MB

resize it

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

404 Member not found

the person is not an active member

check {user_id}

503 Image storage not configured

picture storage is unavailable

try again later

DELETE /api/v1/brands/{brand_id}/members/{user_id}/photo

Removes a member's picture.

curl -X DELETE "https://api.opvs.ai/api/v1/brands/1/members/482/photo" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200
# {"photo": null}

# A person who is not an active member returns a 404 error.

Errors

Status

When

Resolution

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

404 Member not found

the person is not an active member

check {user_id}

POST /api/v1/brands/{brand_id}/members/{user_id}/reset-password

Emails the member a link to choose a new password.

curl -X POST "https://api.opvs.ai/api/v1/brands/1/members/482/reset-password" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200
# {"success": true, "message": "Password reset email sent to ada@example.com"}

# If the email cannot be sent the route returns a 502 error.

Errors

Status

When

Resolution

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

404 Member not found

the person is not an active member

check {user_id}

502 Failed to send password reset email

the email could not be sent

try again later

POST /api/v1/brands/{brand_id}/members/{user_id}/set-password

Sets a member's password directly. This works only for a person who belongs to this workspace and no other; for everyone else, send a reset link.

curl -X POST "https://api.opvs.ai/api/v1/brands/1/members/482/set-password" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"password": "correct-horse-battery", "send_email": true}'

# Response 200
# {"success": true, "message": "Password updated for ada@example.com"}

# A person who belongs to another workspace too returns a 409 error.

Request body: password (string, required, at least 8 characters). send_email (boolean, optional, default false): also email the person that their password changed.

Errors

Status

When

Resolution

400 User has no auth account

the person has never signed in with a password

invite them, or send a reset link

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

404 Member not found

the person is not an active member

check {user_id}

409 Send a reset link instead of setting this person's password.

the person is in more than one workspace, or is an OPVS staff or service account

use reset-password

422

password is shorter than 8 characters

send a longer password

502 Failed to set password

the sign-in service did not accept the change

try again later

Guests

A guest is someone outside the workspace who can open some of its boards or docs. Every route here needs brand:admin and an admin of the workspace.

GET /api/v1/brands/{brand_id}/guests

Lists every guest and each board or docs space they can open.

curl "https://api.opvs.ai/api/v1/brands/1/guests" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200
# {"guests": [{"user_id": 913, "email": "sam@example.com", "full_name": "Sam Reyes",
#              "image": null,
#              "access": [{"kind": "board", "resource_id": "6f1c2a7e-3b0d-4c55-9e1a-2d8f4b7c9a10",
#                          "name": "Launch plan", "role": "editor"}]}],
#  "total": 1}

# Without a token the route returns a 401 error.

Response: guests[].access[].kind is board or docs; role is the guest's level on that board or space, or null.

Errors

Status

When

Resolution

401

no token, or the token is not valid

send a live token

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

502 AgentBoard returned an invalid response

the boards service answered badly

try again later

POST /api/v1/brands/{brand_id}/guests/{user_id}/make-member

Invites a guest to join the workspace as a member. Their guest access stays until they accept.

curl -X POST "https://api.opvs.ai/api/v1/brands/1/guests/913/make-member" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 201
# {"id": 2207, "email": "sam@example.com", "status": "pending",
#  "expires_at": "2026-10-22T16:00:00Z", "created_at": "2026-10-15T16:00:00Z"}

# A guest who already has a pending invitation returns a 400 error.

Errors

Status

When

Resolution

400 User is already a member of this brand

the person is already a member

nothing to do

400 An invitation is already pending for this email

an invitation is waiting

wait for them to accept; Settings → Members → Invitations lists it

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

404 Guest not found

the person is not a guest of this workspace

list guests first

DELETE /api/v1/brands/{brand_id}/guests/{user_id}

Removes a guest from every board and docs space in the workspace. Cards, comments and pages they wrote stay.

curl -X DELETE "https://api.opvs.ai/api/v1/brands/1/guests/913" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200
# {"success": true, "boards_removed": 2, "docs_removed": 1}

# A person who is not a guest returns a 404 error.

Errors

Status

When

Resolution

403

the token lacks brand:admin, or you are not an admin

use an admin's brand:admin token

404 Guest not found

the person is not a guest of this workspace

list guests first

502 AgentBoard returned an invalid response

the boards service answered badly

try again later

Your OPVS address

Every person gets an @opvs.run address when they sign up. These routes act on the token's own person.

GET /api/v1/me/mail/address/availability

Checks whether a new name for your address is free. name is 3 to 30 lowercase letters, numbers or hyphens, starting and ending with a letter or number.

curl "https://api.opvs.ai/api/v1/me/mail/address/availability?name=ada-lovelace" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200
# {"name": "ada-lovelace", "domain": "opvs.run", "available": true}

# A name shorter than 3 characters returns a 422 error.

Errors

Status

When

Resolution

401

no token, or the token is not valid

send a live token

404 Not found

the token's person has no OPVS address

none to change

422

name breaks the naming rule

use 3 to 30 lowercase letters, numbers or hyphens

PUT /api/v1/me/mail/address

Changes your address. Mail to the old address is forwarded to the new one for 30 days.

curl -X PUT "https://api.opvs.ai/api/v1/me/mail/address" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"name": "ada-lovelace"}'

# Response 200
# {"address": "ada-lovelace@opvs.run",
#  "forwarding_from": "ada.l@opvs.run",
#  "forwards_until": "2026-11-14T16:00:00Z"}

# A name someone else holds returns a 409 error.

Errors

Status

When

Resolution

404 Not found

the token's person has no OPVS address

none to change

409 This OPVS address is not available

the name is taken, or is still forwarding for someone else

check availability first and pick another name

409 This is already your OPVS address

the name is your current one

nothing to do

409 This mailbox cannot be renamed

the address is not on opvs.run

it cannot be changed

422

name breaks the naming rule

use 3 to 30 lowercase letters, numbers or hyphens

Machine updates

Ask OPVS to update the software on your machines. A request is queued, never run at once: OPVS updates each machine when no build is running on it. Both routes need an admin of the workspace.

POST /api/v1/machines/{machine_id}/updates

Requests an update for one machine.

curl -X POST "https://api.opvs.ai/api/v1/machines/8d2e6b1a-4f3c-4e9a-b7d5-1c0f9a2e3b44/updates" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 202
# {"id": "c1a9e7f0-2b6d-4d38-8e51-7a4b3c2d1e90",
#  "machine_id": "8d2e6b1a-4f3c-4e9a-b7d5-1c0f9a2e3b44", "machine_name": "build-01",
#  "status": "queued", "requested_by": {"user_id": 482, "name": "Ada Lovelace"},
#  "requested_at": "2026-10-15T16:00:00Z", "wait_for_idle": true, "error": null}

# A machine that is not yours returns a 404 error.

Errors

Status

When

Resolution

403

you are not an admin of this workspace

ask an admin

404 Not found

no machine with that id in your workspace

check the id under Settings → Machines

409 This machine shares its sidecar installation with another brand and remains operator-managed.

the machine is shared with another workspace

OPVS updates it for you; no request is needed

POST /api/v1/machines/updates

Requests an update for every machine in the workspace. Machines that cannot be requested come back with status: "failed" and an error; the rest are queued.

curl -X POST "https://api.opvs.ai/api/v1/machines/updates" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 202 (abridged: one machine, four of its fields)
# {"requests": [{"machine_id": "8d2e6b1a-4f3c-4e9a-b7d5-1c0f9a2e3b44", "machine_name": "build-01",
#                "status": "queued", "error": null}],
#  "queued": 1, "failed": 0, "requested_at": "2026-10-15T16:00:00Z"}

# Without a token the route returns a 401 error.

Errors

Status

When

Resolution

401

no token, or the token is not valid

send a live token

403

you are not an admin of this workspace

ask an admin

Did this answer your question?