Skip to main content
This guide covers the basics of making requests to the cloro API, including synchronous and asynchronous requests.

Synchronous Requests

All cloro API monitoring endpoints follow a consistent request and response structure.

Request structure

All monitoring endpoints follow a consistent request structure:
{
  "prompt": "Your query here (1-10,000 characters)",
  "country": "US", // Optional, defaults to "US"
  "include": {
    // Optional, varies by endpoint
    "markdown": false,
    "html": false
  }
}

Common parameters

All monitoring endpoints share these core parameters:
ParameterTypeRequiredDescription
promptstringYesThe query to send to the AI provider (1-10,000 characters)
countrystringNoISO 3166-1 alpha-2 country code for localized results. Defaults to "US"
includeobjectNoOptional flags for additional response formats

Country codes

The API supports country-specific monitoring. Common examples are US (United States) and GB (United Kingdom). For a complete list, see the Countries endpoint.

Response structure

All successful responses follow this base structure:
{
  "success": true,
  "result": {
    "text": "AI response text",
    "sources": [...],
    "html": "<div>Formatted response</div>",  // Only included when "include.html": true
    // Additional fields vary by endpoint
  }
}

Common response fields

FieldTypeDescription
successbooleanAlways true for successful responses
result.textstringThe AI provider’s response text
result.sourcesarrayArray of sources referenced in the response
result.htmlstringResponse formatted in HTML (included when include.html is true)

Sources array structure

Each source in the sources array follows this format:
{
  "position": 1,
  "url": "https://example.com/article",
  "label": "Example Site",
  "description": "Description of the source content"
}

Optional response formats

Most endpoints support additional response formats through the include parameter:

HTML format

  • Parameter: include.html
  • Type: boolean
  • Default: false
  • Description: Include response formatted in HTML
  • Cost: Varies by endpoint (usually +0 credits)

Markdown format

  • Parameter: include.markdown
  • Type: boolean
  • Default: false
  • Description: Include response formatted in Markdown
  • Cost: Varies by endpoint (usually +0 credits)

Endpoint-specific formats

Different endpoints offer unique formats. See individual endpoint documentation for specific options and features available for each monitoring endpoint. See Pricing for endpoint costs and credit information.

Request examples

curl -X POST "https://api.cloro.dev/v1/monitor/chatgpt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type": application/json" \
  -d
    '{
      "prompt": "What do you know about Acme Corp?",
      "country": "US",
      "include": {
        "markdown": true,
        "html": true
      }
    }'
import requests

response = requests.post(
    "https://api.cloro.dev/v1/monitor/chatgpt",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "What do you know about Acme Corp?",
        "country": "US",
        "include": {"markdown": True, "html": True}
    }
)

result = response.json()
print(result['result']['text'])
print(result['result']['sources'])
if 'html' in result['result']:
    print(result['result']['html'])
if 'markdown' in result['result']:
    print(result['result']['markdown'])
const response = await fetch("https://api.cloro.dev/v1/monitor/chatgpt", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt: "What do you know about Acme Corp?",
    country: "US",
    include: { markdown: true, html: true },
  }),
});

const data = await response.json();
console.log(data.result.text);
console.log(data.result.sources);
if (data.result.html) {
  console.log(data.result.html);
}
if (data.result.markdown) {
  console.log(data.result.markdown);
}

Asynchronous Requests

Think of an asynchronous (async) request like sending a package with a tracking number. Instead of waiting at the post office until the package is delivered (a synchronous process), you hand it over, get a taskId (your tracking number), and are free to do other things. You can then either receive a delivery notification (a webhook) or check the tracking status online yourself (polling). Our async API works the same way. You submit a task, we give you a taskId, and we process your request in the background.

When to use async requests

This approach is ideal when:
  • Your application, especially if it’s running in a serverless environment, has short execution time limits.
  • You want to submit a large number of requests quickly without waiting for each one to complete.
  • You need to build a more resilient system that isn’t dependent on a single, long-running connection.

How it works: a two-step process

The entire process involves two simple steps: making a request and then fetching the result.

