---
title: "Chat API"
description: "Start conversations, send messages, stream replies, pass user data and read conversation history with the Chat Thing REST API."
canonical_url: "https://chatthing.ai/docs/developers/chat-api"
last_updated: "2026-09-25"
---

# Chat API

**Available on:** Standard, Pro, Enterprise plans.

Use the Chat API to talk to your bot from your own app, backend or integration: start a conversation, send messages, stream replies and read back the history.

> **Before you start**
>
> You need the API channel turned on for your bot, its **Channel ID** and a **Secret key**. The API channel is on the Standard, Pro and Enterprise plans. See [API overview](https://chatthing.ai/docs/developers/api-overview#authentication) for how to get them, the base URL, versions and error codes.

All examples use version `2.0`. Every endpoint below also works on `1.0`, with identical requests and responses except for [streaming](https://chatthing.ai/docs/developers/chat-api#stream-replies).

## Endpoints

| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/api/public/channels/{channelId}/2.0/conversation` | [Start a conversation](https://chatthing.ai/docs/developers/chat-api#start-a-conversation) |
| `POST` | `/api/public/channels/{channelId}/2.0/message` | [Send a message](https://chatthing.ai/docs/developers/chat-api#send-a-message), [continue a conversation](https://chatthing.ai/docs/developers/chat-api#continue-a-conversation) or [stream the reply](https://chatthing.ai/docs/developers/chat-api#stream-replies) |
| `POST` | `/api/public/channels/{channelId}/2.0/conversations` | [List conversations](https://chatthing.ai/docs/developers/chat-api#list-conversations) |
| `POST` | `/api/public/channels/{channelId}/2.0/messages` | [List a conversation's messages](https://chatthing.ai/docs/developers/chat-api#list-a-conversations-messages) |

## Start a conversation

Creates a conversation and returns its `conversationId` and the bot's welcome message. Start here if you want to attach [user data](https://chatthing.ai/docs/developers/chat-api#pass-user-data) to the conversation, or if you'll stream replies.

```text
POST /api/public/channels/{channelId}/2.0/conversation
```

### Request body

The body is optional.

| Field | Type | Description |
| --- | --- | --- |
| `userData` | object | Optional. Details about the person chatting, such as `name`, `email` or your own `id`. Saved on the conversation. See [Pass user data](https://chatthing.ai/docs/developers/chat-api#pass-user-data) |
| `message` | string | Optional. Included as `initialMessage` in the [Conversation started webhook](https://chatthing.ai/docs/developers/webhooks#conversation-started-webhook). It isn't sent to the bot: use [Send a message](https://chatthing.ai/docs/developers/chat-api#send-a-message) for that |

**curl**

```bash
curl --request POST \
  --url https://app.chatthing.ai/api/public/channels/{channelId}/2.0/conversation \
  --header 'Content-Type: application/json' \
  --header 'X-API-Secret-Key: {secretKey}' \
  --data '{
    "userData": { "id": "user_1234", "name": "Alex Doe", "email": "alex@example.com" }
  }'
```

**JavaScript**

```javascript
const response = await fetch(
  `https://app.chatthing.ai/api/public/channels/${channelId}/2.0/conversation`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Secret-Key": secretKey,
    },
    body: JSON.stringify({
      userData: { id: "user_1234", name: "Alex Doe", email: "alex@example.com" },
    }),
  },
);
const { conversationId } = await response.json();
```

**Python**

```python
import requests

url = f"https://app.chatthing.ai/api/public/channels/{channel_id}/2.0/conversation"
headers = {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secret_key,
}
payload = {
    "userData": {"id": "user_1234", "name": "Alex Doe", "email": "alex@example.com"}
}

response = requests.post(url, json=payload, headers=headers)
conversation_id = response.json()["conversationId"]
```

### Response

| Field | Type | Description |
| --- | --- | --- |
| `success` | boolean | `true` when the conversation was created |
| `conversationId` | string | Use this in later requests to continue the conversation |
| `response` | string | The bot's welcome message |

```json
{
  "success": true,
  "conversationId": "7bb301ad-e691-4341-8afb-b4407c4ffdf2",
  "response": "Hello, how can I help you?"
}
```

If a token limit has been reached, you get `429` with a plain `statusMessage`. See [Usage limits](https://chatthing.ai/docs/developers/api-overview#usage-limits).

## Send a message

Sends a message to the bot and returns its full reply. If you don't include a `conversationId`, a new conversation is created and its id is returned, so you can continue it later.

```text
POST /api/public/channels/{channelId}/2.0/message
```

### Request body

| Field | Type | Description |
| --- | --- | --- |
| `message` | string | Required. The message to the bot |
| `conversationId` | string | Optional. Continue an existing conversation. Without it, a new conversation is started |
| `stream` | boolean | Optional. Set to `true` to [stream the reply](https://chatthing.ai/docs/developers/chat-api#stream-replies) |
| `extendSystemMessage` | string | Optional. Extra instructions added to the bot's instructions, for this request only. Ignored if `overrideSystemMessage` is set |
| `overrideSystemMessage` | string | Optional. Replaces the bot's instructions, for this request only |
| `extendContext` | object | Optional. Extra information for the bot, for this request only. See [Add context](https://chatthing.ai/docs/developers/chat-api#add-context) |
| `userData` | object | Optional. `id` (string or number), `name`, `email`, `tel`. See [Pass user data](https://chatthing.ai/docs/developers/chat-api#pass-user-data) |

**curl**

```bash
curl --request POST \
  --url https://app.chatthing.ai/api/public/channels/{channelId}/2.0/message \
  --header 'Content-Type: application/json' \
  --header 'X-API-Secret-Key: {secretKey}' \
  --data '{
    "message": "What are your opening hours?"
  }'
```

**JavaScript**

```javascript
const response = await fetch(
  `https://app.chatthing.ai/api/public/channels/${channelId}/2.0/message`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Secret-Key": secretKey,
    },
    body: JSON.stringify({ message: "What are your opening hours?" }),
  },
);
const { conversationId, response: reply } = await response.json();
```

**Python**

```python
import requests

url = f"https://app.chatthing.ai/api/public/channels/{channel_id}/2.0/message"
headers = {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secret_key,
}

response = requests.post(url, json={"message": "What are your opening hours?"}, headers=headers)
data = response.json()
```

A request using the optional fields:

**curl**

```bash
curl --request POST \
  --url https://app.chatthing.ai/api/public/channels/{channelId}/2.0/message \
  --header 'Content-Type: application/json' \
  --header 'X-API-Secret-Key: {secretKey}' \
  --data '{
    "message": "Can I change my delivery date?",
    "extendSystemMessage": "Keep answers under three sentences.",
    "extendContext": { "custom": { "plan": "Pro", "orderCount": 3 } }
  }'
```

**JavaScript**

```javascript
await fetch(`https://app.chatthing.ai/api/public/channels/${channelId}/2.0/message`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secretKey,
  },
  body: JSON.stringify({
    message: "Can I change my delivery date?",
    extendSystemMessage: "Keep answers under three sentences.",
    extendContext: { custom: { plan: "Pro", orderCount: 3 } },
  }),
});
```

**Python**

```python
import requests

url = f"https://app.chatthing.ai/api/public/channels/{channel_id}/2.0/message"
headers = {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secret_key,
}
payload = {
    "message": "Can I change my delivery date?",
    "extendSystemMessage": "Keep answers under three sentences.",
    "extendContext": {"custom": {"plan": "Pro", "orderCount": 3}},
}

