Data Observability platform Help

Import API

The Import API allows you to programmatically import entities into the platform, bulk-delete them, and import or delete column level lineage from raw SQL queries.

Two payload formats are supported:

  • JSON via /api/v1/import - recommended for configuration entities such as test cases, test suites, connections, dynamic rules, variables, webhooks, parameters and business rules.

  • CSV via /api/v1/import/csv - used for catalog entities such as objects, columns, terms and their relations, as well as CSV exports of business rules.

Each JSON request is an array of wrapper objects in the form:

[ { "entityType": "<TYPE>", "entity": { /* entity payload */ } } ]

All entities in a single JSON request must share the same entityType. IDs (id, connectionRef, testsuiteRef, dynamicRuleRef, webhookRefs, testCaseRef) are UUIDs - if the entity already exists with the given ID it is updated, otherwise it is created.

Supported entityType values:

Entity type

JSON

CSV

TEST_CASE

X

X

TEST_SUITE

X

CONNECTION

X

DYNAMIC_RULE

X

VARIABLE

X

WEBHOOK

X

PARAMETER

X

BUSINESS_RULE

X

X

OBJECT

X

COLUMN

X

COLUMN_RELATION

X

COLUMN_TERM_RELATION

X

TERM

X

TERM_RELATION

X

Import JSON entity

/api/v1/import

Create or update entities of one type. An entity whose id is already known is updated, otherwise it is created under that id. Always HTTP 200 for a processed request; the per-entity outcome is in the body. On an update a list key that is absent keeps the current value and an empty list clears it.

Request parameters

Responses

Import one or more entities of the same type as a JSON array. Each element must specify entityType and an entity payload. See the per-type sections below for the expected payload structure.

Response example:

{ "type": "TEST_SUITE", "created": 1, "updated": 1, "failed": 1, "total": 3, "errors": [ { "objectReference": "0b8f6e8e-3d0c-5c55-a0a1-0f8f2f0b6c11", "reason": "A test suite named \"Addresses - core checks\" already exists (reference d2f2d729-721c-4e6e-b5ab-4dad679cb561)" } ], "warnings": [ { "objectReference": "d2f2d729-721c-4e6e-b5ab-4dad679cb561", "reason": "Webhook reference 5e4b3f02-9b21-4f0a-9bd7-1c52b5d0e0a0 was not found and was skipped" } ] }

A processed request always returns HTTP 200; the outcome of each entity is in the body:

  • created, updated, failed, total - counts for this request. An entity is counted as created or updated only after it has been saved completely; a failed entity leaves nothing behind.

  • errors - one entry per failed entity, with its objectReference (the entity id) and a plain reason. objectReference is null when the entry's id is not a UUID; the reason then names the entry's position in the request. When a field has the wrong type (for example an object where a string is expected), the reason names the entry's position and the field, such as field tags[0].name.

  • warnings - the entity was imported, but something in it was skipped, for example a reference to a webhook or test case that does not exist, a custom field that does not exist, a value that is not one of a custom field's options, an invalid email address, an unknown role or a tag without a name. A failed entity reports only its error, never warnings.

null elements in a list are ignored, the same as if they were not sent. A text field containing a NUL character fails the entry, and the reason names the field.

A request that cannot be processed at all returns HTTP 400 with a message: invalid JSON (also a null body or a null entry), an empty array, mixed entity types, an entry whose entityType is missing or unknown (the message lists the valid values), or a catalog type that is imported as a CSV file.

Managing entities by UUID

Dynamic rules, test suites, test cases and business rules can be created, read, updated and deleted from your own tooling by using UUIDs that you generate yourself as the entity id:

Operation

Call

Create

POST /api/v1/import with your own id

Read / exists

GET /api/v1/import/reference/{uuid} - { entityType, entity } in the import format, 404 if unknown

Update

POST /api/v1/import with the same id and the full entity

Delete

POST /api/v1/delete with { "ids": [...] }

