# Agents

Source: https://opvs.ai/docs/api/agents

## `GET` /api/v1/agents/workflows

**List Workflows**

List all workflows for the current brand.

**Parameters**

- `status` (query, any, optional)
- `workflow_type` (query, any, optional)
- `format` (query, any, optional) — Response format: yaml or md

```bash
curl -X GET 'https://app.opvs.ai/api/v1/agents/workflows' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/agents/workflows",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/workflows", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/agents/workflows", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `POST` /api/v1/agents/workflows

**Create Workflow**

Create a new workflow.

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/agents/workflows' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "string",
  "description": "string",
  "workflow_type": "custom",
  "canvas_state": {
    "nodes": [
      null
    ],
    "edges": [
      null
    ]
  },
  "is_template": false,
  "tags": [
    "string"
  ]
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/agents/workflows",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"name": "string", "description": "string", "workflow_type": "custom", "canvas_state": {"nodes": [null], "edges": [null]}, "is_template": false, "tags": ["string"]},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/workflows", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"name": "string", "description": "string", "workflow_type": "custom", "canvas_state": {"nodes": [null], "edges": [null]}, "is_template": false, "tags": ["string"]})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"name": "string", "description": "string", "workflow_type": "custom", "canvas_state": {"nodes": [null], "edges": [null]}, "is_template": false, "tags": ["string"]}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/agents/workflows", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `201` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/agents/workflows/{workflow_id}

**Get Workflow**

Get a single workflow with full canvas state.

**Parameters**

- `workflow_id` (path, string, required)
- `format` (query, any, optional) — Response format: yaml or md

```bash
curl -X GET 'https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `PATCH` /api/v1/agents/workflows/{workflow_id}

**Update Workflow**

Update a workflow (name, description, canvas state, status, etc.).

**Parameters**

- `workflow_id` (path, string, required)

**Request body**

```bash
curl -X PATCH 'https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "string",
  "description": "string",
  "workflow_type": "string",
  "canvas_state": {
    "nodes": [
      null
    ],
    "edges": [
      null
    ]
  },
  "status": "string",
  "tags": [
    "string"
  ]
}'
```

```python
import httpx

resp = httpx.patch(
    "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"name": "string", "description": "string", "workflow_type": "string", "canvas_state": {"nodes": [null], "edges": [null]}, "status": "string", "tags": ["string"]},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}", {
  method: "PATCH",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"name": "string", "description": "string", "workflow_type": "string", "canvas_state": {"nodes": [null], "edges": [null]}, "status": "string", "tags": ["string"]})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"name": "string", "description": "string", "workflow_type": "string", "canvas_state": {"nodes": [null], "edges": [null]}, "status": "string", "tags": ["string"]}`)
	req, _ := http.NewRequest("PATCH", "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `DELETE` /api/v1/agents/workflows/{workflow_id}

**Delete Workflow**

Delete a workflow.

**Parameters**

- `workflow_id` (path, string, required)

```bash
curl -X DELETE 'https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.delete(
    "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}", {
  method: "DELETE",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("DELETE", "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `204` — Successful Response
- `422` — Validation Error

## `POST` /api/v1/agents/workflows/{workflow_id}/deploy

**Deploy Workflow**

Deploy a workflow — activates it and (in the future) syncs to the Management API to create/update the OpenClaw agent.

**Parameters**

- `workflow_id` (path, string, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}/deploy' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}/deploy",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}/deploy", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}/deploy", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/agents/personas

**List Personas**

List all personas for the current brand.

**Parameters**

- `status` (query, any, optional)
- `format` (query, any, optional) — Response format: yaml or md

```bash
curl -X GET 'https://app.opvs.ai/api/v1/agents/personas' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/agents/personas",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/agents/personas", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `POST` /api/v1/agents/personas

**Create Persona**

Create a new persona.

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/agents/personas' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "code": "string",
  "full_name": "string",
  "role": "string",
  "avatar_url": "string",
  "model_default": "string",
  "status": "draft",
  "identity": {},
  "personality": {},
  "behavior": {},
  "model_config_data": {},
  "channels": {},
  "skills": [
    null
  ],
  "memory_files": [
    null
  ],
  "soul_md": "string",
  "tools_md": "string"
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/agents/personas",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"code": "string", "full_name": "string", "role": "string", "avatar_url": "string", "model_default": "string", "status": "draft", "identity": {}, "personality": {}, "behavior": {}, "model_config_data": {}, "channels": {}, "skills": [null], "memory_files": [null], "soul_md": "string", "tools_md": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"code": "string", "full_name": "string", "role": "string", "avatar_url": "string", "model_default": "string", "status": "draft", "identity": {}, "personality": {}, "behavior": {}, "model_config_data": {}, "channels": {}, "skills": [null], "memory_files": [null], "soul_md": "string", "tools_md": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"code": "string", "full_name": "string", "role": "string", "avatar_url": "string", "model_default": "string", "status": "draft", "identity": {}, "personality": {}, "behavior": {}, "model_config_data": {}, "channels": {}, "skills": [null], "memory_files": [null], "soul_md": "string", "tools_md": "string"}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/agents/personas", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `201` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/agents/personas/{persona_id}

**Get Persona**

Get a single persona with full details, visuals, and voice.

**Parameters**

- `persona_id` (path, string, required)
- `format` (query, any, optional) — Response format: yaml or md

```bash
curl -X GET 'https://app.opvs.ai/api/v1/agents/personas/{persona_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/agents/personas/{persona_id}",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas/{persona_id}", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/agents/personas/{persona_id}", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `PATCH` /api/v1/agents/personas/{persona_id}

**Update Persona**

Auto-save update for a persona. JSONB fields are merged (not replaced) — only provided keys are updated. If an own persona is deployed, syncs workspace files to the gateway as a background task.  A live hire's vendor files are never regenerated by customer edits.

**Parameters**

- `persona_id` (path, string, required)

**Request body**

```bash
curl -X PATCH 'https://app.opvs.ai/api/v1/agents/personas/{persona_id}' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "code": "string",
  "full_name": "string",
  "role": "string",
  "avatar_url": "string",
  "model_default": "string",
  "status": "string",
  "identity": {},
  "personality": {},
  "behavior": {},
  "model_config_data": {},
  "channels": {},
  "skills": [
    null
  ],
  "memory_files": [
    null
  ],
  "soul_md": "string",
  "agents_md": "string",
  "tools_md": "string",
  "visuals": {},
  "voice": {}
}'
```

```python
import httpx

