The OntoBricks REST API provides stateless endpoints for external applications to query ontologies and retrieve domain metadata.
http://localhost:8000/api/v1
Use Settings → Developer → API for the curated endpoint catalog and interactive Try-it controls. Its selectors list only API-exposed PUBLISHED domains and PUBLISHED versions. The selected-domain status distinguishes ontology-only domains, graph-backed domains awaiting their first build, and graph-ready domains; controls that require graph data are disabled until a graph exists while ontology operations remain available.
The generated references remain available at /api/docs (Swagger UI),
/api/redoc (ReDoc), and /api/openapi.json (OpenAPI JSON).
All endpoints that access Unity Catalog require Databricks authentication. Credentials can be provided via:
X-Databricks-Host: https://your-workspace.cloud.databricks.com
X-Databricks-Token: dapi...your-token
{
"databricks_host": "https://your-workspace.cloud.databricks.com",
"databricks_token": "dapi...your-token"
}State-changing requests (POST, PUT, PATCH, DELETE) to internal endpoints require a valid CSRF token:
- The server sets a
csrf_tokencookie on first visit. - Include the cookie value in the
X-CSRF-Tokenrequest header. - The
fetch()wrapper in the frontend attaches this header automatically. - External API endpoints (
/api/v1/) and GraphQL are exempted.
All endpoints return JSON responses with a standard format:
{
"success": true,
"data": { ... },
"message": "Optional message"
}{
"success": false,
"error": "Error description"
}Check if the API is running.
Response:
{
"status": "healthy",
"version": "<APP_VERSION>",
"service": "OntoBricks API"
}URLs use /api/v1/domains and /api/v1/domain/… for domain operations (saved ontology + mappings).
List available domains in a Unity Catalog volume.
Request:
{
"catalog": "my_catalog",
"schema": "my_schema",
"volume": "my_volume"
}Response:
{
"success": true,
"data": {
"domains": [
{
"name": "my_domain.json",
"path": "/Volumes/my_catalog/my_schema/my_volume/my_domain.json",
"size": 15234
}
],
"count": 1
}
}Get domain information and statistics.
Request:
{
"domain_path": "/Volumes/catalog/schema/volume/domain.json"
}Response:
{
"success": true,
"data": {
"name": "My Ontology Domain",
"description": "Domain description",
"uri": "https://example.com/ontology#",
"author": "John Doe",
"version": "1.0.0",
"status": "PUBLISHED",
"graph_backend": "none",
"statistics": {
"classes": 5,
"properties": 3,
"entities": 0,
"relationships": 0,
"has_r2rml": false
}
}
}graph_backend is normalized to none, lakebase, databricks, or
neo4j. Legacy documents without the field report lakebase.
Get full ontology details including classes and properties.
Request:
{
"project_path": "/Volumes/catalog/schema/volume/domain.json"
}Response:
{
"success": true,
"data": {
"base_uri": "http://example.org/ontology/",
"prefix": "ont",
"title": "My Ontology",
"description": "Ontology description",
"classes": [...],
"properties": [...],
"class_count": 5,
"property_count": 3
}
}Get list of ontology classes with their URIs.
Request:
{
"project_path": "/Volumes/catalog/schema/volume/domain.json"
}Response:
{
"success": true,
"data": {
"classes": [
{
"name": "Person",
"uri": "http://example.org/ontology/Person",
"attributes": [
{"name": "firstName", "type": "string"},
{"name": "lastName", "type": "string"}
],
"description": "A person entity"
}
],
"count": 1
}
}Get list of ontology properties (relationships) with their URIs.
Request:
{
"project_path": "/Volumes/catalog/schema/volume/domain.json"
}Response:
{
"success": true,
"data": {
"properties": [
{
"name": "worksFor",
"uri": "http://example.org/ontology/worksFor",
"domain": "Person",
"range": "Company",
"attributes": [],
"description": "Employment relationship"
}
],
"count": 1
}
}Get mapping details (entity and relationship mappings).
Request:
{
"project_path": "/Volumes/catalog/schema/volume/domain.json"
}Response:
{
"success": true,
"data": {
"data_source_mappings": [...],
"relationship_mappings": [...],
"has_r2rml": true,
"entity_mapping_count": 4,
"relationship_mapping_count": 2
}
}Get the R2RML mapping content from a domain.
Request:
{
"project_path": "/Volumes/catalog/schema/volume/domain.json"
}Response:
{
"success": true,
"data": {
"r2rml": "@prefix rr: <http://www.w3.org/ns/r2rml#> ...",
"format": "turtle"
}
}Execute a SPARQL query against a domain's ontology.
Request:
{
"project_path": "/Volumes/catalog/schema/volume/domain.json",
"query": "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10",
"limit": 100,
"engine": "local"
}Parameters:
project_path(required): Path to the domain JSON file in Unity Catalogquery(required): SPARQL query stringlimit(optional): Maximum number of results (default: 100)engine(optional): Query engine -local(RDFLib) orspark(default:local)
Response:
{
"success": true,
"data": {
"results": [
{"s": "http://example.org/entity1", "p": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "o": "http://example.org/Person"}
],
"columns": ["s", "p", "o"],
"count": 1,
"engine": "local"
}
}Validate SPARQL query syntax.
Request:
{
"query": "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"
}Response:
{
"success": true,
"data": {
"valid": true,
"error": null
}
}Get sample SPARQL queries generated for a domain.
Request:
{
"project_path": "/Volumes/catalog/schema/volume/domain.json"
}Response:
{
"success": true,
"data": {
"queries": [
{
"name": "List all entity types",
"description": "Returns all distinct entity types (classes) in the ontology",
"query": "PREFIX ont: <http://example.org/> ..."
}
],
"count": 4
}
}OntoBricks auto-generates a typed GraphQL schema from each domain's ontology. Ontology classes become GraphQL types, data properties become scalar fields, and object properties become typed relationship fields with nested traversal.
URL choice: The same router is mounted twice on the main app: in-app / browser paths below use /graphql/.... For the mounted external API (OpenAPI at /api/docs), use /api/v1/graphql/... instead — same handlers and payloads, different prefix (see api.constants.EXTERNAL_GRAPHQL_PUBLIC_PREFIX).
http://localhost:8000/graphql
For programmatic access via the external sub-application:
http://localhost:8000/api/v1/graphql
Returns all domains in the configured registry that have a materialized triple store.
Response:
{
"success": true,
"domains": [
{
"name": "my_domain",
"description": ""
}
],
"message": null
}Opens the interactive GraphiQL IDE for a specific domain. The playground provides auto-complete, documentation explorer, and query history.
Parameters:
project_name(path, required): Name of the domain in the registry
Execute a GraphQL query against the domain's auto-generated schema.
Request:
{
"query": "{ allCustomer(limit: 5) { id label hasInteraction { label } } }",
"variables": {},
"operationName": null,
"depth": 2
}Parameters:
project_name(path, required): Name of the domain in the registryquery(body, required): GraphQL query stringvariables(body, optional): Query variablesoperationName(body, optional): Operation name for multi-operation documents
Response:
{
"data": {
"allCustomer": [
{
"id": "Customer/C001",
"label": "Alice Smith",
"hasInteraction": [
{ "label": "Call 2024-01-15" }
]
}
]
}
}Returns the full GraphQL Schema Definition Language (SDL) for the domain.
Parameters:
project_name(path, required): Name of the domain in the registry
Response:
type Customer {
id: String!
label: String
hasInteraction: [Interaction]
}
type Interaction {
id: String!
label: String
date: String
}
type Query {
allCustomer(limit: Int = 50, offset: Int = 0, search: String): [Customer!]!
customer(id: String!): Customer
allInteraction(limit: Int = 50, offset: Int = 0, search: String): [Interaction!]!
interaction(id: String!): Interaction
}- Schema is auto-generated: The schema is built dynamically from the ontology. Each ontology class becomes a GraphQL type; data properties become
Stringfields; object properties become typed relationship fields. - Per-domain schemas: Different domains may have completely different schemas, reflecting their ontology.
- Caching: Schemas are cached per domain and invalidated on ontology changes.
- Relationship depth: Nested relationships are resolved to a configurable depth (default 2, max 5). The depth can be set via the
depthfield in the request body or the depth selector in the GraphiQL playground. - Triple store required: The domain must have a materialized triple store (synced via Knowledge Graph) for GraphQL queries to return data.
The Knowledge Graph API provides stateless, programmatic access to the graph viewer — triple store status, entity search, ontology artifacts, and build triggers. All endpoints accept an optional project_name query parameter to load a domain from the registry instead of the browser session.
http://localhost:8000/api/v1/digitaltwin
Returns the domain registry location (catalog, schema, volume).
List all domains that have at least one PUBLISHED version in the registry.
Response:
{
"success": true,
"domains": [
{
"name": "customer360",
"description": "Customer 360 ontology",
"graph_backend": "lakebase",
"has_graph": true,
"mcp_policy": {
"disabled_tools": ["query_graphql"],
"context": {"bridges": "preferred", "actions": "disabled"}
}
},
{
"name": "finance",
"description": "Contracts and payments",
"graph_backend": "none",
"has_graph": false,
"mcp_policy": {}
}
]
}mcp_policy is the domain's per-domain MCP policy,
authored in Domain → Information → MCP. Only non-default entries are
stored, so {} means "every tool exposed, every ontology attachment surfaced
normally" — the pre-0.8 behaviour. disabled_tools never contains a
registry-level tool, and a missing context key defaults to normal.
The MCP server reads this field to decide which tools to publish for the session; it is informational for other clients, since the disabling itself is also enforced server-side on the endpoints below.
graph_backend is the backend configured on the numeric-latest PUBLISHED
version: none, lakebase, databricks, or neo4j. has_graph reports
runtime availability, not configuration: it is true only after that version
has a successful graph build. Clients can therefore distinguish an
ontology-only domain (graph_backend: "none") from a graph-backed domain that
has not been built yet.
Lifecycle & API access. Each domain version has a lifecycle status —
DRAFT→IN-REVIEW→PUBLISHED. The external API and MCP only serve data for PUBLISHED versions; when no version is requested the numeric-latest PUBLISHED version is used. Requesting a non-PUBLISHED version explicitly (e.g.domain_version=2) returns an error. Multiple PUBLISHED versions may coexist.
Return per-class dataset, bridge, Unity Catalog action and virtual
attribute metadata for every class in the domain's published ontology, without
loading the full OWL. This is what the MCP server caches on select_domain to
build its [Context] blocks. Only non-empty values are included, and virtual
attributes are declarations only — their values come from
/nodes/context.
Parameters:
domain_name(query, optional): Domain name in the registry (session domain if omitted)domain_version(query, optional): Version to load (latest if omitted)registry_catalog/registry_schema/registry_volume(query, optional): Registry overrides
Response:
{
"success": true,
"domain_name": "customer360",
"classes": [
{
"name": "Customer",
"uri": "https://ontobricks.com/ontology#Customer",
"dataset": {"fullName": "main.crm.customers", "key_column": "customer_id"},
"bridges": [
{"target_domain": "finance", "target_class_name": "Contract",
"label": "Owns contracts",
"target_domain_description": "Contracts and payments"}
],
"actions": [
{"fullName": "main.crm.churn_score", "description": "Churn risk"}
],
"virtualAttributes": [
{"fullName": "main.kg.customer_risk", "function": "customer_risk",
"description": "Live credit risk", "returns_table": true,
"attributes": [
{"name": "risk_score", "column": "risk_score",
"label": "Risk score", "dataType": "DOUBLE"}
]}
]
}
]
}Policy filtering. Attachments set to Disabled in the domain's MCP policy are withheld here:
datasetcomes backnull,bridges,actionsandvirtualAttributescome back empty. Bridges are additionally filtered to targets that are themselves API/MCP-visible. The authoring UI does not go through this endpoint and always sees the full ontology.
Returns all versions for a domain in the registry, latest first. Each version is
annotated with its lifecycle status and an is_published flag (only PUBLISHED
versions are data-accessible via the API/MCP).
Parameters:
domain_name(query, required): Domain name in the registry
Returns a comprehensive readiness status including ontology, metadata, and mapping completeness.
Parameters:
domain_name(query, optional): Domain name in the registrydomain_version(query, optional): Specific PUBLISHED version to load (numeric-latest PUBLISHED if omitted)
Response:
{
"success": true,
"ontology": {
"ready": true,
"class_count": 10,
"property_count": 9,
"base_uri": "https://ontobricks.com/ontology#"
},
"metadata": {
"ready": true,
"table_count": 5
},
"assignment": {
"ready": true,
"entity_total": 10,
"entity_mapped": 10,
"relationship_total": 9,
"relationship_mapped": 9,
"progress_percent": 100
},
"build_ready": true
}Check backend type, table name, data availability, and triple count.
Parameters:
project_name(query, optional): Domain name in the registry
Return the domain's OWL ontology in Turtle format.
Parameters:
project_name(query, optional): Domain name in the registry
Return the domain's R2RML mapping document in Turtle format.
Parameters:
project_name(query, optional): Domain name in the registry
Return the Spark SQL that produces triples from the source tables.
Parameters:
project_name(query, optional): Domain name in the registry
Aggregated statistics: total triples, entity types, predicates, labels.
Parameters:
project_name(query, optional): Domain name in the registry
Trigger a triple store build (sync). Returns a task_id for progress polling.
BFS-based entity search with depth control.
Parameters:
project_name(query, optional): Domain name in the registrysearch(query): Search textentity_type(query, optional): Filter by typedepth(query, optional): BFS depth (default: 2)
Resolve the ontology class for an entity URI and return its external context: linked Unity Catalog dataset (optionally with rows), cross-domain bridges, the Unity Catalog function actions declared on the class, and its virtual attributes (optionally computed). No action is executed here.
Parameters:
entity_uri(query): Full URI of the entity nodedomain_name(query, optional): Domain name in the registryfetch_dataset_rows(query, optional): Fetch rows from the linked table/viewdataset_row_limit(query, optional): Max rows to return, 1–20 (default: 5)follow_bridges(query, optional): Traverse bridge target domainscompute_virtual_attributes(query, optional): Run the class's virtual attribute functions and return their values
Virtual attributes. Declarations always ride along, so a caller knows what
is available for the cost of the class lookup. Each function costs a warehouse
round-trip, so values only appears when compute_virtual_attributes=true —
the difference between not computed and computed as null is preserved by
omitting the key entirely. A group whose function fails carries an error and
leaves the others intact; only the first returned row is used, and a function
returning several sets message instead of aggregating.
"virtual_attributes": [
{"fullName": "main.kg.customer_risk", "function": "customer_risk",
"returns_table": true,
"attributes": [{"name": "risk_score", "column": "risk_score",
"label": "Risk score", "dataType": "DOUBLE"}],
"values": {"risk_score": 0.82}}
]Policy filtering. Each attachment set to Disabled in the domain's MCP policy is withheld from the response, and the work behind it is skipped: a disabled dataset is not queried even with
fetch_dataset_rows=true, disabled bridges are not traversed even withfollow_bridges=true, and disabled virtual attributes are neither listed nor computed even withcompute_virtual_attributes=true. The flags are simply ignored rather than raising.
Invoke one of the class's Unity Catalog function actions on a node. The function
receives exactly one argument: the entity's local ID, extracted from
entity_uri.
Body:
entity_uri: Instance URI of the node to act onaction_full_name: Fully qualified function name (catalog.schema.function)domain_name/domain_version(optional): Registry domain and version
Only functions declared in the resolved class's actions list may be invoked —
the ontology is the allow-list. Requests for any other function are rejected
with success: false and nothing is executed. Table-valued functions run as
SELECT * FROM fn('<id>'); scalar functions run as
SELECT fn('<id>') AS result.
Policy filtering. If the domain sets Actions to Disabled, every invocation is refused here, whatever the function name — a caller that learned a name before the attachment was disabled cannot keep using it. This is deliberately independent of whether the
invoke_entity_actionMCP tool is still published.
Compute the virtual attributes declared on an entity's ontology class by running
their bound Unity Catalog functions. Each function receives exactly one
argument: the entity's local ID, extracted from entity_uri.
Parameters:
entity_uri(query): Full URI of the entity nodefunction(query, optional): Fully qualified function name (catalog.schema.function). When omitted, every group declared on the class is computed.domain_name/domain_version(optional): Registry domain and version
Only functions declared in the resolved class's virtualAttributes list may be
invoked — the ontology is the allow-list. The response carries one group per
function, with values populated from the warehouse result. A group whose
function fails carries an error and leaves the others intact.
Policy filtering. If the domain sets Virtual attributes to Disabled, every computation is refused here, whatever the function name. This is deliberately independent of whether the
compute_virtual_attributesMCP tool is still published.
import requests
# Configuration
API_BASE = "http://localhost:8000/api/v1"
HEADERS = {
"Content-Type": "application/json",
"X-Databricks-Host": "https://your-workspace.cloud.databricks.com",
"X-Databricks-Token": "dapi..."
}
# List domains
response = requests.post(
f"{API_BASE}/domains/list",
headers=HEADERS,
json={
"catalog": "main",
"schema": "default",
"volume": "ontologies"
}
)
payload = response.json()
# Execute SPARQL query
response = requests.post(
f"{API_BASE}/query",
headers=HEADERS,
json={
"project_path": "/Volumes/main/default/ontologies/my_domain.json",
"query": "SELECT ?type (COUNT(?s) as ?count) WHERE { ?s a ?type } GROUP BY ?type",
"limit": 50
}
)
results = response.json()
print(results['data']['results'])# Health check
curl http://localhost:8000/api/v1/health
# List domains
curl -X POST http://localhost:8000/api/v1/domains/list \
-H "Content-Type: application/json" \
-H "X-Databricks-Host: https://your-workspace.cloud.databricks.com" \
-H "X-Databricks-Token: dapi..." \
-d '{"catalog": "main", "schema": "default", "volume": "ontologies"}'
# Execute query
curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-H "X-Databricks-Host: https://your-workspace.cloud.databricks.com" \
-H "X-Databricks-Token: dapi..." \
-d '{
"project_path": "/Volumes/main/default/ontologies/my_domain.json",
"query": "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"
}'| HTTP Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request - Missing or invalid parameters |
| 401 | Unauthorized - Invalid or missing credentials |
| 404 | Not Found - Domain or resource not found |
| 500 | Internal Server Error |
- Stateless: The API is stateless - each request loads the domain fresh from Unity Catalog.
- Engine: Currently, only the
localengine (RDFLib) is fully supported. Thesparkengine requires additional setup. - R2RML Required: SPARQL queries require the domain to have an R2RML mapping generated. Use the web interface to generate mappings first.
- Security: Never share your Databricks token. Consider using environment variables or secure credential management.
This document describes the REST API endpoints available in OntoBricks.
- Local Development:
http://localhost:8000 - Databricks Apps:
https://<workspace>.databricks.com/apps/<app-id>/
| Module | Base Path | Purpose |
|---|---|---|
| Domain API | /api/v1/domains, /api/v1/domain |
Registry list, versions, design status, OWL/R2RML/SQL artifacts |
| Knowledge Graph API | /api/v1/digitaltwin |
Stateless access to triple store, builds, triple search, quality, reasoning |
| Core/Navbar | / |
Session status, file browsing |
| Settings | /settings |
Databricks connection, settings |
| Scheduled Builds | /settings/schedules |
Automated triple store build scheduling |
| Ontology | /ontology |
Ontology design, OWL operations |
| SWRL Rules | /ontology/swrl |
SWRL rule management |
| Constraints | /ontology/constraints |
Property constraints |
| Axioms | /ontology/axioms |
OWL expressions & axioms |
| SHACL Data Quality | /ontology/dataquality |
SHACL shape CRUD, Turtle import/export |
| Mapping | /mapping |
Entity/relationship mapping, R2RML |
| SQL Wizard | /mapping/wizard |
LLM-assisted SQL generation for mappings |
| Knowledge Graph | /dtwin |
Sync, graph viewer, quality checks, internal query execution |
| Data Quality Execution | /dtwin/dataquality |
Run SHACL checks against triple store |
| Reasoning | /dtwin/reasoning |
OWL 2 RL + SWRL inference, inferred triples |
| GraphQL | /graphql (UI); /api/v1/graphql (external API mount) |
Auto-generated typed GraphQL schema from ontology |
| Domain | /domain |
Domain save/load operations (UI route) |
These endpoints provide shared functionality used across the application.
Get current session statistics for the home page dashboard.
GET /session-statusResponse:
{
"has_config": true,
"has_taxonomy": true,
"taxonomy_name": "MyOrganization",
"class_count": 3,
"has_mappings": true,
"entity_mappings": 3,
"relationship_mappings": 2,
"has_r2rml": true,
"has_rdf": false,
"triple_count": 0
}Get the current ontology load status (for navbar indicators).
GET /ontology-statusResponse:
{
"loaded": true,
"has_r2rml": true,
"has_taxonomy": true,
"name": "MyOrganization",
"taxonomy_classes": 3,
"taxonomy_properties": 5
}Clear all session data (ontology, mappings, R2RML).
POST /reset-sessionResponse:
{
"success": true,
"message": "Session reset successfully"
}List files in a Unity Catalog volume.
POST /browse-volumeRequest Body:
{
"catalog": "main",
"schema": "default",
"volume": "ontologies",
"path": ""
}Response:
{
"success": true,
"files": [
{
"name": "taxonomy.ttl",
"path": "/Volumes/main/default/ontologies/taxonomy.ttl",
"size": 2048,
"is_directory": false
}
],
"path": "/Volumes/main/default/ontologies"
}Read a file from a Unity Catalog volume.
POST /read-volume-fileRequest Body:
{
"file_path": "/Volumes/main/default/ontologies/taxonomy.ttl"
}Response:
{
"success": true,
"content": "@prefix owl: <http://www.w3.org/2002/07/owl#> ...",
"filename": "taxonomy.ttl",
"path": "/Volumes/main/default/ontologies/taxonomy.ttl"
}Shared Databricks configuration lives under /settings. Warehouse
selection and every Settings write remain admin-only (CAN_MANAGE).
Read-only discovery used by the domain Data Sources picker
(GET /settings/catalogs, GET /settings/schemas,
GET /settings/schemas/<catalog>) is available to any signed-in app user;
Editors and Builders then persist tables via /domain/metadata/*.
Viewers can list catalogs but cannot import or remove data sources.
GET /settings/currentResponse:
{
"host": "https://your-workspace.databricks.com",
"token": "********",
"warehouse_id": "abc123",
"catalog": "main",
"schema": "default",
"volume_path": "/Volumes/system/ontobricks/mappings",
"from_env": true,
"has_config": true
}POST /settings/test-connectionRequest Body:
{
"host": "https://your-workspace.databricks.com",
"token": "dapi...",
"warehouse_id": "abc123"
}Response:
{
"success": true,
"message": "Connection successful"
}GET /settings/warehousesResponse:
{
"warehouses": [
{"id": "abc123", "name": "Starter Warehouse"},
{"id": "def456", "name": "Production Warehouse"}
]
}GET /settings/catalogsResponse:
{
"catalogs": ["main", "samples", "system"]
}GET /settings/schemas/<catalog>Response:
{
"schemas": ["default", "information_schema"]
}GET /settings/volumes/<catalog>/<schema>Response:
{
"volumes": ["data", "ontologies", "mappings"]
}POST /settings/saveRequest Body:
{
"warehouse_id": "abc123",
"catalog": "main",
"schema": "default"
}GET /settings/get-default-emoji
POST /settings/set-default-emojiPersists default_emoji in the registry global_config document (admin write).
Admin-only. Title, primary color, and logo are stored as one ui_branding
object in the same registry global_config document.
GET /settings/ui-branding
POST /settings/ui-brandingGET response:
{
"success": true,
"branding": {
"app_title": "OntoBricks",
"primary_color": "#4F46E5",
"logo_url": "/static/global/img/favicon.svg",
"is_custom_logo": false,
"palette": {
"primary_rgb": "79, 70, 229",
"primary_dark": "#4338CA",
"on_primary": "#FFFFFF"
}
}
}POST is multipart/form-data with app_title, primary_color, optional
logo_file, and optional reset_logo=true. The three branding fields are
written atomically; validation failure writes nothing.
GET /settings/get-base-uri
POST /settings/save-base-uriGET /settings/get-registry-cache-ttl
POST /settings/save-registry-cache-ttlHow long (seconds, min 10) the registry domain list is cached before refreshing.
Admin only; stored globally. Save body: { "registry_cache_ttl": 300 }.
GET /settings/edit-lock-ttl
POST /settings/save-edit-lock-ttlThe DRAFT single-editor lock lease TTL in seconds (0 disables the lease →
hold-until-close). The GET returns the effective value (Settings › Global
override → ONTOBRICKS_EDIT_LOCK_TTL_S env → default 600). Save is admin-only
and stored globally. Save body: { "edit_lock_ttl_s": 600 }.
Response (GET):
{ "success": true, "edit_lock_ttl_s": 600 }GET /ontology/Returns the ontology designer HTML page.
POST /ontology/saveRequest Body:
{
"name": "MyOrganization",
"base_uri": "https://databricks-ontology.com/MyOrganization#",
"classes": [
{
"name": "Person",
"label": "Person",
"emoji": "👤",
"description": "Represents a person",
"dataProperties": [
{"name": "email", "type": "string"}
]
}
],
"properties": [
{
"name": "name",
"type": "DatatypeProperty",
"domain": "Person",
"range": "xsd:string"
},
{
"name": "worksIn",
"type": "ObjectProperty",
"domain": "Person",
"range": "Department",
"direction": "forward",
"properties": [
{"id": "attr1", "name": "startDate", "type": "date"}
]
}
]
}Response:
{
"success": true,
"message": "Ontology configuration saved to session"
}GET /ontology/loadResponse:
{
"success": true,
"config": {
"name": "MyOrganization",
"base_uri": "https://databricks-ontology.com/MyOrganization#",
"classes": [...],
"properties": [...]
}
}POST /ontology/generate-owlRequest Body:
{
"name": "MyOrganization",
"base_uri": "https://databricks-ontology.com/MyOrganization#",
"classes": [...],
"properties": [...]
}Response:
{
"success": true,
"owl": "@prefix owl: <http://www.w3.org/2002/07/owl#> ..."
}POST /ontology/parse-owlRequest Body:
{
"content": "@prefix owl: <http://www.w3.org/2002/07/owl#> ..."
}Response:
{
"success": true,
"message": "Parsed successfully: 3 classes, 5 properties",
"ontology": {
"info": {...},
"classes": [...],
"properties": [...]
},
"stats": {
"classes": 3,
"properties": 5
}
}POST /ontology/resetResponse:
{
"success": true,
"message": "Ontology reset successfully"
}GET /ontology/get-loaded-ontologyPOST /ontology/save-to-ucRequest Body:
{
"content": "@prefix owl: ...",
"path": "/Volumes/main/default/ontologies/taxonomy.ttl"
}SWRL (Semantic Web Rule Language) rules for automatic inference.
GET /ontology/swrl/listResponse:
{
"success": true,
"rules": [
{
"name": "InferGrandparent",
"description": "Infers grandparent relationship",
"antecedent": "Person(?x) ∧ hasParent(?x, ?y) ∧ hasParent(?y, ?z)",
"consequent": "hasGrandparent(?x, ?z)"
}
]
}POST /ontology/swrl/saveRequest Body:
{
"rule": {
"name": "InferGrandparent",
"description": "Infers grandparent relationship",
"antecedent": "Person(?x) ∧ hasParent(?x, ?y) ∧ hasParent(?y, ?z)",
"consequent": "hasGrandparent(?x, ?z)"
},
"index": -1
}Note: Set index to -1 for new rules, or the rule index to update existing.
POST /ontology/swrl/deleteRequest Body:
{
"index": 0
}POST /ontology/swrl/validateRequest Body:
{
"rule": {
"antecedent": "Person(?x) ∧ hasParent(?x, ?y)",
"consequent": "hasGrandparent(?x, ?z)"
}
}Response:
{
"success": false,
"valid": false,
"errors": ["Undefined variables in consequent: ?z"]
}Manage cardinality constraints, value restrictions, and property characteristics.
GET /ontology/constraints/listResponse:
{
"success": true,
"constraints": [
{
"type": "exactCardinality",
"className": "Employee",
"property": "hasManager",
"cardinalityValue": 1
},
{
"type": "functional",
"property": "hasBirthDate"
}
]
}POST /ontology/constraints/saveRequest Body:
{
"constraint": {
"type": "maxCardinality",
"className": "Person",
"property": "hasPhone",
"cardinalityValue": 3
},
"index": -1
}Constraint Types:
| Category | Types |
|---|---|
| Cardinality | minCardinality, maxCardinality, exactCardinality |
| Value Restrictions | allValuesFrom, someValuesFrom, hasValue |
| Property Characteristics | functional, inverseFunctional, transitive, symmetric, asymmetric, reflexive, irreflexive |
POST /ontology/constraints/deleteRequest Body:
{
"index": 0
}GET /ontology/constraints/get-by-property/<property_uri>GET /ontology/constraints/get-by-class/<class_uri>Manage SHACL shapes for data quality validation. Shapes define constraints (cardinality, datatype, pattern, custom SPARQL) that are checked against the triple store.
GET /ontology/dataquality/listQuery Parameters: category (optional) — filter by category (completeness, conformance, cardinality, structural, uniqueness)
Response:
{
"success": true,
"shapes": [
{
"id": "shape_1",
"name": "Customer.email must exist",
"target_class": "Customer",
"property": "email",
"constraint_type": "sh:minCount",
"constraint_value": "1",
"category": "completeness",
"severity": "Violation"
}
]
}POST /ontology/dataquality/saveRequest Body:
{
"shape": {
"id": "shape_1",
"name": "Customer.email must exist",
"target_class": "Customer",
"property": "email",
"constraint_type": "sh:minCount",
"constraint_value": "1",
"category": "completeness",
"severity": "Violation"
}
}POST /ontology/dataquality/deleteRequest Body:
{
"id": "shape_1"
}GET /ontology/dataquality/exportReturns all SHACL shapes as a Turtle (.ttl) file download.
POST /ontology/dataquality/importRequest Body:
{
"content": "@prefix sh: <http://www.w3.org/ns/shacl#> ..."
}POST /ontology/dataquality/migrateConverts legacy ontology constraints to SHACL shapes.
Manage OWL class expressions and axioms.
GET /ontology/axioms/listResponse:
{
"success": true,
"axioms": [
{
"type": "equivalentClass",
"subject": "Employee",
"objects": ["Person"],
"description": "Employee is equivalent to Person with a job"
},
{
"type": "disjointWith",
"subject": "Person",
"objects": ["Organization"]
},
{
"type": "propertyChain",
"subject": "hasGrandparent",
"chain": ["hasParent", "hasParent"]
}
]
}POST /ontology/axioms/saveRequest Body (Equivalent Class):
{
"axiom": {
"type": "equivalentClass",
"subject": "Employee",
"objects": ["Person"],
"description": "Employee equals Person with job"
},
"index": -1
}Request Body (Property Chain):
{
"axiom": {
"type": "propertyChain",
"subject": "hasGrandparent",
"chain": ["hasParent", "hasParent"]
},
"index": -1
}Request Body (OneOf Enumeration):
{
"axiom": {
"type": "oneOf",
"subject": "TrafficLight",
"individuals": "Red, Yellow, Green"
},
"index": -1
}Axiom Types:
| Category | Types |
|---|---|
| Class Relationships | equivalentClass, disjointWith, disjointUnion |
| Class Expressions | unionOf, intersectionOf, complementOf, oneOf |
| Property Relationships | equivalentProperty, inverseOf, propertyChain, disjointProperties |
POST /ontology/axioms/deleteRequest Body:
{
"index": 0
}GET /ontology/axioms/get-by-class/<class_uri>GET /ontology/axioms/get-by-type/<axiom_type>GET /mapping/Returns the mapping configuration HTML page.
POST /mapping/tablesRequest Body:
{
"catalog": "main",
"schema": "default"
}Response:
{
"tables": ["person", "department", "project"]
}POST /mapping/table-columnsRequest Body:
{
"catalog": "main",
"schema": "default",
"table": "person"
}Response:
{
"columns": [
{"name": "person_id", "type": "STRING"},
{"name": "name", "type": "STRING"},
{"name": "email", "type": "STRING"}
]
}POST /mapping/test-queryRequest Body:
{
"query": "SELECT person_id, dept_id FROM person_department"
}Response:
{
"success": true,
"columns": ["person_id", "dept_id"],
"rows": [
{"person_id": "P001", "dept_id": "D001"}
],
"row_count": 1
}POST /mapping/saveRequest Body:
{
"data_source_mappings": [
{
"ontology_class": "https://example.org/ontology#Person",
"ontology_class_label": "Person",
"sql_query": "SELECT person_id, name, email FROM main.default.person",
"id_column": "person_id",
"label_column": "name",
"attribute_mappings": {
"email": "email"
}
}
],
"relationship_mappings": [
{
"property": "https://example.org/ontology#worksIn",
"property_label": "worksIn",
"source_entity": "Person",
"target_entity": "Department",
"sql_query": "SELECT person_id, dept_id FROM person_department",
"source_column": "person_id",
"target_column": "dept_id",
"direction": "forward",
"attribute_mappings": {
"startDate": "start_date"
}
}
]
}GET /mapping/loadPOST /mapping/generateResponse:
{
"success": true,
"r2rml": "@prefix rr: <http://www.w3.org/ns/r2rml#> ...",
"stats": {
"entity_mappings": 3,
"relationship_mappings": 2
}
}POST /mapping/parse-r2rmlRequest Body:
{
"content": "@prefix rr: <http://www.w3.org/ns/r2rml#> ..."
}Response:
{
"success": true,
"message": "R2RML parsed successfully",
"entity_mappings": [...],
"relationship_mappings": [...],
"stats": {
"entity_count": 3,
"relationship_count": 2
}
}POST /mapping/resetGET /mapping/downloadReturns mapping.ttl file download.
POST /mapping/save-to-ucGET /dtwinReturns the Knowledge Graph HTML page (sync, quality, triples, graph viewer).
Used internally by the sync and graph viewer features to generate and execute SQL from the ontology mappings.
POST /dtwin/executeRequest Body:
{
"query": "PREFIX ont: <https://example.org/ontology#>\nSELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 100",
"engine": "sansa",
"limit": 100
}Response:
{
"success": true,
"columns": ["subject", "predicate", "object"],
"results": [
{
"subject": "https://example.org/Person/P001",
"predicate": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
"object": "https://example.org/ontology#Person"
},
{
"subject": "https://example.org/Person/P001",
"predicate": "http://www.w3.org/2000/01/rdf-schema#label",
"object": "John Doe"
},
{
"subject": "https://example.org/Person/P001",
"predicate": "https://example.org/ontology#worksIn",
"object": "https://example.org/Department/D001"
}
],
"count": 3,
"engine": "spark",
"generated_sql": "SELECT DISTINCT subject, predicate, object FROM (...) LIMIT 100",
"tables_queried": ["person", "department"]
}Engine Options:
sansa- Execute via Spark SQL on Databricks (translates SPARQL to SQL)local- Execute locally using RDFLib (for small datasets or testing)
Status gate.
POST /dtwin/sync/startandPOST /dtwin/sync/loadare blocked when the loaded domain version isIN-REVIEWorPUBLISHED. All read-only sync operations (filter, stats, status, etc.) remain accessible regardless of lifecycle status.
POST /dtwin/sync/startStart an async Knowledge Graph build (CREATE VIEW then populate the graph store).
Always performs a full rebuild. Returns a task_id for progress polling via
GET /tasks/{task_id}.
Response:
{
"success": true,
"task_id": "abc123",
"message": "Sync started"
}POST /dtwin/sync/loadLoad all triples from the graph database and return them as query results.
Request Body (optional):
{ "include_inferred": true }Response:
{
"success": true,
"results": [{"subject": "...", "predicate": "...", "object": "..."}],
"columns": ["subject", "predicate", "object"],
"count": 1500
}POST /dtwin/sync/filterTwo-phase endpoint used by the Graph Explorer. Accessible on any lifecycle status.
Phase "preview" (default) — seed search, returns a flat list of matching
entities with their type and label so the user can pick which ones to explore.
Phase "expand" — accepts selected_uris and runs depth BFS + triple fetch.
Request Body:
{
"phase": "preview",
"entity_type": "Person",
"field": "any",
"match_type": "contains",
"value": "John",
"include_inferred": true
}Response (preview):
{
"success": true,
"entities": [
{"uri": "https://example.org/Person/P001", "type": "Person", "label": "John Doe"}
]
}GET /dtwin/sync/statusResponse:
{
"success": true,
"has_data": true,
"count": 1500,
"last_modified": "2026-02-15 14:32:10"
}The last_modified field is retrieved from the Unity Catalog Delta table metadata (DESCRIBE DETAIL) and indicates the last time the triple store table was updated.
Use the domain's configured LLM serving endpoint to suggest emoji icons for entity names.
POST /dtwin/auto-assign-iconsRequest Body:
{
"entity_names": ["Customer", "Order", "Product", "Invoice"]
}Response:
{
"success": true,
"icons": {
"Customer": "🧑",
"Order": "📋",
"Product": "📦",
"Invoice": "🧾"
}
}Note: Requires a valid LLM serving endpoint configured in Domain Settings (
llm_endpoint).
Execute SHACL data quality checks against the triple store (Delta view or the active Graph DB engine — Lakebase Postgres).
POST /dtwin/dataquality/executeRequest Body:
{
"backend": "delta",
"table_name": "catalog.schema.triples"
}Response:
{
"success": true,
"results": [
{
"shape_name": "Customer.email must exist",
"category": "completeness",
"severity": "Violation",
"total_entities": 150,
"violations": 3,
"pass_rate": 98.0,
"details": "3 violations found — 98.0% pass on 150 entities"
}
],
"summary": {
"total_checks": 12,
"passed": 10,
"failed": 2
}
}Backend Options:
delta— Execute checks as Spark SQL against the Delta triple store viewgraph— Execute checks via the configured Graph DB engine (currently Lakebase Postgres)
POST /dtwin/dataquality/startReturns a task_id for progress polling via GET /tasks/{task_id}/status.
Run OWL 2 RL inference and SWRL rule execution against the triple store.
POST /dtwin/reasoning/startRequest Body:
{
"phases": ["tbox", "swrl", "structural"],
"materialize": true,
"target_table": "catalog.schema.triples_inferred"
}Returns a task_id. Reasoning runs OWL 2 RL T-Box closure, SWRL rules, and optional structural reasoning (transitivity, symmetry).
GET /dtwin/reasoning/inferredResponse:
{
"success": true,
"inferred_count": 42,
"triples": [
{
"subject": "https://example.org/Person/P001",
"predicate": "https://example.org/ontology#hasGrandparent",
"object": "https://example.org/Person/P003",
"rule": "InferGrandparent",
"phase": "swrl"
}
]
}OntoBricks auto-generates a typed GraphQL schema from the ontology. Each class becomes a GraphQL type, data properties become scalar fields, and object properties become typed relationship fields.
GET /graphqlReturns all domains in the configured registry that have a materialized triple store and can be queried via GraphQL.
Response:
{
"success": true,
"domains": [
{
"name": "my_domain",
"description": ""
}
],
"message": null
}GET /graphql/{project_name}Opens the interactive GraphiQL IDE for the domain. Provides auto-complete, documentation explorer, and query history.
GET /graphql/settings/depthResponse:
{
"default": 2,
"max": 5
}POST /graphql/{project_name}Request Body:
{
"query": "{ allCustomer(limit: 5) { id label hasInteraction { label } } }",
"variables": {},
"operationName": null,
"depth": 2
}Response:
{
"data": {
"allCustomer": [
{
"id": "Customer/C001",
"label": "Alice Smith",
"hasInteraction": [
{ "label": "Call 2024-01-15" }
]
}
]
}
}GET /graphql/{project_name}/schemaReturns the full GraphQL Schema Definition Language (SDL) for the domain.
Response (text/plain):
type Customer {
id: String!
label: String
hasInteraction: [Interaction]
}
type Query {
allCustomer(limit: Int = 50, offset: Int = 0, search: String): [Customer!]!
customer(id: String!): Customer
}Note: The GraphQL schema is auto-generated at runtime from the domain's ontology. Each domain has its own schema, cached and invalidated on ontology changes.
Domain routes (/api/v1/domains, /api/v1/domain/...) and Knowledge Graph routes (/api/v1/digitaltwin/...). Most accept an optional project_name (and often project_version) to load a domain from the registry instead of the browser session.
Knowledge Graph base URL: http://localhost:8000/api/v1/digitaltwin
GET /api/v1/digitaltwin/registryReturns the domain registry location (catalog, schema, volume).
GET /api/v1/domainsList all domains that have at least one PUBLISHED version in the registry. The
API/MCP serves the numeric-latest PUBLISHED version (see the lifecycle note
above). Each entry carries the domain's mcp_policy, configured
graph_backend (none, lakebase, databricks, or neo4j), and has_graph
availability flag.
GET /api/v1/domain/classesQuery Parameters: domain_name, domain_version (both optional)
Per-class dataset, bridge and UC action metadata, filtered by the domain's MCP context policy.
GET /api/v1/domain/versionsQuery Parameters: domain_name (required)
Returns all versions for the domain, latest first.
GET /api/v1/domain/design-statusQuery Parameters: domain_name (optional), domain_version (optional)
Returns a comprehensive readiness status including ontology, metadata, and mapping completeness.
Response:
{
"success": true,
"ontology": {
"ready": true,
"class_count": 10,
"property_count": 9,
"base_uri": "https://ontobricks.com/ontology#"
},
"metadata": {
"ready": true,
"table_count": 5
},
"assignment": {
"ready": true,
"entity_total": 10,
"entity_mapped": 10,
"relationship_total": 9,
"relationship_mapped": 9,
"progress_percent": 100
},
"build_ready": true
}GET /api/v1/digitaltwin/statusQuery Parameters: project_name (optional)
Check backend type, table name, data availability, and triple count.
GET /api/v1/domain/ontologyQuery Parameters: project_name (optional)
Return the domain's OWL ontology in Turtle format.
GET /api/v1/domain/r2rmlQuery Parameters: project_name (optional)
Return the domain's R2RML mapping document in Turtle format.
GET /api/v1/domain/sparksqlQuery Parameters: project_name (optional)
Return the Spark SQL that produces triples from the source tables.
GET /api/v1/digitaltwin/statsQuery Parameters: project_name (optional)
Aggregated statistics: total triples, entity types, predicates, labels.
POST /api/v1/digitaltwin/buildTrigger a triple store build (sync). Returns a task_id for progress polling.
GET /api/v1/digitaltwin/triples/findQuery Parameters:
project_name(optional): Domain name in the registrysearch(required): Search textentity_type(optional): Filter by typedepth(optional): BFS depth (default: 2)
BFS-based entity search with depth control.
Manage scheduled triple store builds (requires APScheduler).
GET /settings/schedulesPOST /settings/schedulesRequest Body:
{
"project_name": "my_domain",
"cron": "0 2 * * *",
"enabled": true
}DELETE /settings/schedules/{schedule_id}Read the registry's build-run trace (build_runs) and analytics-run history
(graph_analytics_runs). All four are admin-only, like every other
/settings path. The first two back Settings → Automation → Runs; the last
two are per-domain readers kept for programmatic use.
GET /settings/runs/build?domain=&limit=25&offset=0Newest-first, spanning every domain unless domain is given (an empty value
means every domain). limit is 1–200; offset is ≥ 0.
Response:
{
"success": true,
"domain": null,
"runs": [{"id": 41, "domain": "hr", "version": "2", "status": "success", "triple_count": 18240, "started_at": "2026-08-04T07:12:03"}],
"total": 137,
"limit": 25,
"offset": 0
}total is the full match count, not the page length — page through with
offset until offset + len(runs) == total. Every row carries the domain it
belongs to.
GET /settings/runs/analytics?domain=&limit=25&offset=0Same contract and same response envelope as above, over analytics runs
(status, class_filter, node_count, edge_count,
connected_components, avg_degree, density, duration_ms,
computed_at). Spans every version of every domain.
GET /settings/build-runs/{domain_name}?version=&limit=100Newest-first, optionally scoped to one version. Not paginated (limit is
1–1000).
GET /settings/build-analytics/{domain_name}?version=Aggregates over that domain's build runs: totals, success rate, duration min/avg/max, the latest triple count, the currently active build (the most recent successful run) and a per-version breakdown.
LLM-assisted SQL generation for mapping queries.
GET /mapping/wizard/schema-contextReturns table/column metadata for LLM context.
POST /mapping/wizard/generate-sqlRequest Body:
{
"entity_name": "Customer",
"attributes": ["email", "name", "phone"],
"schema_context": {...}
}Response:
{
"success": true,
"sql": "SELECT customer_id, email, name, phone FROM main.default.customers",
"explanation": "Maps Customer entity to the customers table..."
}POST /mapping/wizard/validate-sqlRequest Body:
{
"sql": "SELECT customer_id FROM main.default.customers"
}{
"name": "Person",
"localName": "Person",
"label": "Person",
"emoji": "👤",
"description": "Represents a person in the organization",
"dataProperties": [
{"name": "email", "type": "string"},
{"name": "salary", "type": "decimal"}
]
}{
"name": "worksIn",
"localName": "worksIn",
"type": "ObjectProperty",
"domain": "Person",
"range": "Department",
"direction": "forward",
"properties": [
{"id": "attr1", "name": "startDate", "type": "date"},
{"id": "attr2", "name": "role", "type": "string"}
]
}| Value | Description |
|---|---|
forward |
Relationship goes from domain to range (→) |
reverse |
Relationship goes from range to domain (←) |
bidirectional |
Relationship goes both ways (↔) |
All endpoints return errors in a consistent format:
{
"success": false,
"message": "Error description",
"error": "Detailed error (optional)"
}HTTP Status Codes:
| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request (missing/invalid parameters) |
| 401 | Unauthorized (invalid token) |
| 404 | Resource not found |
| 500 | Internal server error |
OntoBricks uses Databricks authentication for all data operations:
- Credentials loaded from environment variables (
.env) - Stored in session during use
- Never persisted to disk in plain text
Required Environment Variables:
DATABRICKS_HOST: Workspace URL (withhttps://)DATABRICKS_TOKEN: Personal access token or service principal tokenDATABRICKS_SQL_WAREHOUSE_ID: SQL Warehouse identifier
OntoBricks does not implement rate limiting directly. Limits are determined by:
- Databricks API rate limits
- SQL Warehouse query concurrency
Best Practices:
- Use
LIMITclauses in queries - Avoid very large result sets
- Monitor SQL Warehouse utilization
HTML routes are thin; they call domain objects under back/objects/* and core libraries under back/core/* directly. A few modules (home, settings) retain a thin service module under back/services/ for page-level helpers.
| Route module | Primary domain/core | Purpose |
|---|---|---|
front/routes/home.py, api/routers/internal/home.py |
back/services/home.py, back/objects/session/DomainSession.py |
Home / session overview |
front/routes/home.py (settings page served from home), api/routers/internal/settings.py |
back/services/settings.py, shared/config/settings.py, shared/config/constants.py |
Settings & environment UI |
front/routes/ontology.py, api/routers/internal/ontology.py |
back/objects/ontology/ontology.py, back/core/w3c/* |
Ontology design & import |
front/routes/mapping.py, api/routers/internal/mapping.py |
back/objects/mapping/mapping.py, back/core/w3c/r2rml/* |
Table mapping & R2RML |
front/routes/dtwin.py, api/routers/internal/dtwin.py |
back/objects/digitaltwin/digitaltwin.py, back/core/w3c/sparql/SparqlTranslator.py |
Knowledge Graph, SPARQL, query UI |
front/routes/domain.py, api/routers/internal/domain.py |
back/objects/domain/Domain.py, back/objects/session/DomainSession.py |
Domain save/load & registry UX |
api/routers/internal/tasks.py |
(handlers in routes; registry scheduler via back/objects/registry) |
Task status / triggers |
api/routers/v1.py, api/routers/domains.py, api/routers/digitaltwin.py |
api/service.py |
External stateless REST |
back/fastapi/graphql_routes.py |
back/core/graphql/GraphQLSchemaBuilder.py, back/core/graphql/ResolverFactory.py |
GraphQL (also mounted under /api/v1/graphql) |
This separation ensures:
- Routes are thin HTTP handlers only
- Business logic lives in domain objects (
back/objects/) and is testable and reusable - Clear separation of concerns
- Simplified session management with single-key pattern per module
Session state lives on request.state.session (see back/objects/session). The ontology and mapping HTML routes read and write structured payloads (often keyed as ontology_config / mapping data) via SessionManager and the domain classes:
back/objects/ontology/ontology.py—Ontologyclass for the ontology UI.back/objects/mapping/mapping.py—Mappingclass for mapping UI and session merge helpers.
Prefer inspecting those domain modules and the corresponding front/routes/ and api/routers/internal/ modules for the exact keys and JSON shapes; they are the supported extension points for new UI flows.