Skip to content

Computed Join API

The Computed Join API is exposed through the /containers endpoints. All paths in this page are relative to https://<your-instance>.qualytics.io/api. Authentication uses a Bearer token in the Authorization header.

Complete API Reference

For the full interactive API schema with all request and response fields, see demo.qualytics.io/api/docs. Replace <YOUR_API_TOKEN> in the examples below with a personal access token from your user profile.

Permissions

To create, edit, or delete a Computed Join you need:

  • Editor on the left datastore, or Author on the left datastore plus ownership of the Computed Join.
  • At least Viewer on the right datastore.

Reading requires at least Reporter on the left datastore (where the Computed Join lives). Permission on the right datastore is checked only when creating or editing a cross-datastore join.

Schema

The Computed Join container has the following fields:

Field Type Required on create Description
name string Yes Unique name on the parent datastore (max 255 chars)
container_type string Yes Always "computed_join"
left_container_id integer Yes ID of the left input container
right_container_id integer Yes ID of the right input container
left_join_field_name string Yes Field name to join on (left side, max 255 chars)
right_join_field_name string Yes Field name to join on (right side, max 255 chars)
left_prefix string No (default "left") Prefix applied to columns from the left side (max 100 chars)
right_prefix string No (default "right") Prefix applied to columns from the right side (max 100 chars)
join_type string No (default "inner") One of "inner", "left", "right", "outer". The API also accepts "left_semi" and "left_anti", but the UI does not expose them.
select_clause string Yes SQL Select Expression
where_clause string No SQL Filter Clause
group_by_clause string No SQL Group By Clause
description string No Free-text description (max 255 chars)
owner_id integer No ID of the owning user. Defaults to the user who creates the join. Authors can omit owner_id or set it to their own user ID only. Editors can set it to any user on Create, and only Editors can transfer ownership on Update.
additional_metadata object No Free-form key-value metadata stored alongside the container.
force_drop_fields boolean No PUT only. Set to true to bypass the field-drop conflict when an edit removes fields with active quality checks or anomalies. Ignored on POST (the field-drop conflict cannot arise during create). See Update a Computed Join.

Note

Unlike the UI, the API does not auto-generate the Select Expression. You must provide select_clause explicitly on every create.

Create a Computed Join

Endpoint: POST /api/containers

Permission: Editor on the left datastore, or Author with owner_id set to your own ID (or omitted).

Expected response: 200 OK with the created container.

cURL
curl -X POST https://your-instance.qualytics.io/api/containers \
  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "container_type": "computed_join",
    "name": "customer_orders_join",
    "left_container_id": 101,
    "right_container_id": 202,
    "left_join_field_name": "customer_id",
    "right_join_field_name": "customer_id",
    "left_prefix": "cust",
    "right_prefix": "order",
    "join_type": "left",
    "select_clause": "cust_customer_id, cust_name, cust_city, order_order_id, order_product"
  }'

Validate a Computed Join

Endpoint: POST /api/containers/validate

Permission: Same as Create.

Use this endpoint to test the join configuration without persisting it. On success the endpoint returns no body; validation errors are returned as standard error responses.

Expected response: 204 No Content (nothing is persisted).

Query parameters:

Name Type Default Description
timeout_seconds integer 150 Maximum seconds to wait for the synchronous validation step. Minimum 30, maximum 300.

The Validate endpoint expects the container payload wrapped in {"container": {...}, "container_id": <existing-id-or-null>}. Pass container_id when validating an edit to an existing Computed Join; omit it (or send null) when validating a new one.

cURL
curl -X POST https://your-instance.qualytics.io/api/containers/validate \
  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "container": {
      "container_type": "computed_join",
      "name": "customer_orders_join",
      "left_container_id": 101,
      "right_container_id": 202,
      "left_join_field_name": "customer_id",
      "right_join_field_name": "customer_id",
      "left_prefix": "cust",
      "right_prefix": "order",
      "join_type": "left",
      "select_clause": "cust_customer_id, cust_name, cust_city, order_order_id, order_product"
    },
    "container_id": null
  }'

Update a Computed Join

Endpoint: PUT /api/containers/{id}

Permission: Editor on the left datastore, or Author who is the current owner. Editors do not need to own the join to update it. Only an Editor can reassign owner_id to another user; an Author cannot transfer ownership.

Updates the editable fields of the Computed Join. PUT requires container_type and name on every call (even when neither is changing); other fields are optional and unchanged when omitted. The left and right container_id are immutable after creation; to change them, delete and recreate the join. Sending left_container_id or right_container_id in an update body is silently ignored. Sending an empty or whitespace-only description clears any existing description.

Note

PUT also accepts an incremental_identifier object to configure incremental scans on the joined output. The object has identifier_type (one of "last-modified", "batch-value", "postgresql") and an optional field_name.

cURL
curl -X PUT https://your-instance.qualytics.io/api/containers/123 \
  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "container_type": "computed_join",
    "name": "customer_orders_join",
    "select_clause": "cust_customer_id, cust_name, order_product",
    "where_clause": "order_product IS NOT NULL"
  }'

If the new Select Expression drops fields that have active quality checks or anomalies, the request returns 409 Conflict with a list of affected fields. Re-submit with "force_drop_fields": true in the request body to apply the change; the dropped fields are marked missing and their checks and anomalies are preserved until the fields reappear (see How It Works).

cURL with force_drop_fields
curl -X PUT https://your-instance.qualytics.io/api/containers/123 \
  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "container_type": "computed_join",
    "name": "customer_orders_join",
    "select_clause": "cust_customer_id, cust_name",
    "force_drop_fields": true
  }'

Get a Computed Join

Endpoint: GET /api/containers/{id}

Permission: Reporter (or higher) on the datastore.

cURL
curl -X GET https://your-instance.qualytics.io/api/containers/123 \
  -H "Authorization: Bearer <YOUR_API_TOKEN>"

List Computed Joins

Endpoint: GET /api/containers

Permission: Returns containers on datastores where you have at least Reporter.

Returns containers visible to the caller. Filter by container_type=computed_join to list only Computed Joins, optionally scoped to one or more datastores with datastore.

Query parameters:

Name Type Description
container_type string Filter by container type. Use computed_join to list only Computed Joins. Repeat the parameter to filter by multiple types.
datastore integer Filter by parent datastore ID. Repeat the parameter (?datastore=42&datastore=43) to filter by multiple datastores.
name string Case-insensitive name search.
page integer 1-based page number.
size integer Page size (max 100).
cURL
curl -X GET "https://your-instance.qualytics.io/api/containers?container_type=computed_join&datastore=42" \
  -H "Authorization: Bearer <YOUR_API_TOKEN>"

Delete a Computed Join

Endpoint: DELETE /api/containers/{id}

Permission: Editor on the left datastore, or Author who is the current owner. Editors do not need to own the join to delete it.

Expected response: 204 No Content on success.

Deletes the Computed Join and all its quality checks, anomalies, profile data, and derived computed fields. The operation is irreversible.

If the Computed Join is referenced by quality checks elsewhere, the delete fails with 409 Conflict.

cURL
curl -X DELETE https://your-instance.qualytics.io/api/containers/123 \
  -H "Authorization: Bearer <YOUR_API_TOKEN>"

Error responses

Status Trigger
400 DISTINCT used in the Select Expression; join field not found in the left or right container; incompatible join field types
401 Missing, invalid, or expired Bearer token
403 Caller lacks the required permission for the action
404 The container {id} in the path does not exist (Get, Update, Delete); the referenced left_container_id or right_container_id does not exist (Create, Validate)
408 The synchronous validation step timed out. On POST /containers/validate you can retry with a higher timeout_seconds (up to 300). On Create and Update, the timeout is fixed by the deployment; retry the request, or simplify the join by narrowing each side with a filtered Computed Table or Computed File.
409 Duplicate container name on the same datastore; input container is a Computed Join (not supported); input container has not been profiled; dropping fields with dependent checks or anomalies (use force_drop_fields=true); referenced by quality checks (delete only)
422 Request body validation failure (missing required field, field exceeds max length); SQL parse error returned by the synchronous validation (multi-statement SQL, unresolved column in Select or Where, GROUP BY validation failure, duplicate column names after prefixing)