All of these need an API key with the IMPORT scope.

Read, modify, write back. GET /api/v1/import/reference/{uuid} returns { "entityType": "...", "entity": { ... } }, exactly the shape the import takes. The entity type is resolved from the UUID, so the request needs nothing else. Change the fields you need inside entity and post the whole response back to /api/v1/import as it is; posting it back unchanged is a no-op update.

Update semantics for lists. On an update, a list key that is absent keeps the current value, and an empty list clears it. This applies to the test suite fields tags, webhookRefs, emails and allowedRoles (an empty string clears allowedRoles), the business rule fields owners, allowedRoles and testCaseRefs, the test case field labels and the dynamic rule field drivers. Scalar fields are always taken from the request, so send the full entity.

Recommendations:

  • Send one entity type per request, in dependency order: dynamic rules, test suites, test cases, then business rules, so that dynamicRuleRef, testsuiteRef and testCaseRefs resolve.

  • Send requests sequentially, not in parallel.

  • Use batches of 100 to 200 entities per request. There is no hard limit.

  • Generate the id as a UUID v5 from your own stable key, with a separate namespace per entity type. A UUID can belong to only one entity: reusing a test suite's UUID for a business rule fails that entry with "Reference ... already belongs to a TEST_SUITE".

Entities created in the UI have no reference until they are imported or exported. To manage such an entity through the API, export it once from the UI (the export assigns its reference) and use the id from the export. Creating a new test suite with the name of an existing one fails with A test suite named "..." already exists, followed by the existing suite's reference if it has one; the import never takes over an existing suite silently.

When an entity is deleted, in the UI or through /api/v1/delete, its reference is removed. Importing the same UUID again creates a new entity.

Field reference

Field names, types and rules for the four entity types of the CRUD flow. "Default" is what a create stores when the field is left out; on an update, a left-out scalar field is reset to that default, so always send the full entity (for example the result of GET /api/v1/import/reference/{uuid}). Lists follow the update rule above: left out keeps, empty clears. Unknown fields are ignored.

All entities:

Field

Type

Required

Notes

id

UUID

recommended

Your reference. Without it the entity is created under a generated UUID, reported back as a warning. A UUID can belong to one entity only.

customFields

list of { "fieldName": string, "value": [string] }

no

A required custom field that is left out gets its default value.

DYNAMIC_RULE

Field

Type

Required

Default

Notes

shortDescription

string

yes

Name of the rule. Blank fails the entry.

longDescription

string

no

sql

string

to run

May use the {schema}, {object} and {column} placeholders. Not checked on import.

expectedResult

string

to run

For example 0 or >0. Not checked on import.

drivers

list of string

no

all

Connector types the rule applies to, for example postgresql.

TEST_SUITE

Field

Type

Required

Default

Notes

name

string

yes

Unique, case-insensitive. Blank, or taken by another suite, fails the entry.

owner

string

no

User name.

directory

string

no

root folder

Forward-slash separated path, missing folders are created.

visibility

string

no

PUBLIC

PUBLIC, PRIVATE, READ_ONLY.

allowedRoles

string

no

none

Comma-separated role names; "" clears. An unknown role is skipped with a warning.

severity

string

no

CRITICAL

CRITICAL, WARNING, INFO.

alertMode

string

no

ON_FAILURE

ON_FAILURE, ALWAYS.

emailThreshold

number

no

0

Percentage of failing test cases, 0 to 100, above which an ON_FAILURE alert is sent (10 means 10%). Outside that range fails the entry.

emails

list of string

no

none

Alert recipients. A user's email links that user. An invalid address is skipped with a warning; a repeated one is stored once.

webhookRefs

list of UUID

no

none

References of imported webhooks. An unknown one is skipped with a warning.

tags

list of { "name": string, "color": string }

no

none

A tag without a name is skipped with a warning.

resultsInReportRows

integer

no

0

Result rows shown per test case in the report, 0 to 1000 (clamped). On an update, leave it out to keep the current value.

reportType

string

no

HTML

HTML, EXCEL.

schedule fields

no

not scheduled

See the schedule table below.

TEST_CASE

Field

Type

Required

Default

Notes

description

string

yes

Name of the test case. Blank fails the entry.

sql

string

to run

The test query. Not checked on import.

expectedResult

string

to run

For example 0 or >0. Not checked on import.

type

string

no

Query

Query, Query + total or Compare, exactly as written. Any other value fails the entry.

connectionRef

UUID

yes, to run

none

Reference of an imported connection. connectionName is used when the reference is not found. Neither found: imported without a connection, with a warning. A metadata-only connector fails the entry.

connectionName

string

no

The connection's name exactly as shown in the UI (case-sensitive). The simplest way to link a connection created in the UI, which has no reference until it is exported or imported. Used when connectionRef is absent or not found.

compareConnectionRef

UUID

for Compare

Same rules as connectionRef (compareConnectionName as fallback).

compareSql

string

for Compare

testsuiteRef

UUID

no

none

testsuiteName is used when the reference is not found; neither found gives a warning.

testsuiteName

string

no

The suite's name exactly as shown in the UI (case-sensitive). Used when testsuiteRef is absent or not found.

dynamicRuleRef

UUID

no

none

An unknown one is skipped with a warning.

owner

string

no

User name.

info

string

no

Long description, at most 10000 characters (longer fails the entry).

severity

string

no

CRITICAL

CRITICAL, WARNING, INFO.

disabled

boolean

no

autoUpdate

boolean

no

autoRelation

boolean

no

instance setting

Derive the relation from the SQL.

relations

{ "schema": string, "object": string, "columns": [string] }

no

The tested object.

saveResults

boolean

no

false

resultsInReportRows

integer

no

0

0 to 1000.

predictType

string

no

linear

predictThreshold

number

no

-1 (off)

labels

list of string

no

none

Blank labels are dropped and repeated ones stored once, as in the editor.

schedule fields

no

the suite's schedule

See the schedule table below.

BUSINESS_RULE

Field

Type

Required

Default

Notes

name

string

yes

Unique, case-insensitive. Blank, or taken by another rule, fails the entry.

description

string

no

""

At most 10000 characters (longer fails the entry). On an update, leave it out to keep the current description.

owners

list of string

no

none

User names or display names. An unknown one is skipped with a warning.

allowedRoles

list of string

no

none

Role names.

testCaseRefs

list of UUID

no

none

References of imported test cases. An unknown one is skipped with a warning.

An update keeps the rule's folder, dynamic rule link and auto-generate setting.

Schedule fields (TEST_SUITE and TEST_CASE)

Field

Type

Used by

Default

Notes

scheduleType

string

all

NOT_SCHEDULED, SELECTED_DAYS, MONTHLY, CUSTOM, CRON, in any case. Any other value fails the entry. Test suite: on an update, leave it out to keep the current schedule; NOT_SCHEDULED removes it. Test case: leave it out or use NOT_SCHEDULED to inherit the suite's schedule.

scheduleDay

string

SELECTED_DAYS

every day

Full English day names separated by commas, for example Monday,Wednesday. Spaces and case do not matter; any other name fails the entry.

scheduleTime

string

SELECTED_DAYS, MONTHLY

09:00

24-hour HH:mm from 00:00 to 23:59, for example 09:00. 9:00 or 24:00 fail the entry.

scheduleDate

string or number

MONTHLY

1

Day of month, 1 to 31. For MONTHLY any other value fails the entry; other types ignore it.

scheduleCustom

string or number

CUSTOM, CRON

300 for CUSTOM

CUSTOM: interval in whole minutes, 1 to 1440. CRON: the cron expression, required.

Get entity by reference

/api/v1/import/reference/{reference}

Returns { entityType, entity } in the import format; the entity type is resolved from the reference. The response can be posted back to /api/v1/import unchanged. Needs the IMPORT scope.