resp = httpx.patch(
    "https://app.opvs.ai/api/v1/agents/personas/{persona_id}",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"code": "string", "full_name": "string", "role": "string", "avatar_url": "string", "model_default": "string", "status": "string", "identity": {}, "personality": {}, "behavior": {}, "model_config_data": {}, "channels": {}, "skills": [null], "memory_files": [null], "soul_md": "string", "agents_md": "string", "tools_md": "string", "visuals": {}, "voice": {}},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas/{persona_id}", {
  method: "PATCH",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"code": "string", "full_name": "string", "role": "string", "avatar_url": "string", "model_default": "string", "status": "string", "identity": {}, "personality": {}, "behavior": {}, "model_config_data": {}, "channels": {}, "skills": [null], "memory_files": [null], "soul_md": "string", "agents_md": "string", "tools_md": "string", "visuals": {}, "voice": {}})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"code": "string", "full_name": "string", "role": "string", "avatar_url": "string", "model_default": "string", "status": "string", "identity": {}, "personality": {}, "behavior": {}, "model_config_data": {}, "channels": {}, "skills": [null], "memory_files": [null], "soul_md": "string", "agents_md": "string", "tools_md": "string", "visuals": {}, "voice": {}}`)
	req, _ := http.NewRequest("PATCH", "https://app.opvs.ai/api/v1/agents/personas/{persona_id}", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `DELETE` /api/v1/agents/personas/{persona_id}

**Delete Persona**

Delete a persona, unless a live hire still depends on it.

**Parameters**

- `persona_id` (path, string, required)

```bash
curl -X DELETE 'https://app.opvs.ai/api/v1/agents/personas/{persona_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.delete(
    "https://app.opvs.ai/api/v1/agents/personas/{persona_id}",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas/{persona_id}", {
  method: "DELETE",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("DELETE", "https://app.opvs.ai/api/v1/agents/personas/{persona_id}", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `204` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/agents/personas/{persona_id}/skills

**Get Persona Skills**

Return the configured skills of one own persona in this brand.

**Parameters**

- `persona_id` (path, string, required)
- `format` (query, any, optional)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/agents/personas/{persona_id}/skills' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/agents/personas/{persona_id}/skills",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas/{persona_id}/skills", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/agents/personas/{persona_id}/skills", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `POST` /api/v1/agents/personas/retire

**Retire Personas Bulk**

Clear agents out of all five stores at once — reversibly, or for good.

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/agents/personas/retire' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "persona_ids": [
    "string"
  ],
  "mode": "deactivate",
  "confirm_purge": false,
  "remove_cron": true
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/agents/personas/retire",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"persona_ids": ["string"], "mode": "deactivate", "confirm_purge": false, "remove_cron": true},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas/retire", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"persona_ids": ["string"], "mode": "deactivate", "confirm_purge": false, "remove_cron": true})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"persona_ids": ["string"], "mode": "deactivate", "confirm_purge": false, "remove_cron": true}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/agents/personas/retire", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `POST` /api/v1/agents/personas/{persona_id}/deploy

**Deploy Persona**

Deploy a persona to the OpenClaw gateway.

**Parameters**

