curl --request PUT \
--url https://api.getbluejay.ai/v1/scenario/{workflow_id} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"name": "<string>",
"agent_ids": [
123
],
"description": "<string>",
"definition": {}
}
'import requests
url = "https://api.getbluejay.ai/v1/scenario/{workflow_id}"
payload = {
"name": "<string>",
"agent_ids": [123],
"description": "<string>",
"definition": {}
}
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>', agent_ids: [123], description: '<string>', definition: {}})
};
fetch('https://api.getbluejay.ai/v1/scenario/{workflow_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.getbluejay.ai/v1/scenario/{workflow_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'agent_ids' => [
123
],
'description' => '<string>',
'definition' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.getbluejay.ai/v1/scenario/{workflow_id}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"agent_ids\": [\n 123\n ],\n \"description\": \"<string>\",\n \"definition\": {}\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.getbluejay.ai/v1/scenario/{workflow_id}")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"agent_ids\": [\n 123\n ],\n \"description\": \"<string>\",\n \"definition\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getbluejay.ai/v1/scenario/{workflow_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"agent_ids\": [\n 123\n ],\n \"description\": \"<string>\",\n \"definition\": {}\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"definition": {},
"created_at": "2023-11-07T05:31:56Z",
"organization_id": "<string>",
"agent_ids": [],
"description": "<string>",
"dh_sync_summary": {},
"warnings": [
"<string>"
]
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Update scenario
Partially update a scenario; replacing definition re-validates the same typed React Flow graph as create.
curl --request PUT \
--url https://api.getbluejay.ai/v1/scenario/{workflow_id} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"name": "<string>",
"agent_ids": [
123
],
"description": "<string>",
"definition": {}
}
'import requests
url = "https://api.getbluejay.ai/v1/scenario/{workflow_id}"
payload = {
"name": "<string>",
"agent_ids": [123],
"description": "<string>",
"definition": {}
}
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>', agent_ids: [123], description: '<string>', definition: {}})
};
fetch('https://api.getbluejay.ai/v1/scenario/{workflow_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.getbluejay.ai/v1/scenario/{workflow_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'agent_ids' => [
123
],
'description' => '<string>',
'definition' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.getbluejay.ai/v1/scenario/{workflow_id}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"agent_ids\": [\n 123\n ],\n \"description\": \"<string>\",\n \"definition\": {}\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.getbluejay.ai/v1/scenario/{workflow_id}")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"agent_ids\": [\n 123\n ],\n \"description\": \"<string>\",\n \"definition\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getbluejay.ai/v1/scenario/{workflow_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"agent_ids\": [\n 123\n ],\n \"description\": \"<string>\",\n \"definition\": {}\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"definition": {},
"created_at": "2023-11-07T05:31:56Z",
"organization_id": "<string>",
"agent_ids": [],
"description": "<string>",
"dh_sync_summary": {},
"warnings": [
"<string>"
]
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}# Bluejay — Testing & Monitoring Platform for Conversational AI Agents
You are a senior backend engineer integrating the Bluejay API. Think step-by-step: first understand the endpoint, then plan the integration, then implement with minimal changes.
## Update scenario — PUT /v1/scenario/{workflow_id}
> **What this endpoint does:** Partial update. Omitted fields are unchanged. When agent_ids is present in the JSON body (even as [] or null), junction links are replaced atomically: an empty array or null clears all agent links. When definition is present, it is fully replaced and re-validated like on create. The graph must satisfy the same rules and typed shapes as **POST** `/v1/scenario` (see **components**).
**Endpoint:** PUT `https://api.getbluejay.ai/v1/scenario/{workflow_id}`
**Auth:** `X-API-Key` header
**Content-Type:** application/json
### Required Parameters
| Name | Type | Description |
|------|------|-------------|
| X-API-Key | string | API key required to authenticate requests. |
Review the full parameter list at https://docs.getbluejay.ai/api-reference/endpoint/update-scenario and include any optional parameters (e.g., `name`, `agent_ids`, `description`, `definition`) that serve your integration's use case and align with Bluejay's testing and monitoring capabilities.
### Request Body
```json
{
"name": "example_name",
"agent_ids": [
123
],
"description": "string",
"definition": {
"nodes": [
{
"id": "string",
"type": "start",
"position": {
"x": 1.0,
"y": 1.0
},
"data": {
"key": "value"
}
}
],
"edges": [
{
"id": "string",
"source": "string",
"target": "string",
"sourceHandle": "string"
}
],
"viewport": {
"key": "value"
}
}
}
```
### Example
**PUT with body:**
```python
import requests
def update_scenario(scenario_id: str, payload: dict, api_key: str) -> dict:
url = f"https://api.getbluejay.ai/v1/scenario/{scenario_id}"
headers = {"X-API-Key": api_key}
response = requests.put(url, headers=headers, json=payload)
response.raise_for_status()
return response.json()
```
### Constraints
- Minimal changes — only add/change files needed for this integration.
- Match existing codebase patterns (naming, file structure, error handling).
- Include error handling for 400: Invalid definition; 401: Unauthorized; 404: Not found or no access.
### Integration Checklist
Before writing code, verify:
1. Which module/service owns this API domain in the codebase?
2. What HTTP client and error-handling patterns does the project use?
3. Are there existing types/interfaces to extend?
Then implement the integration, export it, and confirm it compiles/passes lint.
agent_ids appears in the body (including []), all agent links are replaced; [] clears links. If definition appears, it is fully replaced and validated like POST /v1/scenario (same discriminated node and data types as Create scenario).
Sends only the fields you want to change; include definition only when replacing the entire React Flow graph.Path Parameters
Body
Partial update for workflows_v2.
New name for the workflow
1 - 255Set owning agents, or null to clear agent links (must belong to your organization when set).
New description (set empty string to clear if your client sends it)
Full React Flow definition when replacing the graph. Same shape as create: each node needs a top-level id; each edge needs a top-level id unique among edges.
Response
Successful Response
Single workflows_v2 row.
Workflow ID
Name of the workflow
Stored React Flow graph (start / single / options nodes). Nodes and edges use top-level string id fields; edge id values are unique within the graph.
Creation timestamp
Owning organization ID (set by middleware on create)
Linked agent ids when the workflow is agent-scoped
Description
Present on PUT responses when the definition was updated. Keys: updated, created, marked_stale, skipped, errors.
Non-blocking lint warnings emitted at save time (e.g. node text referencing an unknown {{trait_name}}). Empty when the definition is clean or no agents are linked.