Request parameters

Responses

Response example for a business rule:

{ "entityType": "BUSINESS_RULE", "entity": { "id": "3244945c-c777-4fc8-9b63-cf1501011bf3", "name": "Every order must have an address", "description": "Orders with no linked address cannot be fulfilled.", "owners": ["David Smith"], "allowedRoles": [], "testCaseRefs": ["fd523557-118e-4356-81e9-432ed462d50c"] } }

Works for dynamic rules, test suites, test cases and business rules. Returns 404 when the reference is unknown, its entity no longer exists or it belongs to another type (connections, webhooks, variables and parameters are not read back), and 400 when the path is not a UUID.

Import CSV entity

/api/v1/import/csv

Import endpoint for any CSV objects that are previously exported from the application

Request parameters

Responses

{ "type": "CONNECTION", "created": 96, "updated": 96, "unchanged": 96, "deleted": 96, "failed": 96, "total": 96, "errors": [ { "objectReference": "18ad0215-778d-352d-8f14-959901273e8d", "reason": "example" } ], "warnings": [ { "objectReference": "18ad0215-778d-352d-8f14-959901273e8d", "reason": "example" } ], "batchId": "example" }

Used for catalog entity types (OBJECT, COLUMN, COLUMN_RELATION, COLUMN_TERM_RELATION, TERM, TERM_RELATION) as well as CSV exports of TEST_CASE and BUSINESS_RULE. The expected CSV headers match those produced by the matching export template - you can download the template for a given entity type from the catalog import UI.

Term references

Several CSV columns reference business glossary terms by name. Because a term name is only unique within its glossary, these references embed the glossary path in the value:

  • Term name - a term at the glossary root

  • My glossary|Term name - a term inside a glossary, with a pipe (|) separating path and name

  • Parent glossary/Sub glossary|Term name - nested glossary levels are joined with /

This is exactly what exports produce, so exported files re-import without editing. On import a bare term name matches root terms only - a term that lives inside a glossary must be referenced with its full glossary path, even if the name is unique across glossaries. A reference that cannot be resolved marks that row as failed.

The format is used wherever a CSV value points at a term:

  • TERM_RELATION - the sourceName and targetName columns

  • COLUMN_TERM_RELATION - the term column

  • term-type custom field values (cf_ columns) on any entity that supports them

Term mentions in descriptions

Description texts can embed glossary term mentions. Exports serialize each mention as a portable token in the form @[Label](key:|Glossary path|Term name|) (the glossary segment is empty for root terms). On import each token is matched against the glossary: a resolved mention becomes a live term link again, and an unresolved one keeps its label and re-links automatically once a matching term exists (for example later in the same import batch). Plain-text descriptions written by hand import as-is - the tokens only matter when round-tripping exported data.

Entity types

Each section below describes one entityType and which import endpoint accepts it.

  • JSON only (/api/v1/import): TEST_SUITE, CONNECTION, DYNAMIC_RULE, VARIABLE, WEBHOOK, PARAMETER.

  • CSV only (/api/v1/import/csv): OBJECT, COLUMN, COLUMN_RELATION, COLUMN_TERM_RELATION, TERM, TERM_RELATION.

  • Both formats: TEST_CASE, BUSINESS_RULE. Note that CSV business rule import does not link test cases - use JSON if you need testCaseRefs.

CSV imports expect headers that match the corresponding export template - download it from the catalog import UI before filling it in.

Import format

TEST_CASE

Import test cases. connectionRef and testsuiteRef must reference existing entities (or be included earlier in the same deployment flow). relations.schema and relations.object bind the test case to a catalog object so lineage and alerting work correctly.

saveResults keeps each execution's result rows, and resultsInReportRows sets how many breached records the test case's failure alerts list. Both are stored as sent: a resultsInReportRows above 0 makes the execution save results even when saveResults is false, but it does not turn the stored flag on. resultsInReportRows is clamped to 0..1000 silently, so a value above 1000 is imported as 1000 rather than rejected.