- `persona_id` (path, string, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/agents/personas/{persona_id}/deploy' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/agents/personas/{persona_id}/deploy",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas/{persona_id}/deploy", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/agents/personas/{persona_id}/deploy", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `POST` /api/v1/agents/personas/{persona_id}/undeploy

**Undeploy Persona**

Remove a persona's agent from the OpenClaw gateway.

**Parameters**

- `persona_id` (path, string, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/agents/personas/{persona_id}/undeploy' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/agents/personas/{persona_id}/undeploy",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/personas/{persona_id}/undeploy", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/agents/personas/{persona_id}/undeploy", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/agents/canvas

**Get Agent Canvas**

Return saved organigram canvas state for the current brand.

```bash
curl -X GET 'https://app.opvs.ai/api/v1/agents/canvas' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/agents/canvas",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/canvas", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/agents/canvas", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response

## `PUT` /api/v1/agents/canvas

**Save Agent Canvas**

Upsert organigram canvas state (node positions + edges + viewport).

**Request body**

```bash
curl -X PUT 'https://app.opvs.ai/api/v1/agents/canvas' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "canvas_state": {
    "nodes": [
      {
        "id": "string",
        "position": {}
      }
    ],
    "edges": [
      {
        "id": "string",
        "source": "string",
        "target": "string",
        "sourceHandle": "string",
        "targetHandle": "string"
      }
    ]
  },
  "viewport": {
    "x": 0,
    "y": 0,
    "zoom": 1
  }
}'
```

```python
import httpx

resp = httpx.put(
    "https://app.opvs.ai/api/v1/agents/canvas",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"canvas_state": {"nodes": [{"id": "string", "position": {}}], "edges": [{"id": "string", "source": "string", "target": "string", "sourceHandle": "string", "targetHandle": "string"}]}, "viewport": {"x": 0, "y": 0, "zoom": 1}},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/agents/canvas", {
  method: "PUT",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"canvas_state": {"nodes": [{"id": "string", "position": {}}], "edges": [{"id": "string", "source": "string", "target": "string", "sourceHandle": "string", "targetHandle": "string"}]}, "viewport": {"x": 0, "y": 0, "zoom": 1}})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"canvas_state": {"nodes": [{"id": "string", "position": {}}], "edges": [{"id": "string", "source": "string", "target": "string", "sourceHandle": "string", "targetHandle": "string"}]}, "viewport": {"x": 0, "y": 0, "zoom": 1}}`)
	req, _ := http.NewRequest("PUT", "https://app.opvs.ai/api/v1/agents/canvas", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## List Workflows

`GET https://app.opvs.ai/api/v1/agents/workflows`

List all workflows for the current brand.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Create Workflow

`POST https://app.opvs.ai/api/v1/agents/workflows`

Create a new workflow.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Get Workflow

`GET https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}`

Get a single workflow with full canvas state.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Update Workflow

`PATCH https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}`

Update a workflow (name, description, canvas state, status, etc.).

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Delete Workflow

`DELETE https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}`

Delete a workflow.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Deploy Workflow

`POST https://app.opvs.ai/api/v1/agents/workflows/{workflow_id}/deploy`

Deploy a workflow — activates it and (in the future)
syncs to the Management API to create/update the OpenClaw agent.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## List Personas

`GET https://app.opvs.ai/api/v1/agents/personas`

List all personas for the current brand.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Create Persona

`POST https://app.opvs.ai/api/v1/agents/personas`

Create a new persona.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Get Persona

`GET https://app.opvs.ai/api/v1/agents/personas/{persona_id}`

Get a single persona with full details, visuals, and voice.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Update Persona

`PATCH https://app.opvs.ai/api/v1/agents/personas/{persona_id}`

Auto-save update for a persona.
JSONB fields are merged (not replaced) — only provided keys are updated.
If an own persona is deployed, syncs workspace files to the gateway as a
background task.  A live hire's vendor files are never regenerated by
customer edits.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Delete Persona

`DELETE https://app.opvs.ai/api/v1/agents/personas/{persona_id}`

Delete a persona, unless a live hire still depends on it.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Get Persona Skills

`GET https://app.opvs.ai/api/v1/agents/personas/{persona_id}/skills`

Return the configured skills of one own persona in this brand.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Retire Personas Bulk

`POST https://app.opvs.ai/api/v1/agents/personas/retire`

Clear agents out of all five stores at once — reversibly, or for good.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Deploy Persona

`POST https://app.opvs.ai/api/v1/agents/personas/{persona_id}/deploy`

Deploy a persona to the OpenClaw gateway.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Undeploy Persona

`POST https://app.opvs.ai/api/v1/agents/personas/{persona_id}/undeploy`

Remove a persona's agent from the OpenClaw gateway.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Get Agent Canvas

`GET https://app.opvs.ai/api/v1/agents/canvas`

Return saved organigram canvas state for the current brand.

## Save Agent Canvas

`PUT https://app.opvs.ai/api/v1/agents/canvas`

Upsert organigram canvas state (node positions + edges + viewport).

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |
