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, business rules, profiling objects, profiling rules and profiling data types.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:
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 |
|---|---|---|
| X | X |
| X | |
| X | |
| X | |
| X | |
| X | |
| X | |
| X | X |
| X | |
| X | |
| X | |
| X | |
| X | |
| X | |
| X | |
| X | |
| X |
Import JSON entity
Creates or updates entities from JSON, in the same format the application exports. An entry whose id is already known updates that entity; any other entry creates a new one under that id.
One entity type per request. Pick the type in the request schema to see its fields.
Dependency order. Import entities before the entities that refer to them: test suites, then test cases, then business rules.
Batch size. 100 to 200 entities per request is recommended. There is no hard limit.
Send the full entity on an update. A field that is left out is reset to its default; for lists, each field's description says what absent and empty mean. Reading the entity back with
GET /api/v1/import/reference/{reference}gives the full entry to change and post back.Sequential requests. Requests of unrelated entity types may run in parallel, but they are not faster and contend with other writes, so sending requests one after another is recommended.
Requires a service API key with the IMPORT scope.
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. The request schema describes the payload of every entity type, see JSON entity types.
Response example:
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 itsobjectReference(the entityid) and a plainreason.objectReferenceisnullwhen the entry'sidis 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 asfield 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 warning reports what could not be kept, not a rejection. A failed entity reports only its error, never warnings. A JSON payload has no file rows, so warnings identify the entity byobjectReferenceand never carry a line number. Rows that could not be imported applies to CSV uploads only.
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 |
|
Read / exists |
|
Update |
|
Delete |
|
All of these need an API key with the IMPORT scope.
Read, modify, write back. GET /api/v1/import/reference/{uuid} returns the entity as an import entry, { "entityType": "TEST_SUITE", "entity": { ... } }, exactly the shape /api/v1/import takes. The entity type is resolved from the UUID, so the request needs nothing else. Change the fields you need and post the entry back inside an array, [{ "entityType": ..., "entity": ... }]; posting it back unchanged is a no-op update.
Update semantics for lists. On an update, a list key that is absent or null keeps the current value, and an empty list clears it. This applies to the test suite fields tags, emails, webhookRefs and allowedRoles (an empty string clears allowedRoles), the business rule fields 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.
These exceptions keep the current value rather than clear it by accident:
Business rule
owners: on an existing rule, absent,[]or no known name keeps the current owners, and a rule without owners stays without them. A new rule with no known owner gets the importing user as owner when a user imports it; under a service API key it gets no owner, so only administrators can edit it until an owner is added. Each of these cases adds a warning.Test suite
owner: absent, blank or an unknown name keeps the current owner. A new suite with no known owner getsadminas owner, with a warning.A non-empty list in which no name or UUID resolves (business rule
allowedRoles, test suitewebhookRefs) keeps the current value; each unresolved entry is reported as a warning.
Recommendations:
Send one entity type per request, in dependency order: dynamic rules, test suites, test cases, then business rules, so that
dynamicRuleRef,testsuiteRefandtestCaseRefsresolve.Send requests sequentially, not in parallel.
Use batches of 100 to 200 entities per request. There is no hard limit.
Generate the
idas 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
The fields of every entity type, with their defaults, the rules for absent and empty lists and what makes an entry fail, are described in the API specification and rendered per type under JSON entity types. On an update, a field that is left out is reset to its default, so always send the full entity, for example the entry read back with GET /api/v1/import/reference/{uuid}. Unknown fields are ignored.
Get entity by reference
Returns the entity with this id as an import entry, { "entityType": ..., "entity": ... }, the same shape /api/v1/import takes. To update the entity, change the fields you need and post the entry back inside an array; posting it back unchanged is a no-op update.
Reads dynamic rules, test suites, test cases and business rules. Requires a service API key with the IMPORT scope.
Request parameters
Responses
Response example for a business rule:
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
Import endpoint for any CSV objects that are previously exported from the application
Request parameters
Responses
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.
What the counters mean for catalog types
For OBJECT, COLUMN and TERM, created and updated say whether a row wrote a new entity or changed one the catalog already had:
OBJECT- only objects already in the catalog can be imported, so every imported row counts asupdated. A row naming an object the catalog does not have counts infailed.COLUMN- a row naming a column already in the catalog (same connection, schema, object and column name, compared ignoring case) changes that column and counts asupdated. Any other row inserts a new column and counts ascreated.TERM- a row naming a term that already exists in the same glossary (name compared ignoring case) changes that term and counts asupdated. Any other row creates the term and counts ascreated.
A row repeating an earlier row's write target counts in neither: the entity is written once, by the first row, and the repeat is reported as described in Rows that could not be imported.
Rows that could not be imported
A row the platform cannot read or resolve does not fail the upload. The remaining rows import normally and each problem row is reported in the response warnings array as Line <n>: <reason>. Line numbers are 1-based over the raw file with the header as line 1, so they match what a spreadsheet shows and the file can be corrected without counting rows by hand.
The response carries no severity, so read the reason: the first two cases below describe a row that did not import, the third a row that imported with something dropped.
A row is reported for one of three reasons:
It could not be read, and did not import. A cell does not match its column's type - a number, a UUID or a boolean. Boolean columns accept
true/false,1/0,yes/noandy/nin any case; a blank cell falls back to the column's default, and anything else is rejected rather than read asfalse.It could not be resolved, and did not import. Something the row points at does not exist or is not visible to the API key - an unknown connection, object, column or term. A term reference additionally has to carry its glossary path, see Term references.
Part of it was dropped, and the rest imported. A row repeating an earlier row's write target is reported as
Duplicate of line <n>. This row will be skipped.and the entity is written once. AnalertEmailsaddress that is not valid is reported asInvalid email address "<x>" in alertEmails. It will be skipped.and the entity imports without that address - one warning per bad address, so a row with two of them is reported twice on the same line.
Rows that import with a note in the catalog import preview, such as a defaulted owner or an unknown owner name left off, are reported in warnings too.
Warnings are listed in file order. At most 10 are listed, followed by a single line counting the ones left out (2 more problems were not listed.), so a large broken file does not return one warning per row. The count is of problems rather than rows, since one row can report several.
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 rootMy glossary|Term name- a term inside a glossary, with a pipe (|) separating path and nameParent 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- thesourceNameandtargetNamecolumnsCOLUMN_TERM_RELATION- thetermcolumnterm-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
Which import endpoint accepts which entityType:
JSON only (
/api/v1/import):TEST_SUITE,CONNECTION,DYNAMIC_RULE,VARIABLE,WEBHOOK,PARAMETER,PROFILING,PROFILING_RULE,PROFILING_RULE_TYPE.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 needtestCaseRefs.
CSV imports expect headers that match the corresponding export template - download it from the catalog import UI before filling it in.
![]()
JSON entity types
The fields of every JSON entity type are described in the API specification, which the sections below render per type. The same descriptions appear in the Swagger UI the application serves (see API), where the request body of Import JSON entity offers the entity types as a choice. Each description says what the field means, whether it is required, what an absent or empty value does on an update, and how references to other entities are resolved. The TEST_SUITE and BUSINESS_RULE examples of the endpoint import as they are and are a good starting point.
Import entities before the entities that refer to them, one entity type per request:
CONNECTION,WEBHOOK,VARIABLE,DYNAMIC_RULETEST_SUITETEST_CASE, thenPARAMETERBUSINESS_RULEPROFILING_RULE_TYPE, thenPROFILING_RULE, thenPROFILING. The connection's catalog must be synced first, because profilings match their schema, object and columns by name.
A reference that does not resolve never fails the whole request. Depending on the field, the entity is imported without that link, the value that refers to it is skipped, or that one entity fails; the field descriptions say which.
The entity of each type is described below, generated from the same specification.
TEST_SUITE
TestSuiteExportDTO
A test suite. Test cases join a suite through their own testsuiteRef; a suite does not list them.
TEST_CASE
TestCaseExportDTO
A test case. Connections and test suites it refers to must be imported first.
BUSINESS_RULE
BusinessRuleExportDTO
A business rule. An update changes only the fields below; the rule's folder, its dynamic rule link and its auto-generate setting are kept.
CONNECTION
ConnectionExportDTO
A database connection. Credentials are not part of the payload: set them in the Connections page or the secrets backend after the import.
DYNAMIC_RULE
DynamicRuleExportDTO
A dynamic rule: an SQL template that generates test cases from catalog metadata.
VARIABLE
VariableExportDTO
A global variable, used in SQL as ${name}.
WEBHOOK
WebhookExportDTO
A webhook that alerts can be sent to.
PARAMETER
ParameterExportDTO
A rule parameter and its values per test case.
PROFILING
ProfilingExportDTO
A profiling of one catalog object, with its rules, excluded values, schedule and alerts. The connection must exist and its catalog must be synced: the schema, object and rule columns are matched by name. Import PROFILING_RULE_TYPE and PROFILING_RULE first. Rules, excluded values and alerts replace the current ones. Results history never travels with a profiling.
PROFILING_RULE
ProfilingRuleExportDTO
A rule in the profiling rule library, which profilings refer to by name. Built-in rules cannot be imported. A rule name is unique: an unknown id whose name matches an existing rule updates that rule, and a rename follows through to every profiling that uses it.
PROFILING_RULE_TYPE
ProfilingRuleTypeExportDTO
A profiling data type: a named group of database column types that rules target through ruleTypes. A rename follows through to the rules that use it.
Notes
The notes below cover behaviour that is not a property of a single field.
Test cases and business rules from CSV
TEST_CASE and BUSINESS_RULE also import from CSV and Excel files. The columns have the same names as the JSON fields, with relations.schema, relations.object and relations.columns for the relation. A business rule CSV does not link test cases: use JSON when you need testCaseRefs.
In CSV and Excel files reportType accepts any letter case, and any other value fails that row.
Profilings that import partly
A profiling still imports when part of it cannot be resolved, but what happens to the unresolved part depends on which part it is:
Dropped, with a warning. A
rules[].columnNamethat is not in the catalog for that object, and awebhookRefthis instance does not know. The rule or alert is not created; everything else is kept.Created anyway, with a warning. A
ruleNamewith no entry in the profiling rule library. The rule is stored against the profiling but has nothing to execute, so it stays inert until that library rule is imported too, at which point it starts running with no further action.Created anyway, silently. An
emailthat matches no user is stored as a plain address alert rather than a user alert, and emits no warning. Notifications go to that address as typed, so a misspelling is not reported back.
Only the first case leaves nothing behind. Re-importing after fixing the library rule or the address is safe, because rules and alerts are replaced wholesale. Results history, last-execution stamps and profiled values never travel with a profiling: an import restores the definition, not what it has measured.
Built-in profiling rules
The built-in rules columnValues, countOfRows, freshness, uniqueValues, notNullCount and nullCount are not exported and cannot be imported. A PROFILING_RULE payload naming one fails with the existing rule is not modifiable.
OBJECT
CSV import only via /api/v1/import/csv?type=OBJECT. Updates catalog objects (tables and views) that are already in the catalog; a row naming an object the catalog does not have fails. 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. A row for a schema or object the catalog does not have yet creates it first. 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, the term is placed at the glossary root, and when it does not match an existing glossary, that row fails. 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
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:
Response example:
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 reachestotal, 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:
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:
Import the identical query again, under a new batchId or with none:
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:
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
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:
Response example:
Delete entities
Deletes entities by the id they were imported or exported with. One request may mix entity types. The id is released, so importing it again creates a new entity.
Requires a service API key with the IMPORT scope.
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:
Response example: