Skip to content

OpenAPI Cross-Site Data Query

This document explains how to use query_data to query data from other sites that the current Workspace has been authorized to access, and how to correctly handle the async_id returned by asynchronous endpoints.

Applicable Endpoints

Scenario Endpoint Description
Synchronous query (recommended) POST /api/v1/df/query_data_v1 Preferred for new integrations
Asynchronous query POST /api/v1/df/asynchronous/query_data Returns async_id only when the task is still running
Legacy compatibility GET/POST /api/v1/df/query_data GET uses body=<URL-encoded JSON>; not recommended for new integrations
Query authorized targets GET /api/v1/wksp_share/granted_ws_list Obtain the target workspaceUUID and targetRegion
Query site configuration GET /api/v1/workspace/website/list Only for viewing site registration information; does not imply data authorization

External API's POST /api/v1/df/{workspace_uuid}/query_data is a synchronous entry point and does not accept async_id. It uses the same set of DQL query fields underneath, but authentication is performed using the External API AK/SK signature.

Request Model and Limits

Cross-site queries still call the OpenAPI Endpoint of the current site and use the current Workspace's DF-API-KEY. There is no need to directly request the target site, and you should not replace the current Endpoint with the target site's Endpoint.

The structure of each queries[i] is:

{
  "qtype": "dql",
  "query": {
    "q": "L::re(`.*`):(`message`)",
    "workspaceUUIDs": ["wksp_target"],
    "targetRegion": "region_code"
  }
}

The following rules must be followed:

  1. Non-empty workspaceUUIDs takes precedence over workspaceUUID; when workspaceUUIDs is an empty array or null, it falls back to workspaceUUID. It is recommended not to pass both fields. When neither is passed, the current Workspace is queried.
  2. For cross-site queries, explicitly pass the same targetRegion inside the query object of each query, not only at the top level of the request.
  3. All queries[*] in one request can only point to one site. Multiple sites must be split into multiple requests, and the results are merged by the client.
  4. workspaceUUIDs: ["*"] or workspaceUUID: "*" means querying all authorized workspaces visible to the current Workspace within the specified targetRegion; in this case, targetRegion is required.
  5. targetRegion is the regionCode of the site to which the authorizing Workspace belongs, not toRegionCode.
  6. Multiple target workspaces in the same request must belong to the same targetRegion. It is recommended to group target workspaces by site before constructing requests.

Time Range and Pagination Cursor

The start and end times of query.timeRange must use the same unit (seconds, milliseconds, microseconds, or nanoseconds). Mixing units returns HTTP 400, ft.TimeRangeUnitMismatch; the server does not automatically correct it. The request examples in this document use milliseconds; replace them with your actual query time range.

Pagination parameters such as cursor_time and cursor_token are independent of the query time range: when paging, pass the response cursor back as-is according to the API convention, keep the original query's timeRange unchanged, and do not convert the cursor to unify digit lengths.

Obtain Target Workspace and targetRegion

Call:

curl '<Endpoint>/api/v1/wksp_share/granted_ws_list?namespace=logging&pageIndex=1&pageSize=100' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--compressed

namespace filters authorizations by data type, for example:

  • Logs: logging
  • Tracing: tracing
  • Metrics: metric
  • Real User Monitoring (RUM): rum
  • Synthetic Monitoring: dialtest

The response is grouped by authorizing site:

{
  "code": 200,
  "content": [
    {
      "regionCode": "region_a",
      "regionName": "Site A",
      "data": [
        {
          "workspaceUUID": "wksp_target_a",
          "workspaceName": "Target workspace A",
          "regionCode": "region_a",
          "toWorkspaceUUID": "wksp_current",
          "toRegionCode": "region_current",
          "type": ["logging"],
          "indexes": ["*"]
        }
      ],
      "pageInfo": {
        "pageIndex": 1,
        "pageSize": 100,
        "totalCount": 1
      }
    }
  ],
  "success": true
}

