curl --request POST \
--url https://api.qa.tech/v1/chat \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"message": "<string>",
"applicationOverrides": [
{
"applicationShortId": "<string>",
"environment": {
"url": "<string>",
"name": "<string>",
"customHeaders": [
{
"domains": [
"<string>"
],
"headers": {}
}
]
},
"devicePresetShortId": "<string>"
}
],
"projectShortId": "<string>"
}
'import requests
url = "https://api.qa.tech/v1/chat"
payload = {
"message": "<string>",
"applicationOverrides": [
{
"applicationShortId": "<string>",
"environment": {
"url": "<string>",
"name": "<string>",
"customHeaders": [
{
"domains": ["<string>"],
"headers": {}
}
]
},
"devicePresetShortId": "<string>"
}
],
"projectShortId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
message: '<string>',
applicationOverrides: [
{
applicationShortId: '<string>',
environment: {
url: '<string>',
name: '<string>',
customHeaders: [{domains: ['<string>'], headers: {}}]
},
devicePresetShortId: '<string>'
}
],
projectShortId: '<string>'
})
};
fetch('https://api.qa.tech/v1/chat', 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.qa.tech/v1/chat",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'message' => '<string>',
'applicationOverrides' => [
[
'applicationShortId' => '<string>',
'environment' => [
'url' => '<string>',
'name' => '<string>',
'customHeaders' => [
[
'domains' => [
'<string>'
],
'headers' => [
]
]
]
],
'devicePresetShortId' => '<string>'
]
],
'projectShortId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.qa.tech/v1/chat"
payload := strings.NewReader("{\n \"message\": \"<string>\",\n \"applicationOverrides\": [\n {\n \"applicationShortId\": \"<string>\",\n \"environment\": {\n \"url\": \"<string>\",\n \"name\": \"<string>\",\n \"customHeaders\": [\n {\n \"domains\": [\n \"<string>\"\n ],\n \"headers\": {}\n }\n ]\n },\n \"devicePresetShortId\": \"<string>\"\n }\n ],\n \"projectShortId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.post("https://api.qa.tech/v1/chat")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"message\": \"<string>\",\n \"applicationOverrides\": [\n {\n \"applicationShortId\": \"<string>\",\n \"environment\": {\n \"url\": \"<string>\",\n \"name\": \"<string>\",\n \"customHeaders\": [\n {\n \"domains\": [\n \"<string>\"\n ],\n \"headers\": {}\n }\n ]\n },\n \"devicePresetShortId\": \"<string>\"\n }\n ],\n \"projectShortId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.qa.tech/v1/chat")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"message\": \"<string>\",\n \"applicationOverrides\": [\n {\n \"applicationShortId\": \"<string>\",\n \"environment\": {\n \"url\": \"<string>\",\n \"name\": \"<string>\",\n \"customHeaders\": [\n {\n \"domains\": [\n \"<string>\"\n ],\n \"headers\": {}\n }\n ]\n },\n \"devicePresetShortId\": \"<string>\"\n }\n ],\n \"projectShortId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"shortId": "<string>",
"url": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"status": "in_progress",
"runs": [
{
"shortId": "<string>",
"status": "<string>",
"result": "<string>",
"url": "<string>"
}
],
"title": "<string>",
"source": "api",
"messages": [
{
"id": "<string>",
"role": "user",
"createdAt": "2023-11-07T05:31:56Z",
"text": "<string>",
"status": "INITIATED",
"isStreaming": true
}
]
}Start chat conversation
Create a new chat conversation and send its first message.
This is the recommended way to author tests. The QA.tech agent explores the site, grounds tests in what actually exists, and sets up login and config dependencies, so the tests are reliable rather than flaky. Prefer it over create_test_case unless you have already verified the flow exists and gathered the details that tool requires.
Returns 202 immediately with the created conversation. Processing is asynchronous: poll
get_chat_conversation until conversation status is completed, failed, or
cancelled. Assistant message COMPLETED is not enough — starting a test run ends
the current turn while the run continues. Wait at least 1s between polls. When a run
exists, runs[].shortId is the handle for get_run / get_run_test_case.
curl --request POST \
--url https://api.qa.tech/v1/chat \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"message": "<string>",
"applicationOverrides": [
{
"applicationShortId": "<string>",
"environment": {
"url": "<string>",
"name": "<string>",
"customHeaders": [
{
"domains": [
"<string>"
],
"headers": {}
}
]
},
"devicePresetShortId": "<string>"
}
],
"projectShortId": "<string>"
}
'import requests
url = "https://api.qa.tech/v1/chat"
payload = {
"message": "<string>",
"applicationOverrides": [
{
"applicationShortId": "<string>",
"environment": {
"url": "<string>",
"name": "<string>",
"customHeaders": [
{
"domains": ["<string>"],
"headers": {}
}
]
},
"devicePresetShortId": "<string>"
}
],
"projectShortId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
message: '<string>',
applicationOverrides: [
{
applicationShortId: '<string>',
environment: {
url: '<string>',
name: '<string>',
customHeaders: [{domains: ['<string>'], headers: {}}]
},
devicePresetShortId: '<string>'
}
],
projectShortId: '<string>'
})
};
fetch('https://api.qa.tech/v1/chat', 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.qa.tech/v1/chat",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'message' => '<string>',
'applicationOverrides' => [
[
'applicationShortId' => '<string>',
'environment' => [
'url' => '<string>',
'name' => '<string>',
'customHeaders' => [
[
'domains' => [
'<string>'
],
'headers' => [
]
]
]
],
'devicePresetShortId' => '<string>'
]
],
'projectShortId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.qa.tech/v1/chat"
payload := strings.NewReader("{\n \"message\": \"<string>\",\n \"applicationOverrides\": [\n {\n \"applicationShortId\": \"<string>\",\n \"environment\": {\n \"url\": \"<string>\",\n \"name\": \"<string>\",\n \"customHeaders\": [\n {\n \"domains\": [\n \"<string>\"\n ],\n \"headers\": {}\n }\n ]\n },\n \"devicePresetShortId\": \"<string>\"\n }\n ],\n \"projectShortId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.post("https://api.qa.tech/v1/chat")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"message\": \"<string>\",\n \"applicationOverrides\": [\n {\n \"applicationShortId\": \"<string>\",\n \"environment\": {\n \"url\": \"<string>\",\n \"name\": \"<string>\",\n \"customHeaders\": [\n {\n \"domains\": [\n \"<string>\"\n ],\n \"headers\": {}\n }\n ]\n },\n \"devicePresetShortId\": \"<string>\"\n }\n ],\n \"projectShortId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.qa.tech/v1/chat")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"message\": \"<string>\",\n \"applicationOverrides\": [\n {\n \"applicationShortId\": \"<string>\",\n \"environment\": {\n \"url\": \"<string>\",\n \"name\": \"<string>\",\n \"customHeaders\": [\n {\n \"domains\": [\n \"<string>\"\n ],\n \"headers\": {}\n }\n ]\n },\n \"devicePresetShortId\": \"<string>\"\n }\n ],\n \"projectShortId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"shortId": "<string>",
"url": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"status": "in_progress",
"runs": [
{
"shortId": "<string>",
"status": "<string>",
"result": "<string>",
"url": "<string>"
}
],
"title": "<string>",
"source": "api",
"messages": [
{
"id": "<string>",
"role": "user",
"createdAt": "2023-11-07T05:31:56Z",
"text": "<string>",
"status": "INITIATED",
"isStreaming": true
}
]
}Body
Request body for sending a chat message
The message text to send. Example: 'Generate a login flow test for staging'.
1Optional per-application environment overrides. Optional customHeaders on environment persist auth or protection-bypass headers.
Show child attributes
Show child attributes
Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID.
^proj(-.+_.+|_.+)$Response
The request has been accepted for processing, but processing has not yet completed.
Conversation data with recent messages (newest first).
^chat(-.+_.+|_.+)$Dashboard URL for the conversation.
Overall conversation lifecycle. in_progress while the assistant is working or a background test run / research task is still going. Assistant message COMPLETED is not enough — starting a run ends the current turn. Poll until this is completed, failed, or cancelled.
in_progress, completed, failed, cancelled Test runs started from this conversation, newest first. Empty until a run is created. Use shortId with get_run (testCases = all) or nested test-case short IDs from that call with get_run_test_case.
Show child attributes
Show child attributes
Where the conversation originated. api for conversations created via this API, ui for the dashboard, github/gitlab for VCS-triggered chats, and system for everything else.
api, ui, github, gitlab, system Recent messages, newest first. Empty on creation; poll get_chat_conversation to retrieve. Internal wake messages are omitted.
Show child attributes
Show child attributes
Was this page helpful?