curl --request PATCH \
--url https://data.otterly.ai/v1/reports/brand/{reportId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"brandDomainWildcard": true,
"competitors": [
{
"brand": "Nike",
"brandDomain": "nike.com"
}
]
}
'import requests
url = "https://data.otterly.ai/v1/reports/brand/{reportId}"
payload = {
"brandDomainWildcard": True,
"competitors": [
{
"brand": "Nike",
"brandDomain": "nike.com"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
brandDomainWildcard: true,
competitors: [{brand: 'Nike', brandDomain: 'nike.com'}]
})
};
fetch('https://data.otterly.ai/v1/reports/brand/{reportId}', 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://data.otterly.ai/v1/reports/brand/{reportId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'brandDomainWildcard' => true,
'competitors' => [
[
'brand' => 'Nike',
'brandDomain' => 'nike.com'
]
]
]),
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://data.otterly.ai/v1/reports/brand/{reportId}"
payload := strings.NewReader("{\n \"brandDomainWildcard\": true,\n \"competitors\": [\n {\n \"brand\": \"Nike\",\n \"brandDomain\": \"nike.com\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://data.otterly.ai/v1/reports/brand/{reportId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"brandDomainWildcard\": true,\n \"competitors\": [\n {\n \"brand\": \"Nike\",\n \"brandDomain\": \"nike.com\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.otterly.ai/v1/reports/brand/{reportId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"brandDomainWildcard\": true,\n \"competitors\": [\n {\n \"brand\": \"Nike\",\n \"brandDomain\": \"nike.com\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "01HXBR1DGM5XY8Z2N3KQ7VAW4P",
"workspaceId": "01HX7K2YV9D3M8N0G6Q5R4S3T2",
"brand": "Adidas",
"brandVariations": [
"adidas",
"Adidas AG"
],
"brandDomain": "adidas.com",
"brandDomainVariations": [
"adidas.de",
"adidas.co.uk"
],
"brandDomainWildcard": false,
"brandRegex": null,
"countries": [
"us",
"de",
"uk"
],
"competitors": [
{
"brand": "Nike",
"brandVariations": [
"nike",
"Nike Inc."
],
"brandDomain": "nike.com",
"brandDomainVariations": [
"nike.de",
"nike.co.uk"
],
"brandDomainWildcard": false,
"brandRegex": null
}
],
"reportTitle": "Adidas Visibility Report",
"createdDate": "2024-11-01T12:00:00.000Z",
"updatedDate": "2025-05-01T08:30:00.000Z",
"promptIds": [
"01HXP1DRTM5G8Z2N3KQ7VAW4PA",
"01HXP2DRTM5G8Z2N3KQ7VAW4PB"
],
"countryPromptsTotal": {
"us": 50,
"de": 35,
"uk": 28
},
"tags": [
{
"id": "01HX8AB3CDE4FG5HJ6KL7MN8PQ",
"name": "Running Shoes",
"color": "orange"
}
]
}{
"message": "Validation failed",
"target": "query",
"errors": [
{
"path": "country",
"message": "Required",
"code": "invalid_type"
}
]
}{
"message": "Report not found"
}{
"message": "Report not found"
}{
"message": "Report not found"
}{
"message": "Report not found"
}Update a brand report
Changes only the fields you send; an array field you send replaces the stored one whole. A field sent with its stored value is left unchanged and is not re-validated, so a GET body can be sent back as is: its read-only fields (workspaceId, id, countries, tags, createdDate, updatedDate, countryPromptsTotal) are ignored, and the workspace of a report cannot be changed. Send brandRegex: null to clear the detection regex. Changing detection fields (brand, variations, domains, wildcard, regex or competitors) recalculates the report history for every past day, exactly like an edit in the UI, so updated numbers appear with a delay. Changing promptIds adds and removes prompts the same way as the prompt assignment endpoints.
curl --request PATCH \
--url https://data.otterly.ai/v1/reports/brand/{reportId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"brandDomainWildcard": true,
"competitors": [
{
"brand": "Nike",
"brandDomain": "nike.com"
}
]
}
'import requests
url = "https://data.otterly.ai/v1/reports/brand/{reportId}"
payload = {
"brandDomainWildcard": True,
"competitors": [
{
"brand": "Nike",
"brandDomain": "nike.com"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
brandDomainWildcard: true,
competitors: [{brand: 'Nike', brandDomain: 'nike.com'}]
})
};
fetch('https://data.otterly.ai/v1/reports/brand/{reportId}', 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://data.otterly.ai/v1/reports/brand/{reportId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'brandDomainWildcard' => true,
'competitors' => [
[
'brand' => 'Nike',
'brandDomain' => 'nike.com'
]
]
]),
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://data.otterly.ai/v1/reports/brand/{reportId}"
payload := strings.NewReader("{\n \"brandDomainWildcard\": true,\n \"competitors\": [\n {\n \"brand\": \"Nike\",\n \"brandDomain\": \"nike.com\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://data.otterly.ai/v1/reports/brand/{reportId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"brandDomainWildcard\": true,\n \"competitors\": [\n {\n \"brand\": \"Nike\",\n \"brandDomain\": \"nike.com\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.otterly.ai/v1/reports/brand/{reportId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"brandDomainWildcard\": true,\n \"competitors\": [\n {\n \"brand\": \"Nike\",\n \"brandDomain\": \"nike.com\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "01HXBR1DGM5XY8Z2N3KQ7VAW4P",
"workspaceId": "01HX7K2YV9D3M8N0G6Q5R4S3T2",
"brand": "Adidas",
"brandVariations": [
"adidas",
"Adidas AG"
],
"brandDomain": "adidas.com",
"brandDomainVariations": [
"adidas.de",
"adidas.co.uk"
],
"brandDomainWildcard": false,
"brandRegex": null,
"countries": [
"us",
"de",
"uk"
],
"competitors": [
{
"brand": "Nike",
"brandVariations": [
"nike",
"Nike Inc."
],
"brandDomain": "nike.com",
"brandDomainVariations": [
"nike.de",
"nike.co.uk"
],
"brandDomainWildcard": false,
"brandRegex": null
}
],
"reportTitle": "Adidas Visibility Report",
"createdDate": "2024-11-01T12:00:00.000Z",
"updatedDate": "2025-05-01T08:30:00.000Z",
"promptIds": [
"01HXP1DRTM5G8Z2N3KQ7VAW4PA",
"01HXP2DRTM5G8Z2N3KQ7VAW4PB"
],
"countryPromptsTotal": {
"us": 50,
"de": 35,
"uk": 28
},
"tags": [
{
"id": "01HX8AB3CDE4FG5HJ6KL7MN8PQ",
"name": "Running Shoes",
"color": "orange"
}
]
}{
"message": "Validation failed",
"target": "query",
"errors": [
{
"path": "country",
"message": "Required",
"code": "invalid_type"
}
]
}{
"message": "Report not found"
}{
"message": "Report not found"
}{
"message": "Report not found"
}{
"message": "Report not found"
}Authorizations
Path Parameters
Body
Response
The updated brand report. Recalculation completes asynchronously.