Request example:

[ { "entityType": "TEST_CASE", "entity": { "id": "fd523557-118e-4356-81e9-432ed462d50c", "connectionRef": "11d6f2ee-424b-4e64-abcb-f95902496b4a", "testsuiteRef": "d2f2d729-721c-4e6e-b5ab-4dad679cb561", "description": "public.addresses - Count of rows", "sql": "SELECT COUNT(*) FROM public.addresses", "expectedResult": ">0", "type": "Query", "owner": "David", "dynamicRuleRef": "eaf2f027-88fe-4258-9804-b50645ff5eb7", "autoUpdate": false, "disabled": true, "severity": "CRITICAL", "autoRelation": true, "saveResults": true, "resultsInReportRows": 25, "relations": { "columns": [], "schema": "public", "object": "addresses" }, "labels": [ "LIVE" ], "scheduleType": "NOT_SCHEDULED" } }, { "entityType": "TEST_CASE", "entity": { "id": "1e5d783a-dd41-4712-b083-0d5e9a3dc9d8", "connectionRef": "11d6f2ee-424b-4e64-abcb-f95902496b4a", "testsuiteRef": "d2f2d729-721c-4e6e-b5ab-4dad679cb561", "description": "public.addresses - Duplicates", "sql": "SELECT COUNT(*) FROM (SELECT \"language\",\"suite\" FROM public.addresses GROUP BY \"language\",\"suite\" HAVING COUNT(*)>1) a", "expectedResult": "=0", "type": "Query", "owner": "David", "autoUpdate": false, "disabled": false, "severity": "WARNING", "relations": { "columns": [ "language", "suite" ], "schema": "public", "object": "addresses" }, "labels": [] } } ]

Key fields:

  • type - Query, Query + total or Compare; any other value fails the entry. Compare additionally requires compareConnectionRef and compareSql.

  • dynamicRuleRef - optional UUID of the parent dynamic rule when this case was generated from one.

  • labels - on an update, leave the key out to keep the current labels, send [] to clear them.

  • severity - CRITICAL, WARNING, INFO.

  • scheduleType - see Scheduling. Omit or use NOT_SCHEDULED to inherit the test suite schedule.

TEST_SUITE

Import test suites. Referenced test cases are linked through testsuiteRef in the test case payload - a test suite import does not embed its test cases.

Request example:

[ { "entityType": "TEST_SUITE", "entity": { "id": "d2f2d729-721c-4e6e-b5ab-4dad679cb561", "name": "Addresses - core checks", "owner": "David", "directory": "Customer data/Addresses", "emails": [ "data-quality@example.com" ], "emailThreshold": 10, "resultsInReportRows": 100, "severity": "CRITICAL", "alertMode": "ON_FAILURE", "visibility": "PUBLIC", "allowedRoles": "data-quality,analysts", "webhookRefs": [ "5e4b3f02-9b21-4f0a-9bd7-1c52b5d0e0a0" ], "tags": [ { "name": "LIVE", "color": "green" }, { "name": "core", "color": "blue" } ], "scheduleType": "SELECTED_DAYS", "scheduleDay": "Monday,Tuesday,Wednesday,Thursday,Friday", "scheduleTime": "06:00" } } ]

