curl --request POST \
--url https://server.promptwatch.com/api/v2/monitors \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"name": "<string>",
"models": [
"<string>"
],
"description": "<string>",
"languageCode": "en-US",
"countryCode": "US",
"stateCode": "<string>",
"cityCode": "<string>",
"latitude": 0,
"longitude": 0,
"locationName": "<string>",
"personaId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"personaStackingEnabled": true,
"initialPrompts": [
{
"prompt": "<string>",
"keywords": [
"<string>"
]
}
],
"generatePrompts": [
{
"amount": 25,
"instructions": "<string>"
}
]
}
'import requests
url = "https://server.promptwatch.com/api/v2/monitors"
payload = {
"name": "<string>",
"models": ["<string>"],
"description": "<string>",
"languageCode": "en-US",
"countryCode": "US",
"stateCode": "<string>",
"cityCode": "<string>",
"latitude": 0,
"longitude": 0,
"locationName": "<string>",
"personaId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"personaStackingEnabled": True,
"initialPrompts": [
{
"prompt": "<string>",
"keywords": ["<string>"]
}
],
"generatePrompts": [
{
"amount": 25,
"instructions": "<string>"
}
]
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
models: ['<string>'],
description: '<string>',
languageCode: 'en-US',
countryCode: 'US',
stateCode: '<string>',
cityCode: '<string>',
latitude: 0,
longitude: 0,
locationName: '<string>',
personaId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
personaStackingEnabled: true,
initialPrompts: [{prompt: '<string>', keywords: ['<string>']}],
generatePrompts: [{amount: 25, instructions: '<string>'}]
})
};
fetch('https://server.promptwatch.com/api/v2/monitors', 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://server.promptwatch.com/api/v2/monitors",
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([
'name' => '<string>',
'models' => [
'<string>'
],
'description' => '<string>',
'languageCode' => 'en-US',
'countryCode' => 'US',
'stateCode' => '<string>',
'cityCode' => '<string>',
'latitude' => 0,
'longitude' => 0,
'locationName' => '<string>',
'personaId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'personaStackingEnabled' => true,
'initialPrompts' => [
[
'prompt' => '<string>',
'keywords' => [
'<string>'
]
]
],
'generatePrompts' => [
[
'amount' => 25,
'instructions' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <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://server.promptwatch.com/api/v2/monitors"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"models\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"languageCode\": \"en-US\",\n \"countryCode\": \"US\",\n \"stateCode\": \"<string>\",\n \"cityCode\": \"<string>\",\n \"latitude\": 0,\n \"longitude\": 0,\n \"locationName\": \"<string>\",\n \"personaId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"personaStackingEnabled\": true,\n \"initialPrompts\": [\n {\n \"prompt\": \"<string>\",\n \"keywords\": [\n \"<string>\"\n ]\n }\n ],\n \"generatePrompts\": [\n {\n \"amount\": 25,\n \"instructions\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<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.post("https://server.promptwatch.com/api/v2/monitors")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"models\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"languageCode\": \"en-US\",\n \"countryCode\": \"US\",\n \"stateCode\": \"<string>\",\n \"cityCode\": \"<string>\",\n \"latitude\": 0,\n \"longitude\": 0,\n \"locationName\": \"<string>\",\n \"personaId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"personaStackingEnabled\": true,\n \"initialPrompts\": [\n {\n \"prompt\": \"<string>\",\n \"keywords\": [\n \"<string>\"\n ]\n }\n ],\n \"generatePrompts\": [\n {\n \"amount\": 25,\n \"instructions\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://server.promptwatch.com/api/v2/monitors")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"models\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"languageCode\": \"en-US\",\n \"countryCode\": \"US\",\n \"stateCode\": \"<string>\",\n \"cityCode\": \"<string>\",\n \"latitude\": 0,\n \"longitude\": 0,\n \"locationName\": \"<string>\",\n \"personaId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"personaStackingEnabled\": true,\n \"initialPrompts\": [\n {\n \"prompt\": \"<string>\",\n \"keywords\": [\n \"<string>\"\n ]\n }\n ],\n \"generatePrompts\": [\n {\n \"amount\": 25,\n \"instructions\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "6ba7b818-9dad-11d1-80b4-00c04fd430c8",
"name": "North America — core keywords",
"description": "Illustrative monitor for API docs only.",
"active": true,
"models": [
"openai/gpt-4.1",
"anthropic/claude-sonnet-4-20250514"
],
"languageCode": "en-US",
"countryCode": "US",
"latitude": null,
"longitude": null,
"locationAccuracy": null,
"locationName": null,
"promptFrequency": null,
"promptCount": 48,
"responseCount": 620,
"responseCountInRange": 92,
"averageVisibility": 54.25,
"personaName": "Marketing manager",
"personaDescription": null,
"personaAgeRange": null,
"personaEducationLevel": null,
"createdAt": "2026-01-12T10:00:00.000Z",
"updatedAt": "2026-03-30T09:30:00.000Z"
}{
"code": "MONITOR_NOT_FOUND",
"message": "Monitor not found"
}{
"error": "Unauthorized",
"message": "Missing or invalid X-API-Key header."
}{
"error": "Payment Required",
"message": "Cannot create prompt. Your organization has 50 of 50 active prompts. Please upgrade your plan to continue.",
"current": 50,
"limit": 50,
"available": 0
}{
"error": "Unauthorized",
"message": "Missing or invalid X-API-Key header."
}{
"code": "MONITOR_NOT_FOUND",
"message": "Monitor not found"
}Create Monitor
Create a new monitor
curl --request POST \
--url https://server.promptwatch.com/api/v2/monitors \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"name": "<string>",
"models": [
"<string>"
],
"description": "<string>",
"languageCode": "en-US",
"countryCode": "US",
"stateCode": "<string>",
"cityCode": "<string>",
"latitude": 0,
"longitude": 0,
"locationName": "<string>",
"personaId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"personaStackingEnabled": true,
"initialPrompts": [
{
"prompt": "<string>",
"keywords": [
"<string>"
]
}
],
"generatePrompts": [
{
"amount": 25,
"instructions": "<string>"
}
]
}
'import requests
url = "https://server.promptwatch.com/api/v2/monitors"
payload = {
"name": "<string>",
"models": ["<string>"],
"description": "<string>",
"languageCode": "en-US",
"countryCode": "US",
"stateCode": "<string>",
"cityCode": "<string>",
"latitude": 0,
"longitude": 0,
"locationName": "<string>",
"personaId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"personaStackingEnabled": True,
"initialPrompts": [
{
"prompt": "<string>",
"keywords": ["<string>"]
}
],
"generatePrompts": [
{
"amount": 25,
"instructions": "<string>"
}
]
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
models: ['<string>'],
description: '<string>',
languageCode: 'en-US',
countryCode: 'US',
stateCode: '<string>',
cityCode: '<string>',
latitude: 0,
longitude: 0,
locationName: '<string>',
personaId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
personaStackingEnabled: true,
initialPrompts: [{prompt: '<string>', keywords: ['<string>']}],
generatePrompts: [{amount: 25, instructions: '<string>'}]
})
};
fetch('https://server.promptwatch.com/api/v2/monitors', 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://server.promptwatch.com/api/v2/monitors",
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([
'name' => '<string>',
'models' => [
'<string>'
],
'description' => '<string>',
'languageCode' => 'en-US',
'countryCode' => 'US',
'stateCode' => '<string>',
'cityCode' => '<string>',
'latitude' => 0,
'longitude' => 0,
'locationName' => '<string>',
'personaId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'personaStackingEnabled' => true,
'initialPrompts' => [
[
'prompt' => '<string>',
'keywords' => [
'<string>'
]
]
],
'generatePrompts' => [
[
'amount' => 25,
'instructions' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <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://server.promptwatch.com/api/v2/monitors"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"models\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"languageCode\": \"en-US\",\n \"countryCode\": \"US\",\n \"stateCode\": \"<string>\",\n \"cityCode\": \"<string>\",\n \"latitude\": 0,\n \"longitude\": 0,\n \"locationName\": \"<string>\",\n \"personaId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"personaStackingEnabled\": true,\n \"initialPrompts\": [\n {\n \"prompt\": \"<string>\",\n \"keywords\": [\n \"<string>\"\n ]\n }\n ],\n \"generatePrompts\": [\n {\n \"amount\": 25,\n \"instructions\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<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.post("https://server.promptwatch.com/api/v2/monitors")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"models\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"languageCode\": \"en-US\",\n \"countryCode\": \"US\",\n \"stateCode\": \"<string>\",\n \"cityCode\": \"<string>\",\n \"latitude\": 0,\n \"longitude\": 0,\n \"locationName\": \"<string>\",\n \"personaId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"personaStackingEnabled\": true,\n \"initialPrompts\": [\n {\n \"prompt\": \"<string>\",\n \"keywords\": [\n \"<string>\"\n ]\n }\n ],\n \"generatePrompts\": [\n {\n \"amount\": 25,\n \"instructions\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://server.promptwatch.com/api/v2/monitors")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"models\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"languageCode\": \"en-US\",\n \"countryCode\": \"US\",\n \"stateCode\": \"<string>\",\n \"cityCode\": \"<string>\",\n \"latitude\": 0,\n \"longitude\": 0,\n \"locationName\": \"<string>\",\n \"personaId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"personaStackingEnabled\": true,\n \"initialPrompts\": [\n {\n \"prompt\": \"<string>\",\n \"keywords\": [\n \"<string>\"\n ]\n }\n ],\n \"generatePrompts\": [\n {\n \"amount\": 25,\n \"instructions\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "6ba7b818-9dad-11d1-80b4-00c04fd430c8",
"name": "North America — core keywords",
"description": "Illustrative monitor for API docs only.",
"active": true,
"models": [
"openai/gpt-4.1",
"anthropic/claude-sonnet-4-20250514"
],
"languageCode": "en-US",
"countryCode": "US",
"latitude": null,
"longitude": null,
"locationAccuracy": null,
"locationName": null,
"promptFrequency": null,
"promptCount": 48,
"responseCount": 620,
"responseCountInRange": 92,
"averageVisibility": 54.25,
"personaName": "Marketing manager",
"personaDescription": null,
"personaAgeRange": null,
"personaEducationLevel": null,
"createdAt": "2026-01-12T10:00:00.000Z",
"updatedAt": "2026-03-30T09:30:00.000Z"
}{
"code": "MONITOR_NOT_FOUND",
"message": "Monitor not found"
}{
"error": "Unauthorized",
"message": "Missing or invalid X-API-Key header."
}{
"error": "Payment Required",
"message": "Cannot create prompt. Your organization has 50 of 50 active prompts. Please upgrade your plan to continue.",
"current": 50,
"limit": 50,
"available": 0
}{
"error": "Unauthorized",
"message": "Missing or invalid X-API-Key header."
}{
"code": "MONITOR_NOT_FOUND",
"message": "Monitor not found"
}Authorizations
API key for authentication. Get yours from the Promptwatch dashboard under Settings > API Keys.
Body
Monitor name
1List of LLM models to monitor
1Monitor description
Language code
Country code
State code
City code
Latitude of the point ChatGPT, Google AI Overviews and Google AI Mode answer from (requires the Local GEO/SEO Targeting feature). Send together with longitude. Other models use the country, state and city.
-90 <= x <= 90Longitude of the pinned point. Send together with latitude.
-180 <= x <= 180Accuracy radius of the pinned point in meters. Defaults to 50 when coordinates are sent.
20, 50, 100, 500, 1000, 5000, null Name shown for the pinned point, such as an address. Ignored without coordinates.
120Monitor-level tracking frequency. EVERY_12_HOURS, EVERY_6_HOURS and HOURLY require the Hourly Tracking feature (Business and Agency Scale, or enabled per organization); DAILY requires either Hourly Tracking or Custom Prompt Frequency; EVERY_OTHER_DAY, WEEKLY and MONTHLY require the Custom Prompt Frequency feature. Omit or null to inherit the organization's default frequency.
DAILY, EVERY_OTHER_DAY, WEEKLY, MONTHLY, EVERY_12_HOURS, EVERY_6_HOURS, HOURLY, null Persona ID
Inject the persona's stackable prompt around each tracked prompt at run time
Initial prompts to create with the monitor
Show child attributes
Show child attributes
Optional array of generation batches (max 3, one per prompt type). Each entry triggers one independent call to the prompt generator (batches run in parallel; no prompt text from other batches or from initialPrompts is passed as context). Per-entry amount is 1-50; the sum across all entries must also be <= 50.
3Show child attributes
Show child attributes
Response
Default Response
Monitor unique identifier
Monitor name
Whether the monitor is active
List of LLM models being monitored
Language code for the monitor
Country code for the monitor
Latitude of the monitor's pinned point. Null when no point is pinned.
Longitude of the monitor's pinned point. Null when no point is pinned.
Accuracy radius of the pinned point in meters. Null when no point is pinned.
Name of the pinned point. Null when none was given.
Number of prompts in this monitor
Total number of responses across all prompts
Average visibility score for the monitor within the selected date range
Monitor creation timestamp
Monitor last update timestamp
Monitor description
Monitor-level tracking frequency. EVERY_12_HOURS, EVERY_6_HOURS and HOURLY run several times a day on fixed UTC hours. Null inherits the organization's default frequency.
DAILY, EVERY_OTHER_DAY, WEEKLY, MONTHLY, EVERY_12_HOURS, EVERY_6_HOURS, HOURLY Number of responses created within the selected date range
Persona name used for the monitor
Persona description
Persona age range
Persona education level