When organizing parameters:

  • Use data[*].workspaceUUID as the value of query.workspaceUUID or query.workspaceUUIDs.
  • Use the content[*].regionCode of the group containing that workspace (or the regionCode of the same data item) as query.targetRegion.
  • Do not use toWorkspaceUUID as the query target; it is usually the grantee Workspace to which the current API Key belongs.
  • Do not use toRegionCode as targetRegion; it is usually the current site.
  • granted_ws_list paginates independently per site group. pageInfo.count is only the number of items on the current page; do not use it to compare with totalCount and increment the page indefinitely.
  • On the first call, you may omit regionCode and use pageIndex=1&pageSize=100 to discover authorizing sites; afterward, explicitly pass the regionCode for each site you need to query, and start paging from page 1 for each site.
  • Stop when the cumulative number of unique authorizations obtained for a site reaches that group's pageInfo.totalCount, or when pageIndex * pageSize >= totalCount. When merging page data, deduplicate by the authorization record uuid, and validate the target mapping with (regionCode, workspaceUUID); if conflicting authorizations appear for the same mapping, do not expand the permission scope on your own.

For example, to fetch only page 2 of region_a:

curl '<Endpoint>/api/v1/wksp_share/granted_ws_list?namespace=logging&regionCode=region_a&pageIndex=2&pageSize=100' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--compressed

The content[*].regionCode returned by GET /api/v1/workspace/website/list can only be used as a site code candidate. A site appearing in the site list does not mean the current Workspace has data authorization for that site; the final result must be based on granted_ws_list.

Synchronous Cross-Site Query

The following example queries wksp_target_a in the region_a site:

curl '<Endpoint>/api/v1/df/query_data_v1' \
-H 'Content-Type: application/json' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--data-raw '{
  "queries": [
    {
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["wksp_target_a"],
        "targetRegion": "region_a"
      }
    }
  ]
}' \
--compressed

Query all authorized workspaces within a site:

{
  "queries": [
    {
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["*"],
        "targetRegion": "region_a"
      }
    }
  ]
}

If you need to query both region_a and region_b, send two separate requests:

Target list
  ├─ region_a: [wksp_a1, wksp_a2] -> Request 1
  └─ region_b: [wksp_b1]          -> Request 2
                                 Client merges results

Do not mix different targetRegion values in the same queries array; otherwise the API will return ft.UnsupportMultiSiteQuery.

Asynchronous Query and async_id Lifecycle

async_id is a handle for a single query task, not a session ID, a fixed client ID, or a pagination cursor. A new query must never carry a historical async_id.

1. First Submission: Omit async_id

curl '<Endpoint>/api/v1/df/asynchronous/query_data' \
-H 'Content-Type: application/json' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--data-raw '{
  "queries": [
    {
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["wksp_target_a"],
        "targetRegion": "region_a"
      }
    }
  ]
}' \
--compressed

If the task is still running, example response:

{
  "code": 200,
  "content": {
    "data": [
      {
        "async_id": "async_task_001",
        "is_running": true
      }
    ]
  },
  "success": true,
  "traceId": "TRACE-XXXX"
}

2. Polling: Only Pass Back Running Task IDs

Poll only when the same result item satisfies both of the following conditions:

content.data[i].is_running === true
and
content.data[i].async_id is non-empty

Place the ID back into queries[i].async_id at the same array index, and keep qtype, query.q, the time range, target workspace, and targetRegion unchanged:

{
  "queries": [
    {
      "async_id": "async_task_001",
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["wksp_target_a"],
        "targetRegion": "region_a"
      }
    }
  ]
}

Use incremental backoff and set an overall timeout, for example, wait 1 second first, then gradually increase to 2 seconds, 4 seconds; do not send continuous requests without intervals.

3. Completion: Stop Carrying async_id

When content.data[i].is_running is false, the task has ended. The caller should read the final data and stop polling immediately. Whether or not the async_id field still appears in the response object, the next new query must omit the old ID.

The following behaviors are incorrect:

  • Hard-coding the previous task's async_id into all subsequent requests.
  • Reusing the old ID after modifying DQL, time range, workspace, or targetRegion.
  • Placing content.data[0].async_id into queries[1].
  • Using async_id instead of search_after, cursor_time, or cursor_token for pagination.