Key fields:

  • directory - forward-slash separated folder path. Missing folders are created on import.

  • emailThreshold - percentage of failing test cases (0 to 100) above which an email notification is sent.

  • alertMode - ALWAYS or ON_FAILURE.

  • visibility - PUBLIC, PRIVATE or READ_ONLY. PUBLIC is viewable and editable by everyone, PRIVATE is viewable and editable only by the owner and users matching allowedRoles, READ_ONLY is viewable by everyone but only editable by the owner and users matching allowedRoles.

  • allowedRoles - comma-separated role names. Used when visibility is PRIVATE (controls view and edit) or READ_ONLY (controls edit only). Ignored when visibility is PUBLIC.

  • scheduleType - NOT_SCHEDULED, SELECTED_DAYS, MONTHLY, CUSTOM, CRON. Additional fields scheduleDay, scheduleTime, scheduleDate, scheduleCustom are used depending on the chosen type - see Scheduling. Fields the type does not use can be left out; they get the scheduling form's defaults (every day, 09:00, day 1, interval 300). A CRON schedule needs only scheduleCustom with the cron expression, for example "0 6 * * 1-5"; without one the entity fails with "A CRON schedule needs a cron expression in scheduleCustom". On an update, leaving scheduleType out keeps the suite's current schedule; NOT_SCHEDULED removes it.

  • tags, webhookRefs, emails, allowedRoles - on an update, leave the key out to keep the current value, send an empty value to clear it. A webhookRefs UUID that does not resolve is skipped with a warning.

CONNECTION

Import database connections. Credentials are not included in the payload and must be set through the Connections UI or the secrets backend after import.

Request example:

[ { "entityType": "CONNECTION", "entity": { "id": "11d6f2ee-424b-4e64-abcb-f95902496b4a", "type": "postgresql", "name": "warehouse-prod", "databaseUrl": "warehouse.internal", "databaseName": "analytics", "databaseUser": "dqm_reader", "databasePort": 5432, "maxThreads": 4, "timeout": 60, "properties": "sslmode=require", "jdbcUrlOverride": null } } ]

Key fields:

  • type - connector identifier as shown in the Connections UI (e.g. postgresql, mssql, snowflake, bigquery). See Connections.

  • jdbcUrlOverride - use this to supply a full JDBC URL instead of the discrete databaseUrl/databasePort/databaseName triple.

DYNAMIC_RULE

Import dynamic rules - SQL templates that generate test cases based on metadata.

Request example:

[ { "entityType": "DYNAMIC_RULE", "entity": { "id": "eaf2f027-88fe-4258-9804-b50645ff5eb7", "shortDescription": "Row count > 0", "longDescription": "Asserts that the target object has at least one row.", "sql": "SELECT COUNT(*) FROM {schema}.{object}", "expectedResult": ">0", "drivers": [ "postgresql", "mssql" ] } } ]

Key fields:

  • sql - may use the {schema}, {object} and {column} placeholders that are substituted per generated test case.

  • drivers - list of connector types this dynamic rule applies to. Leave empty for all. On an update, leave the key out to keep the current drivers; [] clears them.

VARIABLE

Import global variables usable in SQL via ${variableName} syntax.

Request example:

[ { "entityType": "VARIABLE", "entity": { "id": "8b3d1e42-9ac0-4a7d-8a71-5c2f8d1aa001", "name": "environment", "value": "PRODUCTION" } }, { "entityType": "VARIABLE", "entity": { "id": "8b3d1e42-9ac0-4a7d-8a71-5c2f8d1aa002", "name": "maxDaysStale", "value": "7" } } ]

WEBHOOK

Import webhook definitions used for alerting.

Request example:

[ { "entityType": "WEBHOOK", "entity": { "id": "5e4b3f02-9b21-4f0a-9bd7-1c52b5d0e0a0", "name": "slack-data-quality", "url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX", "json": { "text": "DQM alert: {{testSuiteName}} - {{failedCount}} failing tests" } } } ]

Key fields:

  • json - request body template. Placeholders such as {{testSuiteName}}, {{failedCount}} are substituted by the alerting engine when the webhook fires.

PARAMETER

Import per-test-case parameter overrides. values[].testCaseRef must match an existing test case UUID.

Request example:

[ { "entityType": "PARAMETER", "entity": { "id": "6a1f9b3b-0d77-4f35-9fa4-c7b82b3c1234", "name": "expectedRowCount", "values": [ { "testCaseRef": "fd523557-118e-4356-81e9-432ed462d50c", "value": "10000" }, { "testCaseRef": "1e5d783a-dd41-4712-b083-0d5e9a3dc9d8", "value": "0" } ] } } ]

