Real-time monitoring is currently only available for Enterprise customers. To upgrade, get in touch with our sales team.

Our API enables you to track and manage all your monitored workflows. You can:

  • Get all active workflows with monitoring enabled
  • Retrieve historical data changes across your workflows

Prerequisites

To get the most out of this guide, you’ll need to:

1. Get All Active Monitoring Workflows

Use the following endpoint to retrieve your workflows:

GET /v4/workflows

See full API reference

The response will include all workflows that are in your scope (user, team, organization).

To get all workflows that are active and have real-time monitoring enabled, you can use the following query parameter:

curl -X GET "https://api.kadoa.com/v4/workflows?limit=100&state=ACTIVE&monitoring=true&updateInterval=REAL_TIME" \
  -H "x-api-key: YOUR_API_KEY"

2. Get Historical Data Changes

The /changes endpoint returns all historical data changes detected by your monitoring workflows. By default, it returns changes from all your active workflows.

curl -X GET "https://api.kadoa.com/v4/changes" \
  -H "x-api-key: YOUR_API_KEY"

You can filter changes by workflow and date range using the different query parameters. See full API reference.

Example with filters:

curl -X GET "https://api.kadoa.com/v4/changes?startDate=2024-11-01T00:00:00Z&endDate=2024-11-30T23:59:59Z" \
  -H "x-api-key: YOUR_API_KEY"

Differences Field Explanation

Each change includes a differences array showing structured representations of what changed:

{
  "differences": [
    {
      "type": "changed",
      "fields": [
        {
          "key": "title",
          "previousValue": "Old Title",
          "value": "New Title"
        }
      ]
    }
  ]
}

The differences field provides an object-based diffing with the following structure:

  • type: The type of change - can be added, removed, or changed
  • fields: All fields of the object (even if unchanged)

Each field change includes:

  • key: Field name that was changed
  • value: Current field value
  • previousValue: Previous field value (only present for changed type)

Example

Let’s look at a simplified example with three fields: id, name, and status.

Data before change:

{
  "products": [
    { "id": "001", "name": "Product A", "status": "In Stock" },
    { "id": "002", "name": "Product B", "status": "Low Stock" },
    { "id": "003", "name": "Product C", "status": "Out of Stock" },
    { "id": "004", "name": "Product D", "status": "In Stock" }
  ]
}

Data after change:

{
  "products": [
    { "id": "001", "name": "Product A Premium", "status": "In Stock" },
    { "id": "003", "name": "Product C", "status": "In Stock" },
    { "id": "004", "name": "Product D", "status": "In Stock" },
    { "id": "005", "name": "Product E", "status": "New Arrival" }
  ]
}

The differences field would show:

{
  "differences": [
    {
      "type": "changed",
      "fields": [
        {
          "key": "id",
          "previousValue": "001",
          "value": "001"
        },
        {
          "key": "name",
          "previousValue": "Product A",
          "value": "Product A Premium"
        },
        {
          "key": "status",
          "previousValue": "In Stock",
          "value": "In Stock"
        }
      ]
    },
    {
      "type": "removed",
      "fields": [
        {
          "key": "id",
          "value": "002"
        },
        {
          "key": "name",
          "value": "Product B"
        },
        {
          "key": "status",
          "value": "Low Stock"
        }
      ]
    },
    {
      "type": "changed",
      "fields": [
        {
          "key": "id",
          "previousValue": "003",
          "value": "003"
        },
        {
          "key": "name",
          "previousValue": "Product C",
          "value": "Product C"
        },
        {
          "key": "status",
          "previousValue": "Out of Stock",
          "value": "In Stock"
        }
      ]
    },
    {
      "type": "added",
      "fields": [
        {
          "key": "id",
          "value": "005"
        },
        {
          "key": "name",
          "value": "Product E"
        },
        {
          "key": "status",
          "value": "New Arrival"
        }
      ]
    }
  ]
}

Note that item with id: "004" remains unchanged, so it doesn’t appear in the differences array.

For real-time updates, consider using our WebSocket SDK instead of polling this endpoint.

WebSocket API

With our WebSocket API, you can listen to real-time changes from your monitoring workflows.

Prerequisites

We strongly recommend using our SDK for real-time updates. The SDK handles the connection, authentication, message acknowledgement, message replay and auto-reconnect. If you need to implement a native WebSocket integration, please contact us.

Message Format

All messages are JSON objects with the following fields:

Always present:

  • type: The type of the message.
  • timestamp: The timestamp of the message.

Optional depending on the type:

  • data: The data of the message.
  • id: The ID of the message used for acknowledgement.

Message Types

workflow_data_change

This message is sent when a workflow data changes.

Fields:

id
string

The change ID of the workflow. You can also retrieve the change with screenshot over the /changes endpoint or view the change in the Kadoa dashboard like: https://www.kadoa.com/data-diff/ID

workflowId
string

The ID of the workflow. Accessible over the /workflows endpoint or the Kadoa dashboard like: https://www.kadoa.com/workflow/WORKFLOW_ID

data
object

The data of the workflow. Full snapshot of the data at the time of the change.

differences
array

Structured representation of changes with object-based diffing. For an explanation of the differences format, please refer to the monitoring API documentation.

url
string

The URL of the page the workflow is monitoring.

createdAt
string

The timestamp in ISO format when the change was detected.

Example:

{
  "type": "workflow_data_change",
  "timestamp": 1736367604663,
  "id": "2df91fbd-74c1-4d11-91aa-50030393574b",
  "data": {
    "id": "66d0c9e65baad1694a2132d0",
    "workflowId": "677fc12545e790b20a4eec34",
    "data": [{ "title": "Test News" }, { "title": "New News" }],
    "differences": [
      {
        "type": "added",
        "fields": [
          {
            "key": "title",
            "value": "New News"
          }
        ]
      }
    ],
    "url": "https://thisismymonitoredpage.com",
    "createdAt": "2025-01-09T10:00:00Z"
  }
}

heartbeat

Reconnection logic is handled by the SDK. If you implement a native WebSocket integration, you might need to handle reconnections yourself.

This message is sent every 15 seconds. It’s used to keep the connection alive. If you don’t receive a heartbeat after 30 seconds, the connection is considered lost, reconnection is needed.

Example:

{
  "type": "heartbeat",
  "timestamp": 1736367604663
}