response = requests.post(url, json=payload, headers=headers)
```

### Response

| Field | Type | Description |
| --- | --- | --- |
| `success` | boolean | `true` when the bot replied |
| `conversationId` | string | The conversation this message belongs to |
| `response` | string | The bot's reply |

```json
{
  "success": true,
  "conversationId": "ea74ba3d-6645-4a88-92d1-7f78b1f83688",
  "response": "We're open 9am to 5pm, Monday to Friday."
}
```

### Errors

| Code | When |
| --- | --- |
| `400` | `message` is missing, or a field has the wrong type |
| `403` | The secret key doesn't match this channel |
| `404` | The channel isn't found or is turned off, or the `conversationId` doesn't belong to this bot |
| `429` | A token limit was reached, or the message is longer than the bot's **Maximum message length**. The body has a stable `code`; see [Usage limits](https://chatthing.ai/docs/developers/api-overview#usage-limits) |

## Continue a conversation

Send the `conversationId` you got back from an earlier request. The bot then sees the earlier messages in the conversation, so it can answer follow-up questions.

**curl**

```bash
curl --request POST \
  --url https://app.chatthing.ai/api/public/channels/{channelId}/2.0/message \
  --header 'Content-Type: application/json' \
  --header 'X-API-Secret-Key: {secretKey}' \
  --data '{
    "conversationId": "ea74ba3d-6645-4a88-92d1-7f78b1f83688",
    "message": "And on bank holidays?"
  }'
```

**JavaScript**

```javascript
await fetch(`https://app.chatthing.ai/api/public/channels/${channelId}/2.0/message`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secretKey,
  },
  body: JSON.stringify({
    conversationId: "ea74ba3d-6645-4a88-92d1-7f78b1f83688",
    message: "And on bank holidays?",
  }),
});
```

**Python**

```python
import requests

url = f"https://app.chatthing.ai/api/public/channels/{channel_id}/2.0/message"
headers = {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secret_key,
}
payload = {
    "conversationId": "ea74ba3d-6645-4a88-92d1-7f78b1f83688",
    "message": "And on bank holidays?",
}

response = requests.post(url, json=payload, headers=headers)
```

The response has the same shape as [Send a message](https://chatthing.ai/docs/developers/chat-api#send-a-message).

## Stream replies

Add `"stream": true` to a [Send a message](https://chatthing.ai/docs/developers/chat-api#send-a-message) request to receive the reply in pieces as it's written, instead of waiting for the whole answer. Your users see text sooner.

The stream format depends on the version in the URL. Use `2.0`: streaming on `1.0` is deprecated.

### Streaming on version 2.0

```text
POST /api/public/channels/{channelId}/2.0/message
```

```bash
curl --request POST \
  --url https://app.chatthing.ai/api/public/channels/{channelId}/2.0/message \
  --header 'Content-Type: application/json' \
  --header 'X-API-Secret-Key: {secretKey}' \
  --data '{
    "message": "What are your opening hours?",
    "stream": true
  }'
```

The response is a Server-Sent Events stream (`Content-Type: text/event-stream`). Each event is one `data: {json}` line holding one chunk, and the stream ends with `data: [DONE]`.

The conversation id is in the `x-conversation-id` response header, and also in a `data-conversation` chunk at the start of the stream. Use either to continue the conversation.

| Chunk `type` | What it means |
| --- | --- |
| `start` | The reply has started. Carries a `messageId` |
| `data-conversation` | `{ "conversationId": "..." }`, sent straight after `start` |
| `text-start`, `text-delta`, `text-end` | The reply text. Join the `delta` values of the `text-delta` chunks |
| `tool-input-start`, `tool-input-delta`, `tool-input-available` | The bot is using a power-up, and the input it's sending |
| `tool-output-available` | The power-up's result. `output` holds `{ "message": "...", "display": ... }`, where `display` is an optional rich display (cards, tables and so on) |
| `data-turn` | `{ "rowIds": [...], "lastRowId": "...", "sources": [...] }`, sent once the turn's messages are saved |
| `finish` | The reply finished successfully. Always comes after `data-turn` |
| `error`, `data-error` | The reply failed. `error` has a readable message; `data-error` has `{ "provider", "model", "statusCode", "statusMessage" }`. No `finish` follows |

You may also see `start-step` and `finish-step` chunks, which you can ignore.

Example stream:

```text
data: {"type":"start","messageId":"5f3c0c4e-8e1a-4f44-9a7b-2f1d3e4c5b6a"}

data: {"type":"data-conversation","data":{"conversationId":"ea74ba3d-6645-4a88-92d1-7f78b1f83688"}}

data: {"type":"start-step"}

data: {"type":"text-start","id":"txt-1"}

data: {"type":"text-delta","id":"txt-1","delta":"We're open 9am to 5pm,"}

data: {"type":"text-delta","id":"txt-1","delta":" Monday to Friday."}

data: {"type":"text-end","id":"txt-1"}

data: {"type":"finish-step"}

data: {"type":"data-turn","data":{"rowIds":["9df33cfc-1bc5-4990-8aa2-94552aa646c4"],"lastRowId":"9df33cfc-1bc5-4990-8aa2-94552aa646c4","sources":[]}}

data: {"type":"finish"}

data: [DONE]
```

Reading the stream in JavaScript:

```javascript
const response = await fetch(
  `https://app.chatthing.ai/api/public/channels/${channelId}/2.0/message`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Secret-Key": secretKey,
    },
    body: JSON.stringify({ message, stream: true }),
  },
);

const conversationId = response.headers.get("x-conversation-id");
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });

  // events are separated by a blank line
  const events = buffer.split("\n\n");
  buffer = events.pop() ?? "";

  for (const event of events) {
    const payload = event.replace(/^data: /, "").trim();
    if (!payload || payload === "[DONE]") continue;
    const chunk = JSON.parse(payload);
    if (chunk.type === "text-delta") {
      process.stdout.write(chunk.delta);
    }
  }
}
```

If you build with JavaScript, the [`ai` npm package](https://www.npmjs.com/package/ai) can read this stream for you (for example with `readUIMessageStream`), so you don't have to parse it by hand.

If a token limit has been reached, you get a normal (not streamed) `429` response with the [usage limit body](https://chatthing.ai/docs/developers/api-overview#usage-limits).

### Streaming on version 1.0 (deprecated)

> **Deprecated**
>
> Streaming on version `1.0` still works but is deprecated and will be removed in a future release. Move to [version 2.0 streaming](https://chatthing.ai/docs/developers/chat-api#streaming-on-version-20).

On `/api/public/channels/{channelId}/1.0/message` with `"stream": true`, the reply is newline-delimited JSON: one OpenAI-style `chat.completion.chunk` object per line. Join the `choices[0].delta.content` values to build the reply. The stream ends when the response closes. The conversation id isn't included in this format, so [start a conversation](https://chatthing.ai/docs/developers/chat-api#start-a-conversation) first if you need it.

```text
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"model-id","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"model-id","choices":[{"index":0,"delta":{"content":"We're open"},"finish_reason":null}]}
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"model-id","choices":[{"index":0,"delta":{"content":" 9am to 5pm."},"finish_reason":null}]}
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"model-id","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
```

Reading the 1.0 stream in JavaScript (the parser also tolerates a `data: ` prefix and a `[DONE]` line, so it works with earlier examples of this format):

```javascript
const response = await fetch(
  `https://app.chatthing.ai/api/public/channels/${channelId}/1.0/message`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Secret-Key": secretKey,
    },
    body: JSON.stringify({ message, stream: true }),
  },
);

const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });

  const lines = buffer.split("\n");
  buffer = lines.pop() ?? "";

  for (const line of lines) {
    const payload = line.replace(/^data: /, "").trim();
    if (!payload || payload === "[DONE]") continue;
    const content = JSON.parse(payload).choices[0]?.delta?.content;
    if (content) process.stdout.write(content);
  }
}
```

## Pass user data

User data tells the bot who it's talking to, so it can personalise answers, and passes those details on to your [webhooks](https://chatthing.ai/docs/developers/webhooks).

- **When you start a conversation** with [Start a conversation](https://chatthing.ai/docs/developers/chat-api#start-a-conversation), `userData` is saved on the conversation. The bot sees it on every reply, it appears with the conversation in Chat Thing, and it's included in the [Conversation started](https://chatthing.ai/docs/developers/webhooks#conversation-started-webhook) and [Conversation escalated](https://chatthing.ai/docs/developers/webhooks#conversation-escalated-webhook) webhooks. This is the recommended way.
- **On Send a message**, `userData` accepts `id`, `name`, `email` and `tel`. When that request creates a new conversation, the details are included in the Conversation started webhook, but they aren't saved on the conversation. To make the details available to the bot, send them when you start the conversation.

User data is whatever your code sends. Chat Thing doesn't check it, so don't rely on it to prove who someone is.

## Add context

`extendContext` gives the bot extra information for one request, such as details of the page or account the user is looking at. It isn't saved on the conversation.

| Field | Type | Description |
| --- | --- | --- |
| `custom` | object | Your own key-value pairs. Values must be strings, numbers or true/false |
| `pageMeta` | object | Details of a web page: `url` (required), and optionally `title`, `description`, `og:title` and `og:description` |
| `markdown` | string | Any extra text, such as the content of the page |

```json
{
  "message": "Is this in stock?",
  "extendContext": {
    "pageMeta": { "url": "https://example.com/products/blue-mug", "title": "Blue mug" },
    "custom": { "sku": "MUG-BLUE", "stock": 12 }
  }
}
```

`extendSystemMessage` and `overrideSystemMessage` also apply to one request only. Anyone with your secret key can use them to change the bot's instructions, which is another reason to keep the key on your server.

## List conversations

Returns the bot's conversations, oldest first, a page at a time.

```text
POST /api/public/channels/{channelId}/2.0/conversations
```

### Request body

| Field | Type | Description |
| --- | --- | --- |
| `limit` | integer | Optional. Conversations per page, from 1 to 100. Default `10` |
| `cursor` | string | Optional. To get the next page, send the `pagination.last` value from the previous response. Leave it out for the first page |

**curl**

```bash
curl --request POST \
  --url https://app.chatthing.ai/api/public/channels/{channelId}/2.0/conversations \
  --header 'Content-Type: application/json' \
  --header 'X-API-Secret-Key: {secretKey}' \
  --data '{ "limit": 2 }'
```

**JavaScript**

```javascript
const response = await fetch(
  `https://app.chatthing.ai/api/public/channels/${channelId}/2.0/conversations`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Secret-Key": secretKey,
    },
    body: JSON.stringify({ limit: 2 }),
  },
);
```

**Python**

```python
import requests

url = f"https://app.chatthing.ai/api/public/channels/{channel_id}/2.0/conversations"
headers = {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secret_key,
}