Parameter values are fully replaced on import: any existing values for the parameter that are not listed in the values array are removed.

BUSINESS_RULE

Import business rules. The testCaseRefs field links the rule to test cases by UUID - those test cases must already exist or be imported in the same deployment.

Request example:

[ { "entityType": "BUSINESS_RULE", "entity": { "id": "3244945c-c777-4fc8-9b63-cf1501011bf3", "name": "Every order must have an address", "description": "Orders with no linked address cannot be fulfilled.", "owners": [ "david@example.com", "anna@example.com" ], "allowedRoles": [ "data-stewards" ], "testCaseRefs": [ "fd523557-118e-4356-81e9-432ed462d50c", "1e5d783a-dd41-4712-b083-0d5e9a3dc9d8" ] } } ]

Key fields:

  • owners - user names or display names. An unknown name is skipped with a warning.

  • owners, allowedRoles, testCaseRefs - on an update, leave the key out to keep the current value, send [] to clear it. A testCaseRefs UUID that does not resolve is skipped with a warning.

An update changes the name, description and the lists above. The rule's folder, its dynamic rule link and the auto-generate setting are kept, since the import format does not carry them.

Business rules are also importable from CSV via /api/v1/import/csv?type=BUSINESS_RULE, however CSV import does not link test cases - use the JSON endpoint if you need to set testCaseRefs.

OBJECT

CSV import only via /api/v1/import/csv?type=OBJECT. Imports catalog objects (tables and views) into the catalog. Expected CSV headers match the OBJECT export template downloadable from the catalog import UI.

COLUMN

CSV import only via /api/v1/import/csv?type=COLUMN. Imports column descriptions and metadata attached to existing catalog objects. Expected CSV headers match the COLUMN export template.

COLUMN_RELATION

CSV import only via /api/v1/import/csv?type=COLUMN_RELATION. Imports column-level lineage relations between catalog columns. For SQL-driven lineage that the platform should parse for you instead, use the Import lineage endpoint.

COLUMN_TERM_RELATION

CSV import only via /api/v1/import/csv?type=COLUMN_TERM_RELATION. Imports the mapping between catalog columns and business glossary terms. The term column uses the term reference format, so glossary-scoped terms are written as My glossary|Term name.

TERM

CSV import only via /api/v1/import/csv?type=TERM. Imports business glossary terms.

Columns: name (required), color, description, type, glossary, plus one cf_ column per custom field defined for terms (multiple values within one cell are separated by ;). glossary is the full path of an existing glossary with nested levels joined by / (e.g. Finance/Accounting); when it is empty or does not match an existing glossary, the term is placed at the glossary root. An unknown type value creates that term type. Descriptions may carry term mention tokens; values of term-type custom fields use the term reference format.

TERM_RELATION

CSV import only via /api/v1/import/csv?type=TERM_RELATION. Imports relations between business glossary terms.

Columns: sourceName, relation, targetName. Both term columns use the term reference format - there is no separate glossary column, the glossary path is part of the term reference (My glossary|Term name).

The relation value is matched case-insensitively against the built-in relations (Synonym, Related to, Contains) and the custom relation types defined under Settings. A directed custom relation is accepted by either of its side names - importing the inverse side swaps source and target, so the stored relation always uses the type's original direction. An unknown relation value creates a new custom relation type with that name. Rows that duplicate an existing relation are reported as failed, and Contains relations are validated against containment cycles.

Import lineage

/api/v1/import/lineage

Import column level lineage from SQL queries

Request parameters

Responses

Parses the supplied SQL queries against the named connection's metadata and creates column level lineage relations where source and destination columns can be resolved. Queries that reference objects unknown to the platform are skipped unless smart relations are enabled in lineage settings.

Request example:

