# cloro — Orthogonal API

> Pay-per-use API on Orthogonal. Each call is billed to your Orthogonal balance.
> Base API: `https://api.orthogonal.com/v1/run` · [llms.txt](https://www.orthogonal.com/llms.txt) · [browse all APIs](https://www.orthogonal.com/catalog)

Monitor AI search answers (ChatGPT, Gemini, Perplexity, Google AI Mode/Overviews, Bing AI Mode) and Google results as structured JSON: parsed text, cited sources, brand entities, shopping results and ads, geo-targeted by country.

**Verified:** no

## Access

**Run API:** `POST https://api.orthogonal.com/v1/run`
**Auth:** `Authorization: Bearer $ORTHOGONAL_API_KEY`
Get an API key at https://www.orthogonal.com/account/keys

Every call goes through the unified Run API: send the API `slug`, the endpoint `path`, and the `query`/`body` parameters. The response is `{ "success": true, "price": "<usd>", "data": { ... } }`.

## Endpoints

### Google product details

Get a Google shopping card product: the product panel (offers, specs, reviews, images) for a productResultToken from a Google Search or AI Mode result. Tokens expire five minutes after the issuing scrape.

`POST /v1/monitor/google/product`

**Estimated cost:** $0.002616

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `productResultToken` | string | Yes | The `productResultToken` from a Google Search shopping card, or from a Google AI Mode shopping card or inline product. The token carries the query, locale and location of the request that issued it, so the request takes no other field. |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/google/product","body":{"productResultToken":"<string>"}}'
```

### Gemini answer monitoring

Monitor Gemini Responses: runs a prompt on Google Gemini from a chosen country and returns the answer text and cited sources, with optional Markdown/HTML.

`POST /v1/monitor/gemini`

**Estimated cost:** Dynamic — use `"dryRun": true` in the Run API request to check the exact cost before calling.

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `prompt` | string | Yes | The prompt to send to Gemini |
| `country` | string | Yes | Country/region code for localized response, using ISO 3166-1 alpha-2 country codes. |
| `include` | object | No | Optional flags for including additional response formats |
| `state` | string | No | State code for sub-country geo-targeting (e.g., "CA"). Only valid with country "US". Paid add-on: +2 credits, on top of the base cost and any other add-on ([pricing](/guides/providers#state-level-targeting)). |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/gemini","body":{"prompt":"<string>","country":"<string>","include":"<object>","state":"<string>"}}'
```

### Google search results

Monitor Google Search Results: organic results, People Also Ask, related searches, ads, shopping and optional AI Overview for a query, 1-10 pages, geo-targeted.

`POST /v1/monitor/google`

**Estimated cost:** Dynamic — use `"dryRun": true` in the Run API request to check the exact cost before calling.

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `query` | string | No | The search query to execute on Google. Required unless you supply 'url' instead — the two are mutually exclusive. |
| `url` | string | No | A complete Google web search URL to run instead of building the request from 'query' and the targeting fields. Must be an absolute http(s) URL on a Google web search host (google.com, google.co.uk, www.google.de, ...), with the path '/search' and a non-empty 'q'. Mutually exclusive with 'query', 'location', 'uule' and 'pages' — the URL owns those values. cloro applies a fixed set of query parameters — 'q', 'gl', 'hl', 'uule', 'num' (read as result depth), 'start', 'tbs' and 'safe' — and drops an |
| `country` | string | No | ISO 3166-1 alpha-2 country code for localized search results. See [List of countries](/api-reference/endpoint/countries) for the codes each provider supports. Required in the standard request shape unless you send `gl`. When you supply 'url' instead, country is derived from the URL's 'gl' — pass it explicitly to override that, or when the URL has no 'gl'. |
| `gl` | string | No | Alternative to `country`, using Google's own parameter name for the result geography. Same ISO 3166-1 alpha-2 codes, accepted in either case (`us` or `US`), and must be a country the endpoint supports — see `GET /v1/countries`. Provide `country` or `gl`; sending both with different values is a `400`. |
| `hl` | string | No | Interface language, as Google's own `hl` parameter (e.g. `en`, `de`, `pt-BR`). Free-form and case-insensitive — Google owns the list of codes. Overrides the language cloro derives from the country, so the interface language and the result geography can differ. |
| `location` | string | No | Google canonical location name for geo-targeted results, in comma-separated format: 'City,Region,Country' (see https://developers.google.com/google-ads/api/reference/data/geotargets for all ~100,000 supported locations). Use alongside 'country' for city-level precision. Mutually exclusive with 'uule' — provide one or the other, not both. Cannot be combined with 'url'. When both `location` and `uule` are omitted, cloro pins results to the country's canonical location (e.g. `Portugal` for `PT`) wh |
| `uule` | string | No | Pre-encoded Google UULE string for precise geo-targeting. Use this when you have a pre-built UULE value instead of a location name. Mutually exclusive with 'location' — provide one or the other, not both. Cannot be combined with 'url'; put 'uule' in the URL's query string instead. |
| `device` | string | No | Device the search is run from. 'desktop' returns the desktop SERP; 'ios' (Safari on iPhone), 'android' (Chrome on Android) and 'mobile' (alias for 'android') all return the mobile SERP. |
| `pages` | integer | No | Number of search results pages to scrape (1-10). Paid add-on: +2 credits per page after the first ([pricing](/guides/providers#google-search-multi-page-pricing)). Cannot be combined with 'url' — in that shape, depth comes from the URL's 'num' (rounded up to whole pages of 10, capped at 10 pages). |
| `include` | object | No | Optional flags for including additional response data |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/google","body":{"query":"<string>","url":"<string>","country":"<string>","gl":"<string>","hl":"<string>","location":"<string>","uule":"<string>","device":"<string>","pages":"<integer>","include":"<object>"}}'
```

### ChatGPT answer monitoring

Monitor ChatGPT Responses: runs a prompt (or up to 5-turn conversation) on ChatGPT from a chosen country and returns answer text, cited sources, entities, and optionally shopping cards, query fan-out, ads and raw response.

`POST /v1/monitor/chatgpt`

**Estimated cost:** Dynamic — use `"dryRun": true` in the Run API request to check the exact cost before calling.

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `prompt` | string | Yes | The prompt to send to ChatGPT, or an array of up to 5 prompts for a multi-turn conversation. With an array, ChatGPT answers the prompts in order, in the same conversation, and `result` is an array with one response for each prompt. Each prompt after the first costs +1 credit ([pricing](/guides/providers#chatgpt-additional-features)). |
| `country` | string | Yes | Country/region code for localized response, using ISO 3166-1 alpha-2 country codes. |
| `include` | object | No | Optional flags for including additional response formats |
| `legacy` | boolean | No | Serve ChatGPT's legacy desktop interface instead of the default mobile-web one. The legacy interface streams the answer as an event stream, so `result.model`, `result.searchQueries` and `result.mapSearchQueries` are populated. ChatGPT shows ads far more often on this interface. Best-effort and temporary: OpenAI controls which interface it serves and can retire the legacy one at any time, so a request can still come back in the mobile-web shape. Handle both. Defaults to false. |
| `disableWebSearch` | boolean | No | Do not force ChatGPT's web search. cloro returns the answer ChatGPT gives on its own, which uses web search only when ChatGPT decides to, so `result.sources`, `result.citationPills` and `result.searchQueries` are often empty. Defaults to false: web search is forced on every request. |
| `state` | string | No | State code for sub-country geo-targeting (e.g., "CA"). Only valid with country "US". Paid add-on: +2 credits, on top of the base cost and any other add-on ([pricing](/guides/providers#state-level-targeting)). |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/chatgpt","body":{"prompt":"<string>","country":"<string>","include":"<object>","legacy":"<boolean>","disableWebSearch":"<boolean>","state":"<string>"}}'
```

### Google redirect resolver

Resolve a Google redirect link: returns the destination URL of one redirectLink from a Google Search, Google News or AI Mode response.

`POST /v1/monitor/google/goto`

**Estimated cost:** $0.000872

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `url` | string | Yes | The Google redirect link to resolve, as an absolute URL. Must be a `google.com` or `www.google.com` link with a `/goto` or `/url` path — the form shipped as `redirectLink` beside every resolved link on Google Search, Google News, and AI Mode responses. |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/google/goto","body":{"url":"<string>"}}'
```

### Google News results

Monitor Google News Results: news articles (titles, links, snippets, sources, dates, thumbnails) for a query, 1-10 pages.

`POST /v1/monitor/google/news`

**Estimated cost:** Dynamic — use `"dryRun": true` in the Run API request to check the exact cost before calling.

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `query` | string | Yes | The search query to execute on Google News |
| `country` | string | No | ISO 3166-1 alpha-2 country code for localized news results. See [List of countries](/api-reference/endpoint/countries) for the codes each provider supports. |
| `gl` | string | No | Alternative to `country`, using Google's own parameter name for the result geography. Same ISO 3166-1 alpha-2 codes, accepted in either case (`us` or `US`), and must be a country the endpoint supports — see `GET /v1/countries`. Provide `country` or `gl`; sending both with different values is a `400`. |
| `hl` | string | No | Interface language, as Google's own `hl` parameter (e.g. `en`, `de`, `pt-BR`). Free-form and case-insensitive — Google owns the list of codes. Overrides the language cloro derives from the country, so the interface language and the result geography can differ. |
| `device` | string | No | Device the search is run from. 'desktop' returns the desktop news SERP; 'ios' (Safari on iPhone), 'android' (Chrome on Android) and 'mobile' (alias for 'android') all return the mobile news SERP. |
| `pages` | integer | No | Number of news results pages to scrape (1-10). Paid add-on: +2 credits per page after the first ([pricing](/guides/providers#google-search-multi-page-pricing)). |
| `include` | object | No | Optional flags for including additional response data |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/google/news","body":{"query":"<string>","country":"<string>","gl":"<string>","hl":"<string>","device":"<string>","pages":"<integer>","include":"<object>"}}'
```

### Google AI Mode monitoring

Monitor AI Mode Responses: runs a prompt on Google AI Mode, geo-targeted by country or city, and returns the answer, sources and products.

`POST /v1/monitor/aimode`

**Estimated cost:** $0.005232

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `prompt` | string | Yes | The prompt to send to AI Mode |
| `country` | string | No | Country/region code for localized response, using ISO 3166-1 alpha-2 country codes. |
| `gl` | string | No | Alternative to `country`, using Google's own parameter name for the result geography. Same ISO 3166-1 alpha-2 codes, accepted in either case (`us` or `US`), and must be a country the endpoint supports — see `GET /v1/countries`. Provide `country` or `gl`; sending both with different values is a `400`. |
| `hl` | string | No | Interface language, as Google's own `hl` parameter (e.g. `en`, `de`, `pt-BR`). Free-form and case-insensitive — Google owns the list of codes. Overrides the language cloro derives from the country, so the interface language and the result geography can differ. |
| `location` | string | No | Google canonical location name for geo-targeted results, in comma-separated format: 'City,Region,Country' (see https://developers.google.com/google-ads/api/reference/data/geotargets for all ~100,000 supported locations). Use alongside 'country' for city-level precision. Mutually exclusive with 'uule' — provide one or the other, not both. When both `location` and `uule` are omitted, cloro pins results to the country's canonical location (e.g. `Portugal` for `PT`) where it has one; otherwise Googl |
| `uule` | string | No | Pre-encoded Google UULE string for precise geo-targeting. Use this when you have a pre-built UULE value instead of a location name. Mutually exclusive with 'location' — provide one or the other, not both. |
| `device` | string | No | Device type for search results |
| `include` | object | No | Optional flags for including additional response formats |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/aimode","body":{"prompt":"<string>","country":"<string>","gl":"<string>","hl":"<string>","location":"<string>","uule":"<string>","device":"<string>","include":"<object>"}}'
```

### Bing AI Mode monitoring

Monitor Bing AI Mode Responses: the answer, sources and citation pills from Bing AI Mode (Copilot Search) for a prompt in a chosen country.

`POST /v1/monitor/bing/aimode`

**Estimated cost:** Dynamic — use `"dryRun": true` in the Run API request to check the exact cost before calling.

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `prompt` | string | Yes | The prompt to send to Bing AI Mode. Bing puts the prompt in the page URL, so the limit is 3,500 characters after URL encoding. A letter, digit or space counts as 1, most punctuation as 3, an accented or Cyrillic letter as 6, and a Chinese, Japanese or Korean character as 9. Thus a CJK prompt can have a maximum of 388 characters. A longer prompt returns a 400 error: "Prompt is too long (max 3,500 characters, fewer for non-Latin scripts)". |
| `country` | string | Yes | Country/region code for localized response, using ISO 3166-1 alpha-2 country codes. Bing AI Mode accepts all countries except KR and RU. `GET /v1/countries?model=bing_aimode` returns the list. |
| `state` | string | No | State code for sub-country geo-targeting (e.g., "CA"). Only valid with country "US". Paid add-on: +2 credits, on top of the base cost and any other add-on ([pricing](/guides/providers#state-level-targeting)). |
| `include` | object | No | Optional flags for including additional response formats |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/monitor/bing/aimode","body":{"prompt":"<string>","country":"<string>","state":"<string>","include":"<object>"}}'
```

### Supported countries

List of countries: ISO country codes supported, optionally filtered by provider (model).

`GET /v1/countries`

**Cost:** Free

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `model` | string | No | Filter countries available for a specific model. Omit to return all supported countries. |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/countries","method":"GET","query":{"model":"<string>"}}'
```

### Supported US states

List of states: US state codes supported for state-level targeting.

`GET /v1/states`

**Cost:** Free

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `country` | string | Yes | ISO 3166-1 alpha-2 country code. Only "US" returns results. |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/states","method":"GET","query":{"country":"<string>"}}'
```

### Async scrape task

Create async task: queue one scrape (ChatGPT, Gemini, Perplexity, AI Mode, Bing AI Mode, Google, Google News or Google product) for background processing; returns a task ID to poll, optionally delivered to a webhook.

`POST /v1/async/task`

**Estimated cost:** Dynamic — use `"dryRun": true` in the Run API request to check the exact cost before calling.

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `taskType` | string | Yes | The AI provider to use for this task. |
| `payload` | object | Yes | The provider's request body, validated against the same schema as its sync endpoint (for example `ChatGPTMonitorRequest`). That makes `country` required here too, or `gl` on the Google endpoints. For `GOOGLE_PRODUCT`, send only `productResultToken`. |
| `priority` | integer | No | Task priority level (1-10). Higher numbers are processed first. Defaults to 1. |
| `idempotencyKey` | string | No | Unique string to prevent duplicate task creation. Must be unique across your account. |
| `webhook` | object | No | Webhook configuration for task completion notification. |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/async/task","body":{"taskType":"<string>","payload":"<object>","priority":"<integer>","idempotencyKey":"<string>","webhook":"<object>"}}'
```

### Batch async tasks

Create batch async tasks: queue up to 500 scrape tasks in one request; each is validated independently and returns its own task ID.

`POST /v1/async/task/batch`

**Estimated cost:** Dynamic — use `"dryRun": true` in the Run API request to check the exact cost before calling.

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `taskType` | string | Yes | The AI provider to use for this task. |
| `payload` | object | Yes | The provider's request body, validated against the same schema as its sync endpoint (for example `ChatGPTMonitorRequest`). That makes `country` required here too, or `gl` on the Google endpoints. For `GOOGLE_PRODUCT`, send only `productResultToken`. |
| `priority` | integer | No | Task priority level (1-10). Higher numbers are processed first. Defaults to 1. |
| `idempotencyKey` | string | No | Unique string to prevent duplicate task creation. Must be unique across your account. |
| `webhook` | object | No | Webhook configuration for task completion notification. |

```bash
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/async/task/batch","body":[{"taskType":"<string>","payload":"<object>","priority":"<integer>","idempotencyKey":"<string>","webhook":"<object>"}]}'
```

### Async task result

Get async task status: the status of a task you created and, once completed, its full result. Tasks are deleted 24 hours after finishing.

`GET /v1/async/task/{taskId}`

**Cost:** Free

**Docs:** https://cloro.dev/docs

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `taskId` | string | Yes | Path parameter — substitute directly into the endpoint `path`. |

```bash
# Replace {taskId} in "path" with real values before sending
curl -X POST 'https://api.orthogonal.com/v1/run' \
  -H 'Authorization: Bearer $ORTHOGONAL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"api":"cloro","path":"/v1/async/task/{taskId}","method":"GET"}'
```

---

Full details and an interactive quickstart: https://www.orthogonal.com/publisher/cloro