Step 1: make an API request

First, you send an API request. If you include a webhook.url, we’ll notify you when the job is done. If you omit it, you will need to poll for the result.
curl -X POST "https://api.cloro.dev/v1/async/task" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type": application/json" \
  -d 
    "{
    "taskType": "CHATGPT",
    "idempotencyKey": "your-custom-identifier-123",
    "webhook": {
      "url": "https://your-app.com/webhook-handler"
    },
    "payload": {
      "prompt": "What is the weather in New York?",
      "country": "US"
    }
  }"
Identifying your requests with idempotencyKeyYou can optionally include an idempotencyKey in your request. This is a unique string you create that allows you to easily identify and reference your requests in your own system.
We’ll acknowledge your request and provide a taskId.
{
  "success": true,
  "task": {
    "id": "b27a21e1-7c39-4aa2-a347-23e828c426f9",
    "taskType": "CHATGPT",
    "status": "QUEUED",
    "createdAt": "2025-11-10T15:00:00.000Z",
    "idempotencyKey": "your-custom-identifier-123"
  },
  "credits": {
    "creditsToCharge": 10,
    "creditsCharged": 0
  }
}
Now, you can store this taskId and wait for the results.

Step 2: receive the results

You have two options for retrieving the results of your task.
Option A: Webhooks (Recommended)
A webhook is an automated message sent from our servers to yours when your task is complete. If you provided a webhook.url in your request, we will send an HTTP POST request to that URL containing the full result.
{
  "task": {
    "id": "b27a21e1-7c39-4aa2-a347-23e828c426f9",
    "taskType": "CHATGPT",
    "status": "COMPLETED",
    "createdAt": "2025-11-10T15:00:00.000Z",
    "idempotencyKey": "your-custom-identifier-123"
  },
  "credits": {
    "creditsToCharge": 10,
    "creditsCharged": 10
  },
  "response": {
    "model": "gpt-5-mini",
    "text": "The weather in New York is currently sunny...",
    "html": "<p>The weather in New York is currently sunny...</p>",
    "sources": [],
    "shoppingCards": [],
    "entities": [],
    "markdown": "The weather in New York is currently sunny...",
    "searchQueries": ["weather in New York"]
  }
}
Responding to a webhook To let us know you’ve received the webhook, your server must respond with a 2xx status code (e.g., 200 OK). If we don’t receive a successful response, we’ll try again. We will attempt to deliver a webhook up to 5 times with an exponential backoff strategy. If an attempt fails, the next one will be scheduled for:
  • Attempt 2: ~2 minutes later
  • Attempt 3: ~4 minutes later
  • Attempt 4: ~8 minutes later
  • Attempt 5: ~16 minutes later
// Example: A simple server endpoint to receive the webhook
app.post('/webhook-handler', (req, res) => {
  // It's best to process the result asynchronously
  console.log(req.body);

// Immediately send a 200 OK to acknowledge receipt
res.status(200).send();
});

Option B: Polling
If you don’t provide a webhook URL, you can periodically check for the result yourself. This is called “polling.” You can make a GET request to our Get task status endpoint using the taskId you received in Step 1. Once the task is complete, the response will contain the full result.
curl -X GET "https://api.cloro.dev/v1/async/task/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"

Understanding Limits

The asynchronous system has a two-step process for handling limits to provide both flexibility and fairness.

1. Task Submission Limits

When you submit a task, we only check two things:
  • Credit Limit: We verify you have enough credits for the task.
  • Queue Limit: Your organization can have a maximum of 100,000 tasks waiting in the queue. If you exceed this, you will receive a 429 Too Many Requests error. Please contact our team if you need this limit increased.

2. Task Processing Limits

Once your task is in the queue, our scheduler picks it up for processing. This is where your subscription’s concurrency limit is enforced. For example, if your plan allows 10 concurrent requests, our scheduler will process up to 10 of your tasks in parallel. Tasks are processed in the order they were received (FIFO).
For practical concurrency patterns and examples, see our concurrency documentation.