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"
}
}{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "API key rate limit exceeded",
"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"
}
}{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "API key rate limit exceeded",
"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 |
aimodeaioverviewchatgptcopilotgeminigooglegrokperplexity
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. The docs don’t publish a static country list or total count because coverage varies by provider and changes over time —GET /v1/countries is the source of truth. To confirm a specific country, call the endpoint (with model=<provider> for the provider you plan to use) and check whether its ISO 3166-1 alpha-2 code appears in the response. See the request examples above.
My request is rejected with a “model not available in country” 400 even though the code is a valid ISO country. Why?
Two lists are at play, and they are not the same:- The
countryparameter accepts any ISO 3166-1 alpha-2 code at the schema level, so a code likeCZpasses basic validation. - Each AI provider has its own availability list — the subset of those ISO codes cloro can actually route to for that model. When the code passes schema validation but is not in the model’s availability list, the monitor endpoint rejects the request with a
400whosedetailsinclude a “model not available in country” message.
GET /v1/countries?model=<provider> and confirm the code is in the response before sending a monitor request. If it is present and the request still fails, see Why is ChatGPT (or Copilot) suddenly failing for a specific country? — some providers intermittently require login in specific regions, which blocks the anonymous session cloro uses.
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
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?