curl --request DELETE \
--url https://api.getbluejay.ai/v1/digital-human/{digital_human_id} \
--header 'X-API-Key: <x-api-key>'import requests
url = "https://api.getbluejay.ai/v1/digital-human/{digital_human_id}"
headers = {"X-API-Key": "<x-api-key>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {'X-API-Key': '<x-api-key>'}};
fetch('https://api.getbluejay.ai/v1/digital-human/{digital_human_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/digital-human/{digital_human_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://api.getbluejay.ai/v1/digital-human/{digital_human_id}"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("X-API-Key", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.delete("https://api.getbluejay.ai/v1/digital-human/{digital_human_id}")
.header("X-API-Key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getbluejay.ai/v1/digital-human/{digital_human_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["X-API-Key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"intent": "<string>",
"success_criteria": "<string>",
"id": 123,
"bluejay_as_code_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tag": "<string>",
"tags": [
"<string>"
],
"system_prompt_rule_ids": [
"<string>"
],
"system_prompt_rule_quotes": [
"<string>"
],
"name": "<string>",
"language": "en",
"accent": "multilingual",
"gender": "male",
"custom_voice_id": "<string>",
"background_noise": "<string>",
"custom_background_noise_url": "<string>",
"voice_speed": "<string>",
"audio_quality": "<string>",
"connection_quality": "<string>",
"fluency": "<string>",
"verbosity": "<string>",
"phone_number": "<string>",
"extension": "<string>",
"outbound_text_number": "<string>",
"follow_up_sms_success_criteria": "<string>",
"websocket_url": "<string>",
"background_noise_volume": 123,
"expected_tool_calls": [
{
"name": "<string>",
"parameters": {},
"output": "<unknown>"
}
],
"allow_end_call_tool": true,
"allow_silence_tool": true,
"allow_dtmf_tool": true,
"default_dtmf_or_voiced": "voiced",
"silence_tool_instructions": "default",
"endpointing_delay": 123,
"creativity": 123,
"hangup_phrases": [
"<string>"
],
"hangup_instructions": "<string>",
"silence_timeout": 123,
"role_description": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"traits": [
{
"trait_name": "<string>",
"trait_data_type": "BOOLEAN",
"value": "<unknown>",
"is_sip_header": false
}
],
"interruptions": {},
"scripted_responses": [
{
"match_type": "exact",
"match_phrase": "<string>",
"response_type": "phrase",
"occurrence_mode": "always",
"response_value": "<string>",
"scripted_response_audio_snippet_url": "<string>",
"occurrence_n": 1,
"silence_duration": 1
}
],
"scripted_responses_ordered": false,
"speaks_first_config": {
"speaks_first": true,
"mode": "custom",
"message": "<string>",
"dynamic": true
},
"original_transcript": "<string>",
"formatted_transcript": [
{}
],
"enriched_playback": [
{}
],
"workflow_v2_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workflow_path_index": 123,
"tested_path": [
"<string>"
],
"livekit_metadata": {},
"test_name": "<string>",
"journey_steps": [
{
"step": 1,
"intent": "",
"success_criteria": "",
"modality": "voice",
"direction": "inbound",
"wait_seconds": 123,
"response_window_seconds": 123,
"unresponsive": false,
"phone_number": "<string>"
}
],
"always_on_mode": true,
"always_on_active": false,
"num_runs": 1,
"attack_vector": "<string>",
"attack_type": "<string>",
"attack_plan": {}
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Delete Digital Human
Delete a Digital Human by ID.
curl --request DELETE \
--url https://api.getbluejay.ai/v1/digital-human/{digital_human_id} \
--header 'X-API-Key: <x-api-key>'import requests
url = "https://api.getbluejay.ai/v1/digital-human/{digital_human_id}"
headers = {"X-API-Key": "<x-api-key>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {'X-API-Key': '<x-api-key>'}};
fetch('https://api.getbluejay.ai/v1/digital-human/{digital_human_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/digital-human/{digital_human_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://api.getbluejay.ai/v1/digital-human/{digital_human_id}"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("X-API-Key", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.delete("https://api.getbluejay.ai/v1/digital-human/{digital_human_id}")
.header("X-API-Key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getbluejay.ai/v1/digital-human/{digital_human_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["X-API-Key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"intent": "<string>",
"success_criteria": "<string>",
"id": 123,
"bluejay_as_code_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tag": "<string>",
"tags": [
"<string>"
],
"system_prompt_rule_ids": [
"<string>"
],
"system_prompt_rule_quotes": [
"<string>"
],
"name": "<string>",
"language": "en",
"accent": "multilingual",
"gender": "male",
"custom_voice_id": "<string>",
"background_noise": "<string>",
"custom_background_noise_url": "<string>",
"voice_speed": "<string>",
"audio_quality": "<string>",
"connection_quality": "<string>",
"fluency": "<string>",
"verbosity": "<string>",
"phone_number": "<string>",
"extension": "<string>",
"outbound_text_number": "<string>",
"follow_up_sms_success_criteria": "<string>",
"websocket_url": "<string>",
"background_noise_volume": 123,
"expected_tool_calls": [
{
"name": "<string>",
"parameters": {},
"output": "<unknown>"
}
],
"allow_end_call_tool": true,
"allow_silence_tool": true,
"allow_dtmf_tool": true,
"default_dtmf_or_voiced": "voiced",
"silence_tool_instructions": "default",
"endpointing_delay": 123,
"creativity": 123,
"hangup_phrases": [
"<string>"
],
"hangup_instructions": "<string>",
"silence_timeout": 123,
"role_description": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"traits": [
{
"trait_name": "<string>",
"trait_data_type": "BOOLEAN",
"value": "<unknown>",
"is_sip_header": false
}
],
"interruptions": {},
"scripted_responses": [
{
"match_type": "exact",
"match_phrase": "<string>",
"response_type": "phrase",
"occurrence_mode": "always",
"response_value": "<string>",
"scripted_response_audio_snippet_url": "<string>",
"occurrence_n": 1,
"silence_duration": 1
}
],
"scripted_responses_ordered": false,
"speaks_first_config": {
"speaks_first": true,
"mode": "custom",
"message": "<string>",
"dynamic": true
},
"original_transcript": "<string>",
"formatted_transcript": [
{}
],
"enriched_playback": [
{}
],
"workflow_v2_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workflow_path_index": 123,
"tested_path": [
"<string>"
],
"livekit_metadata": {},
"test_name": "<string>",
"journey_steps": [
{
"step": 1,
"intent": "",
"success_criteria": "",
"modality": "voice",
"direction": "inbound",
"wait_seconds": 123,
"response_window_seconds": 123,
"unresponsive": false,
"phone_number": "<string>"
}
],
"always_on_mode": true,
"always_on_active": false,
"num_runs": 1,
"attack_vector": "<string>",
"attack_type": "<string>",
"attack_plan": {}
}{
"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.
## Delete Digital Human — DELETE /v1/digital-human/{digital_human_id}
> **What this endpoint does:** Delete a Digital Human by ID.
**Endpoint:** DELETE `https://api.getbluejay.ai/v1/digital-human/{digital_human_id}`
**Auth:** `X-API-Key` header
### Required Parameters
| Name | Type | Description |
|------|------|-------------|
| digital_human_id | integer | |
| X-API-Key | string | API key required to authenticate requests. |
### Example
**DELETE request:**
```python
import requests
def delete_digital_human(digital_human_id: int, api_key: str) -> dict:
url = f"https://api.getbluejay.ai/v1/digital-human/{digital_human_id}"
headers = {"X-API-Key": api_key}
response = requests.delete(url, headers=headers)
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 422: Validation Error.
### 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.
Path Parameters
Response
Successful Response
Response model for digital human data.
Description of the digital human
Success criteria for the digital human
Unique identifier for the digital human
Stable code-addressable identifier
Tag for categorizing the digital human
All tags associated with the digital human
Ids of the system-prompt rules this digital human covers.
The quoted system-prompt rules this digital human covers.
Name of the digital human
Language of the digital human
en, es, pt, ja, tr, hi, ar, he, ru, zh, ml, fr, yue, vi, de, ko, ur, te, ta, mal, kn, mr, gu, tl, el, ad Accent of the digital human
multilingual, american, american2, mature, southern, italian, indian, british, australian, scottish, irish, welsh, mexican, spanish, portuguese, french, turkish, japanese, hindi, arabic, egyptian, levantine, hebrew, russian, chinese, german, korean, urdu, telugu, tamil, malayalam, kannada, marathi, gujarati, vietnamese, cantonese, tagalog, greek, autodetect, watson, watsonbritish, watsonaustralian, watsoncanadian Gender of the digital human
male, female ElevenLabs voice_id of a cloned voice used for TTS, if assigned
Type of background noise
Bucket-relative path of the uploaded custom background noise audio when background_noise is 'custom'
Speed of the digital human's voice
Audio quality of the digital human's voice
How often the caller's line drops out: none, low, medium or high
Fluency level of the digital human's speech
Verbosity level of the digital human's responses
Phone number for the digital human
Extension dialed as DTMF after connecting when this DH calls an inbound agent
Outbound text number
Criteria the captured follow-up SMS is graded against
WebSocket URL for real-time communication
Volume of background noise
Expected tool calls
Show child attributes
Show child attributes
Allow the digital human to end the tool call
Allow the digital human to use the silence tool
Allow the digital human to use the DTMF tool
Tool instructions; "default" or custom text
Delay for endpointing
Temperature setting
Phrases that trigger hangup
Freeform instructions for how/when to hang up
Silence timeout in seconds
Description of the role for the digital human
When this digital human was created
List of traits associated with this digital human
Show child attributes
Show child attributes
Interruption configuration for the digital human
List of scripted responses for the digital human, in the order they were saved
Show child attributes
Show child attributes
When true, scripted_responses run as a script in list order (each fires once, next one arms); when false any one fires whenever its match_phrase comes up
Speaks first config: speaks_first, mode (custom|ai_generated), message (when custom), dynamic (wait for the agent, open only if quiet; defaults true)
Show child attributes
Show child attributes
The original transcript text attached to this digital human
Structured transcript as [{"role": "USER"|"AGENT", "utterance": "..."}]
Show child attributes
Show child attributes
Optional enriched playback stored as JSONB: a list of turn objects
Source workflow_v2 UUID — set when this DH is generated from a workflow
0-based path index within enumerate_workflow_v2_paths output
Ordered names of the workflow path steps this DH was generated from (Generate-From-Workflow only).
LiveKit-specific configuration and metadata for this digital human
User-facing label for this digital human
Ordered journey steps for a multi-step (Customer Journey) digital human
Show child attributes
Show child attributes
Whether always-on mode is enabled
When true, this DH actively receives inbound calls on phone_number
Number of times this digital human is run per simulation run
Attack tactic key from VECTOR_CATALOG. NULL for non-red-team.
Umbrella attack category. NULL for non-red-team.
Crescendo escalation ladder. NULL for non-red-team.