List of countries
curl --request GET \
--url https://api.cloro.dev/v1/countries \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.cloro.dev/v1/countries"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.cloro.dev/v1/countries', 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.cloro.dev/v1/countries",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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.cloro.dev/v1/countries"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cloro.dev/v1/countries")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloro.dev/v1/countries")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body[
"AF",
"AX",
"AL",
"DZ",
"AS"
]{
"success": false,
"error": "Request validation failed",
"details": [
{
"field": "prompt",
"message": "Prompt cannot be empty"
}
]
}{
"error": {
"code": "MISSING_API_KEY",
"message": "Missing or invalid API key",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Route not found",
"details": {
"id": "/v1/invalid-endpoint"
},
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": "Maximum retries exceeded"
}Utilities
List of countries
Returns a list of all supported ISO 3166-1 alpha-2 country codes. Can be filtered by model to get countries available for specific AI providers.
GET
/
v1
/
countries
List of countries
curl --request GET \
--url https://api.cloro.dev/v1/countries \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.cloro.dev/v1/countries"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.cloro.dev/v1/countries', 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.cloro.dev/v1/countries",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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.cloro.dev/v1/countries"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cloro.dev/v1/countries")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloro.dev/v1/countries")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body[
"AF",
"AX",
"AL",
"DZ",
"AS"
]{
"success": false,
"error": "Request validation failed",
"details": [
{
"field": "prompt",
"message": "Prompt cannot be empty"
}
]
}{
"error": {
"code": "MISSING_API_KEY",
"message": "Missing or invalid API key",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Route not found",
"details": {
"id": "/v1/invalid-endpoint"
},
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": "Maximum retries exceeded"
}Returns the ISO 3166-1 alpha-2 country codes supported by the monitoring API, optionally filtered to one AI provider.
Available model values:
Request parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
model | string | Optional. Filter countries available for a specific model. If not provided, returns all supported countries. An unrecognized value returns 400. | chatgpt |
aimodeaioverviewchatgptcopilotgeminigoogleperplexity
Example usage
Basic request
curl -X GET "https://api.cloro.dev/v1/countries" \
-H "Authorization: Bearer YOUR_API_KEY"
["AF", "AX", "AL", "DZ", "AS", "AD"]
Filter by model
curl -X GET "https://api.cloro.dev/v1/countries?model=chatgpt" \
-H "Authorization: Bearer YOUR_API_KEY"
["US", "GB", "CA", "AU", "DE"]
import requests
response = requests.get(
"https://api.cloro.dev/v1/countries",
params={"model": "perplexity"},
headers={"Authorization": "Bearer YOUR_API_KEY"}
)
countries = response.json()
print(countries)
const fetch = require('node-fetch');
const response = await fetch('https://api.cloro.dev/v1/countries?model=google', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const countries = await response.json();
console.log(countries);
Caching
The country list rarely changes, so fetch it when your application starts and cache it for 24 hours or more. Use the cached model-filtered list to populate your country picker and to validate input before a monitor request goes out, and keep a fallback in case the endpoint is briefly unavailable.Common questions
Which countries are supported?
cloro supports country-level targeting for nearly all countries. See the request examples above for how to query all countries or filter by specific provider.How do I target multiple countries or run a “global” query?
country takes a single ISO 3166-1 alpha-2 code. There is no wildcard, “global”, or multi-country value. To cover several markets, send one request per country and merge the results client-side — use async tasks or batch tasks to fan out.
Can I target specific cities or states?
US state-level targeting is available on ChatGPT, Copilot, Perplexity, Gemini, and Grok via thestate parameter. Use the States endpoint to get the full list of supported codes.
The Google Search and AI Mode endpoints support city-level geo-targeting via the location parameter, which accepts Google canonical location names. Google Search covers AI Overview too, since AI Overview is requested through it with include.aioverview.
What’s supported:
- ✅ Country-level targeting using ISO 3166-1 alpha-2 codes (e.g.,
US,GB,JP) on all endpoints - ✅ State-level targeting via
stateparameter (e.g.,CA,NY,TX) on ChatGPT, Copilot, Perplexity, Gemini, and Grok (US only for now) - ✅ City-level targeting via
locationparameter (e.g.,New York,New York,United States) on Google Search (including AI Overview) and AI Mode
- ❌ City-level targeting on Google News — it accepts
countryonly, notlocation/uule - ❌ State-level targeting on Google Search or AI Mode (use
location/uuleinstead) - ❌ State-level targeting outside the US
- ❌ Metro/region targeting
- ❌ Zip/postal code targeting
- ❌ Latitude/longitude coordinates
Why are my geo-targeted requests returning unexpected results?
- Invalid country codes: use ISO 3166-1 alpha-2 codes (two-letter format).
-
Non-canonical
locationstrings:locationis not validated against Google’s geotargets list. A string that isn’t a canonical name is accepted and encoded as-is rather than rejected, and Google falls back to broader targeting — typically country level. You get a200with country-level results, not an error, so verify the exact canonical name (City,Region,Country) before assuming city targeting applied. - Provider limitations: coverage varies by provider and region.
- Prompt language mismatch: English prompts in non-English countries may affect result quality.
How does geo-targeting work?
Thecountry parameter routes your request through servers in or near the target region.
What geo-targeting affects:
- Search results and web sources
- Local business information
- Regional product availability (shopping cards)
- Language and cultural context
- Time zones and date formats
- API pricing (same cost regardless of country)
- Response format or structure
- Available features or endpoints
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Query Parameters
Filter countries available for a specific model
Available options:
aimode, aioverview, chatgpt, copilot, gemini, google, grok, perplexity Response
List of supported country codes
Example:
["AF", "AX", "AL", "DZ", "AS"]
Was this page helpful?
⌘I