{ "connectionName": "connection_name", "aggregateRelations": false, "batchId": "overnight-data-loading-2026-04-28", "queries": [ "SELECT COUNT(*) FROM sports.participants_events JOIN sports.latest_revisions ON id = event_id WHERE rank > 1" ] }

Response example:

{ "type": "QUERY", "created": 1, "updated": 0, "unchanged": 0, "deleted": 0, "failed": 0, "total": 1, "errors": [], "warnings": [], "batchId": "overnight-data-loading-2026-04-28" }

What the counters mean

total is the number of relations resolved from the submitted queries, and every one of them lands in exactly one of the next four counters:

  • created - the relation did not exist and a new row was inserted.

  • updated - the relation already existed, and this call attached new query evidence to its reference chain.

  • unchanged - the relation already existed and its whole reference chain was already there. Nothing was written; the import was an idempotent no-op.

  • failed - reserved. Lineage import has no partial failure: a query that resolves to no known columns is skipped before counting and never reaches total, while a genuine error aborts the whole call. The counter is in the sum for consistency with the other import endpoints.

So for a lineage import:

created + updated + unchanged + failed = total

deleted sits outside that sum, because the relations it counts were removed from a previous batch and were never part of the submitted payload.

unchanged is present only on the lineage import response. The other import endpoints do not detect a no-op, so they omit the field rather than report a zero they cannot stand behind, and so does the delete endpoint below, which submits no relations to leave unchanged.

A worked example. Import a query for the first time:

{ "created": 1, "updated": 0, "unchanged": 0, "total": 1 }

Import the identical query again, under a new batchId or with none:

{ "created": 0, "updated": 0, "unchanged": 1, "total": 1 }

Nothing was written, and unchanged: 1 is what says so. Before this counter existed the same call answered with every counter at zero, which was indistinguishable from an import that resolved nothing. Now import that same query together with a new one:

{ "created": 1, "updated": 0, "unchanged": 1, "total": 2 }

Batches

When you omit batchId, a UUID is generated, persisted as the batch handle, and returned in the response. Pass that same id to a later call to replace the batch, or to the delete endpoint below to remove it. Re-importing under an existing batchId replaces the batch: relations that reappear in the payload are reported as updated, and relations no longer present are removed and counted in deleted.

Note the interaction with unchanged. Replacing under the same batchId clears that batch's own reference rows first, so a relation that reappears is written afresh and counts as updated rather than unchanged. A nightly job that always passes the same batchId will therefore normally keep reporting updated, even when nothing about the lineage has actually changed.

That sweep is scoped to the batch's own rows. If identical evidence also exists under a different batchId, or with no batch at all (an import from the user interface, for instance), it survives the sweep and still matches, so the same call reports unchanged instead. In short: unchanged means nothing needed writing, and whether a same-batch re-import reaches that state depends on whether any other batch already holds the same evidence.

Delete lineage batch

/api/v1/import/lineage

Delete all lineage relations imported under a batchId

Request parameters

Responses

Removes every lineage relation imported under the given batchId, passed as a query parameter. Relations the batch created that retain no other references are deleted; relations that other batches still reference keep the relation row but lose the references this batch contributed. The call is idempotent - an unknown batchId returns deleted: 0.

Request example:

DELETE /api/v1/import/lineage?batchId=overnight-data-loading-2026-04-28

Response example:

{ "type": "QUERY", "created": 0, "updated": 0, "deleted": 3, "failed": 0, "total": 0, "errors": [], "warnings": [], "batchId": "overnight-data-loading-2026-04-28" }

Delete entities

/api/v1/delete

Delete any imported entity by the reference id(s)

Request parameters

Responses

Bulk-deletes entities by UUID. The endpoint resolves the entity type from the UUID automatically, so IDs from different types can be mixed in a single request.

Request example:

{ "ids": [ "3244945c-c777-4fc8-9b63-cf1501011bf3" ] }

Response example:

{ "deleted": 1, "failed": 0, "total": 1, "errors": [] }
14 October 2026