If is_running=true but async_id is empty, do not backfill with a locally saved historical ID. Record the response traceId and reissue the same logical query with a finite retry strategy; if it persists, contact technical support.

In batch asynchronous queries, content.data[i] corresponds to queries[i] by array index. To reduce the risk of mismatching IDs with query items, it is recommended to submit only one query per asynchronous call.

Difference Between Pagination and Asynchronous Tasks

After an asynchronous task completes, pagination still uses the pagination fields returned by the final query result:

Scenario Next Request Parameter
Log deep pagination Pass the response search_after into the next query's query.search_after
Segmented time query First set query.cursor_time to the end time, then pass the response next_cursor_time
Safe pagination for identical timestamps Pass the response next_cursor_token into the next query's query.cursor_token

Pagination is a new query request and should not continue carrying the async_id of a completed task. If a pagination request becomes an asynchronous task again, start a new lifecycle from "omit async_id".

Client-Side Merging Recommendations

The server does not support querying across multiple sites in one query_data request. When merging on the client side, it is recommended to:

  1. First group target workspaces by targetRegion.
  2. Each site uses independent requests, independent pagination, and independent asynchronous task handling.
  3. Add client-side metadata to each batch of results, such as sourceRegion and queriedWorkspaceUUIDs. Multi-workspace queries do not guarantee that every record carries a reliable source workspace, so you cannot label the entire batch as a single sourceWorkspaceUUID; only when each query targets a single workspace can you do so. When record-level source is required, query each workspace individually, or have DQL return a source dimension that the business has confirmed is reliable.
  4. Sort and deduplicate log-type results by time, date_ns, and a stable unique identifier; for metric results, first confirm that the time granularity, aggregation function, and tag set are consistent before merging.
  5. When any site fails, keep the successful results from other sites and return per-site error details; do not wrap partial success as full success.

Common Errors

Error Code / Symptom Cause Resolution
ft.TimeRangeUnitMismatch The start and end times in timeRange use different units Reconstruct the time range with the same unit; still pass pagination cursors back as-is from the response
ft.UnsupportMultiSiteQuery A single request mixes multiple target sites Split requests by targetRegion
ft.workspaceUnauthorized The target Workspace is not authorized to the current Workspace Re-query granted_ws_list and confirm the authorization status and UUID
ft.NotFoundWorkspaceAuthorizationCfg The target site has no available authorization configuration, commonly when using * but the site has no authorization Check targetRegion and confirm that a valid authorization exists on the target site
ft.NoInitOtherNodeCfg Cross-organization site authorization exists, but the target site's Front Endpoint / node configuration is missing Do not blindly retry; contact the site administrator to check and complete the target node configuration
ft.InvalidWorkspace The target Workspace on the current site is invalid or disabled Refresh the workspace list and confirm its status
Keeps polling old results The client keeps reusing the async_id of a completed task Delete the local ID after is_running=false; do not pass async_id in new queries
Site exists but no data is found Only workspace/website/list was checked; authorization was not confirmed Use wksp_share/granted_ws_list as the source of truth
DQLDataAccessScopeRestricted warning Data access rules allow only some indexes or do not allow the relevant indexes Check warnings[].details[].metadata.restriction and data access rules

Pre-Launch Checklist

  • Request the current site's OpenAPI Endpoint using the current Workspace's DF-API-KEY.
  • Obtain the target workspaceUUID and its group's regionCode from granted_ws_list.
  • Every cross-site query explicitly passes the same targetRegion.
  • Multi-site targets have been split into multiple requests by targetRegion.
  • New asynchronous queries do not pass async_id.
  • Poll only when is_running=true and the ID is non-empty, and bind tasks by array index.
  • Delete the task ID after is_running=false; pagination starts from a new asynchronous lifecycle.
  • Set polling backoff, overall timeout, pagination limit, and per-site error handling.
  • When merging results, preserve the source site/workspace and deduplicate by the business primary key.

Feedback

Is this page helpful?