response = requests.post(url, json={"limit": 2}, headers=headers)
```

### Response

| Field | Type | Description |
| --- | --- | --- |
| `success` | boolean | `true` on success |
| `conversations` | array | Each has `id`, `createdAt` (ISO 8601) and `initialMessage` (the first message after the bot's welcome message, or `null`) |
| `pagination.total` | integer | Total number of conversations for this bot |
| `pagination.last` | string or null | The `id` of the last conversation on this page. Send it as `cursor` to get the next page. `null` when the page is empty |

```json
{
  "success": true,
  "conversations": [
    {
      "id": "3eda9841-9813-49a4-a75c-3758ea31b43c",
      "createdAt": "2026-01-16T10:07:04.296Z",
      "initialMessage": "What are your opening hours?"
    },
    {
      "id": "9b03aeb0-d9fe-466d-9fc9-49607643ade7",
      "createdAt": "2026-01-16T10:07:24.458Z",
      "initialMessage": "Do you deliver to Ireland?"
    }
  ],
  "pagination": {
    "total": 15,
    "last": "9b03aeb0-d9fe-466d-9fc9-49607643ade7"
  }
}
```

### Page through results

Keep requesting with `cursor` set to the previous `pagination.last` until a page comes back with fewer items than your `limit`:

```javascript
let cursor;
do {
  const res = await fetch(`https://app.chatthing.ai/api/public/channels/${channelId}/2.0/conversations`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "X-API-Secret-Key": secretKey },
    body: JSON.stringify({ limit: 100, cursor }),
  });
  const { conversations, pagination } = await res.json();
  // ...use conversations
  cursor = conversations.length === 100 ? pagination.last : undefined;
} while (cursor);
```

## List a conversation's messages

Returns the messages in one conversation, oldest first, a page at a time.

```text
POST /api/public/channels/{channelId}/2.0/messages
```

### Request body

| Field | Type | Description |
| --- | --- | --- |
| `conversationId` | string | Required. The conversation to read |
| `limit` | integer | Optional. Messages per page, from 1 to 100. Default `10` |
| `cursor` | string | Optional. To get the next page, send the `pagination.last` value from the previous response. Leave it out for the first page |

**curl**

```bash
curl --request POST \
  --url https://app.chatthing.ai/api/public/channels/{channelId}/2.0/messages \
  --header 'Content-Type: application/json' \
  --header 'X-API-Secret-Key: {secretKey}' \
  --data '{
    "conversationId": "{conversationId}",
    "limit": 10
  }'
```

**JavaScript**

```javascript
const response = await fetch(
  `https://app.chatthing.ai/api/public/channels/${channelId}/2.0/messages`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Secret-Key": secretKey,
    },
    body: JSON.stringify({ conversationId, limit: 10 }),
  },
);
```

**Python**

```python
import requests

url = f"https://app.chatthing.ai/api/public/channels/{channel_id}/2.0/messages"
headers = {
    "Content-Type": "application/json",
    "X-API-Secret-Key": secret_key,
}
payload = {"conversationId": conversation_id, "limit": 10}

response = requests.post(url, json=payload, headers=headers)
```

### Response

| Field | Type | Description |
| --- | --- | --- |
| `success` | boolean | `true` on success |
| `messages` | array | Each has `id`, `message`, `role` and `createdAt` (ISO 8601) |
| `pagination.total` | integer | Total number of messages in the conversation |
| `pagination.last` | string or null | The `id` of the last message on this page. Send it as `cursor` to get the next page |

`role` is usually `user` or `assistant`. Power-up activity can appear as other roles, such as `tool`. Keep only `user` and `assistant` if you want the transcript your user saw.

```json
{
  "success": true,
  "messages": [
    {
      "id": "9df33cfc-1bc5-4990-8aa2-94552aa646c4",
      "message": "Hello, how can I help you?",
      "role": "assistant",
      "createdAt": "2026-01-16T10:07:20.127Z"
    },
    {
      "id": "4364a927-ca22-4bab-ac17-48903a514717",
      "message": "Do you deliver to Ireland?",
      "role": "user",
      "createdAt": "2026-01-16T10:07:24.324Z"
    },
    {
      "id": "b5ce7f56-9340-4072-8716-793f720f6fb1",
      "message": "Yes, we deliver to Ireland in 3 to 5 working days.",
      "role": "assistant",
      "createdAt": "2026-01-16T10:07:26.518Z"
    }
  ],
  "pagination": {
    "total": 3,
    "last": "b5ce7f56-9340-4072-8716-793f720f6fb1"
  }
}
```

If the conversation doesn't exist or belongs to another bot, you get `404`.

## Related

- [API overview](https://chatthing.ai/docs/developers/api-overview): Base URL, API keys, authentication headers, versions, error codes and usage limits for the Chat Thing REST API.
- [Webhooks](https://chatthing.ai/docs/developers/webhooks): Send Chat Thing events such as new conversations, escalations and syncs to your own systems, Slack or Discord, and trigger data source syncs from a URL.
