CloudQuery External Syncs API
The external-syncs API from CloudQuery — 9 operation(s) for external-syncs.
The external-syncs API from CloudQuery — 9 operation(s) for external-syncs.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/cloudquery:cloudquery-external-syncs-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
contact:
email: support@cloudquery.io
name: CloudQuery Support Team
url: https://cloudquery.io
description: 'Welcome to the CloudQuery Platform API documentation! This API can be used to interact with the CloudQuery platform. As a user, the API allows you to search the CloudQuery asset inventory, run SQL queries against the data warehouse, save and load searches, and much more. As an administrator, it allows you to manage your teams, syncs, and other objects.
### Authentication
The API is secured using bearer tokens. To get started, you can generate an API key for your Platform deployment from your platform dashboard. For a step-by-step guide, see: https://www.cloudquery.io/docs/cli/managing-cloudquery/deployments/generate-api-key.
The base URL for the API depends on where your CloudQuery Platform is hosted. If running locally, this is usually http://localhost:3000/api. In a production deployment it should be an HTTPS URL. For purposes of illustration, we will assume the platform instance is available at https://cloudquery.mycompany.com. In this case, the base API endpoint will be https://cloudquery.mycompany.com/api.
### Example Request
To test your connection to the API, we can use the `/plugins` endpoint. For example:
`curl -v -H "Authorization: Bearer $CLOUDQUERY_API_KEY" \ https://cloudquery.mycompany.com/api/plugins`'
license:
name: MIT
url: https://spdx.org/licenses/MIT
termsOfService: https://www.cloudquery.io/terms
title: CloudQuery Platform OpenAPI Spec External Syncs API
version: 1.0.0
security:
- bearerAuth: []
- cookieAuth: []
tags:
- name: external-syncs
paths:
/external-syncs:
post:
description: 'Open a new external sync. The server assigns and returns a sync ID that the client includes on subsequent presign requests. This endpoint is idempotent per `(tenant, invocation_id)`: calling it again with the same invocation_id returns the existing sync.'
operationId: PlatformCreateExternalSync
tags:
- external-syncs
requestBody:
content:
application/json:
schema:
type: object
required:
- invocation_id
- sources
properties:
invocation_id:
type: string
minLength: 1
maxLength: 200
description: Client-supplied identifier for this CLI invocation. Typically a UUID generated by the CloudQuery CLI. Used as an idempotency key.
example: 4c3ea5cd-7f3d-4dfd-8ea8-c0b29eadac69
sources:
type: array
minItems: 1
description: 'The source plugins this sync will upload, reported by the CloudQuery CLI. Required: a sync must declare its sources so the platform can reject (422) sources whose version the asset view can''t process before any data is uploaded.'
items:
type: object
required:
- name
- path
- version
properties:
name:
type: string
description: Configured source name (`_cq_source_name`); used only to identify the source in error messages.
example: aws
path:
type: string
description: Source plugin path the asset view keys support by.
example: cloudquery/aws
version:
type: string
description: Source plugin version (semver, `v`-prefixed).
example: v32.3.1
responses:
'201':
description: Response
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformExternalSync'
'400':
$ref: '#/components/responses/PlatformBadRequest'
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'422':
$ref: '#/components/responses/PlatformUnprocessableEntity'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform create external sync
x-summary-source: derived
/external-syncs/whoami:
get:
description: Return the identity of the caller. Used by the CloudQuery Platform destination plugin to validate an API key at startup.
operationId: PlatformWhoamiExternalSync
tags:
- external-syncs
responses:
'200':
description: Response
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformExternalSyncWhoami'
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform whoami external sync
x-summary-source: derived
/external-syncs/supported-source-versions:
get:
description: List the asset-view-pinned version for each supported source plugin — the newest version the platform can ingest (a source is supported from `.0.0` up to and including this version). The CloudQuery CLI uses this to warn before running a sync whose source version the platform can't process. Optionally filter to a single plugin path.
operationId: PlatformListSupportedSourceVersions
tags:
- external-syncs
parameters:
- name: path
in: query
required: false
description: Filter to a single source plugin path (e.g. `cloudquery/aws`). When set, the response contains only that path, or is empty if it isn't supported.
schema:
type: string
example: cloudquery/aws
responses:
'200':
description: Pinned version keyed by source plugin path.
content:
application/json:
schema:
type: object
additionalProperties:
type: string
example:
cloudquery/aws: v32.5.5
cloudquery/gcp: v14.2.1
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform list supported source versions
x-summary-source: derived
/external-syncs/recommended-source-config:
get:
description: 'Get a ready-to-write source spec the platform recommends for a source plugin: the plugin''s example config sanitized for platform syncs (placeholder auth-scope values removed, wired to the injected `platform` destination, tables set to the recommended list) at the platform''s pinned version. The CloudQuery CLI writes this as the scaffolded sync config instead of deriving one from the plugin docs. An empty `config` means the platform has no scaffold for the plugin, which the CLI reports as an error.'
operationId: PlatformGetRecommendedSourceConfig
tags:
- external-syncs
parameters:
- name: path
in: query
required: true
description: The source plugin path (e.g. `cloudquery/gcp`).
schema:
type: string
example: cloudquery/gcp
responses:
'200':
description: The recommended source spec for the plugin.
content:
application/json:
schema:
type: object
required:
- config
properties:
config:
type: string
description: Ready-to-write CloudQuery source spec YAML. Empty when the platform has no scaffold for the plugin.
version:
type: string
description: The pinned source plugin version baked into the config.
example: v23.0.1
tables:
type: array
description: The table names baked into the config.
items:
type: string
'400':
$ref: '#/components/responses/PlatformBadRequest'
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform get recommended source config
x-summary-source: derived
/platform-destination/token:
post:
description: 'Mint a short-lived (~7 days), signed platform-destination token (prefix `cqpd_`) for the caller''s tenant. The user pastes this token as their CloudQuery CLI credential: it authenticates plugin/usage calls to cloud (which verifies it offline) and `/external-syncs/*` on this platform — no host configuration. Any signed-in tenant user with write access can mint one for their own tenant, whatever their login method (local password, SAML, magic link); a tenant API key with write access works too, for CI (a default `ci`-role key cannot mint). It is a derived credential: the CLI re-mints it from the durable root (cloud login, a tenant API key, or a fresh tenant sign-in) as it nears expiry, so a leaked token expires within about a week. There is no per-token revocation — verification is offline on both stacks, against either of the tenant''s two external-sync secret slots. Rotating the secret demotes the outgoing one to the second slot as a grace window, so outstanding tokens keep working until a second rotation displaces it; two rotations revoke every outstanding token for the tenant. Disabling the user who minted a token does not invalidate it before it expires. Returned once.'
operationId: PlatformCreatePlatformDestinationToken
tags:
- external-syncs
responses:
'201':
description: Token minted
content:
application/json:
schema:
type: object
additionalProperties: false
required:
- token
- expires_at
properties:
token:
type: string
description: The signed `cqpd_` token. Shown once.
expires_at:
type: string
format: date-time
description: When the token expires.
plugin_version:
type: string
description: Recommended `cloudquery/platform` destination plugin version.
example: v1.0.0
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'422':
$ref: '#/components/responses/PlatformUnprocessableEntity'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform create platform destination token
x-summary-source: derived
/external-syncs/{external_sync_id}/files/presign:
post:
description: Mint a short-lived presigned PUT URL for a single Parquet file belonging to an external sync. The client uses the returned URL to upload directly to the platform-owned S3 bucket without ever seeing AWS credentials.
operationId: PlatformPresignExternalSyncFile
tags:
- external-syncs
parameters:
- name: external_sync_id
in: path
required: true
description: The external sync ID returned from `POST /external-syncs`.
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
required:
- source_name
- sync_group_id
- table
- content_type
properties:
sync_group_id:
type: integer
format: int64
minimum: 1
description: The `_cq_sync_group_id` value (time-based uint64) carried on rows from this sync. The platform encodes it in the object key so assetview's `(tenant, source, sync_group_id)` finalize key matches the row data — without it the staging-to-main promote wipes rows whose sgid disagrees with the path.
example: 20260415120000124
source_name:
type: string
minLength: 1
maxLength: 200
pattern: ^\.*[A-Za-z0-9_-][A-Za-z0-9_.-]*$
x-pattern-message: source_name may contain only letters, digits, '_', '.', or '-' (and not be all dots)
description: CloudQuery source plugin name the file's rows originate from (the value of `_cq_source_name`). Encoded into the object key so platform ingestion can key staging-table finalization by source. Restricted to an encoding-invariant charset so the S3 key the ingest pipeline parses matches what was written (S3 event notifications URL-encode keys).
example: aws
table:
type: string
minLength: 1
maxLength: 200
pattern: ^\.*[A-Za-z0-9_-][A-Za-z0-9_.-]*$
x-pattern-message: table may contain only letters, digits, '_', '.', or '-' (and not be all dots)
description: CloudQuery table name this file is for. Used in the object key. Restricted to an encoding-invariant charset (see source_name).
example: aws_ec2_instances
content_type:
type: string
description: The exact Content-Type the client will send with the PUT.
example: application/vnd.apache.parquet
responses:
'200':
description: Response
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformExternalSyncPresignedFile'
'400':
$ref: '#/components/responses/PlatformBadRequest'
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'404':
$ref: '#/components/responses/PlatformNotFound'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform presign external sync file
x-summary-source: derived
/external-syncs/{external_sync_id}/progress:
post:
description: Report progress for an external sync. The platform destination plugin calls this periodically with running row counts while writing, and once with a terminal status (`completed`/`failed`) when the sync ends. Used to surface live progress and a final state for syncs the platform does not orchestrate. Counts are cumulative totals; omitted fields leave the last-reported value unchanged, and a terminal status is final (a later `started` won't reopen the sync).
operationId: PlatformReportExternalSyncProgress
tags:
- external-syncs
parameters:
- name: external_sync_id
in: path
required: true
description: The external sync ID returned from `POST /external-syncs`.
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
required:
- status
properties:
status:
type: string
enum:
- started
- completed
- failed
description: Current lifecycle state of the sync.
example: started
rows:
type: integer
format: int64
minimum: 0
description: Total rows written so far across all tables.
example: 12345
table_progress:
type: object
description: Per-table row counts, keyed by table name.
additionalProperties:
type: object
properties:
rows:
type: integer
format: int64
minimum: 0
responses:
'204':
description: Progress recorded.
'400':
$ref: '#/components/responses/PlatformBadRequest'
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'404':
$ref: '#/components/responses/PlatformNotFound'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform report external sync progress
x-summary-source: derived
/external-sync-runs:
get:
description: List the team's external syncs (CLI runs uploaded to the platform), newest first. Read-only view for the frontend; the tenant is resolved from the host.
operationId: PlatformListExternalSyncRuns
tags:
- external-syncs
parameters:
- $ref: '#/components/parameters/platform_per_page'
- $ref: '#/components/parameters/platform_page'
- name: status
in: query
required: false
description: Filter by lifecycle status.
schema:
type: string
enum:
- started
- finalizing
- completed
- failed
responses:
'200':
description: Response
content:
application/json:
schema:
type: object
required:
- items
- metadata
properties:
items:
type: array
items:
$ref: '#/components/schemas/PlatformExternalSync'
metadata:
$ref: '#/components/schemas/PlatformListMetadata'
'400':
$ref: '#/components/responses/PlatformBadRequest'
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform list external sync runs
x-summary-source: derived
/external-sync-runs/{external_sync_id}:
get:
description: Get a single external sync, including its live progress and lifecycle status. The tenant is resolved from the host.
operationId: PlatformGetExternalSyncRun
tags:
- external-syncs
parameters:
- name: external_sync_id
in: path
required: true
description: The external sync ID returned from `POST /external-syncs`.
schema:
type: string
format: uuid
responses:
'200':
description: Response
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformExternalSync'
'401':
$ref: '#/components/responses/PlatformRequiresAuthentication'
'404':
$ref: '#/components/responses/PlatformNotFound'
'500':
$ref: '#/components/responses/PlatformInternalError'
summary: Platform get external sync run
x-summary-source: derived
components:
schemas:
PlatformExternalSyncPresignedFile:
description: A single presigned S3 PUT URL to upload one Parquet file to.
type: object
required:
- url
- key
- required_headers
- expires_at
properties:
url:
type: string
format: uri
description: The presigned URL. Issue an HTTP PUT to this URL with the file body.
key:
type: string
description: The S3 object key the presigned URL writes to. Recorded so the platform can locate the uploaded file without listing the bucket.
example: syncs/tenant/11111111-1111-1111-1111-111111111111/external/22222222-2222-2222-2222-222222222222/aws_ec2_instances___3a.parquet
required_headers:
description: Headers that MUST be sent with the PUT request exactly as given. These are bound into the signature; replaying them verbatim is required.
type: object
additionalProperties:
type: string
example:
Content-Type: application/vnd.apache.parquet
expires_at:
type: string
format: date-time
description: The absolute instant after which the URL stops being valid.
example: '2026-04-15T14:43:20Z'
PlatformExternalSync:
description: 'A sync that a user is running with their own local CloudQuery CLI and uploading to the CloudQuery Platform through the presigned-URL proxy. Unlike managed syncs, the platform does not schedule these: the CLI owns the lifecycle and only the uploaded files land on the platform.'
type: object
required:
- id
- invocation_id
- created_at
properties:
id:
type: string
format: uuid
description: Server-assigned ID of the external sync. Include this in subsequent presign requests.
invocation_id:
type: string
description: Client-supplied identifier used to make sync creation idempotent.
example: 4c3ea5cd-7f3d-4dfd-8ea8-c0b29eadac69
created_at:
type: string
format: date-time
example: '2026-04-15T14:28:20Z'
status:
type: string
enum:
- started
- finalizing
- completed
- failed
description: Lifecycle state. The destination plugin reports `started`/`failed`; when it reports done the platform records `finalizing` until the uploaded data is ingested, then flips to `completed`.
rows:
type: integer
format: int64
description: Total rows written across all tables.
table_progress:
type: object
description: Per-table row counts, keyed by table name.
additionalProperties:
type: integer
format: int64
updated_at:
type: string
format: date-time
description: Last time progress was reported.
finished_at:
type: string
format: date-time
description: When the sync reached a terminal status, if it has.
PlatformListMetadata:
required:
- page_size
properties:
total_count:
type: integer
last_page:
type: integer
page_size:
type: integer
time_ms:
type: integer
next_cursor:
type: string
description: 'Opaque cursor for the next page when using keyset pagination. Present only
for keyset-eligible list queries (default order, no group_by); omitted on
the last page. Pass it back as the `cursor` query parameter.
'
PlatformExternalSyncWhoami:
description: Identity of the CloudQuery Platform tenant the request is authenticated as.
type: object
required:
- tenant_id
properties:
tenant_id:
type: string
format: uuid
description: The UUID of the tenant this API key belongs to.
warning:
type: string
description: Advisory message the client should surface to the user verbatim (e.g. the presented token is about to expire). Omitted when there is nothing to warn about.
plugin_version:
type: string
description: Recommended cloudquery/platform destination plugin version. The CLI pins the injected destination to it — notably in the headless flow, which only calls whoami and never mints.
example: v1.0.0
PlatformFieldError:
allOf:
- $ref: '#/components/schemas/PlatformBasicError'
- properties:
errors:
items:
type: string
type: array
field_errors:
additionalProperties:
type: string
type: object
type: object
PlatformBasicError:
additionalProperties: false
description: Basic Error
required:
- message
- status
properties:
message:
type: string
status:
type: integer
title: Basic Error
type: object
responses:
PlatformInternalError:
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformBasicError'
description: Internal Error
PlatformRequiresAuthentication:
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformBasicError'
description: Requires authentication
PlatformBadRequest:
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformFieldError'
description: Bad request
PlatformNotFound:
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformBasicError'
description: Resource not found
PlatformUnprocessableEntity:
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformFieldError'
description: UnprocessableEntity
parameters:
platform_page:
description: Page number of the results to fetch
in: query
name: page
required: false
schema:
default: 1
minimum: 1
type: integer
format: int64
platform_per_page:
description: The number of results per page (max 1000).
in: query
name: per_page
required: false
schema:
default: 100
maximum: 1000
minimum: 1
type: integer
format: int64
securitySchemes:
bearerAuth:
scheme: bearer
type: http
basicAuth:
scheme: basic
type: http
cookieAuth:
scheme: cookie
type: http
x-provenance:
method: harvested
publisher: CloudQuery
source: https://platform-multi-tenant-api-docs.cloudquery.io/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)