Skip to main content

Set up data-platform resources

A data platform is made of a handful of resource types: catalogs (with their schemas, tables, and columns), data products, connectors, and the collaboration boundaries (workspaces and clean rooms) which have their own guide, Use workspaces and clean rooms. This guide sets up the rest, in the order you would build them.

Every operation here runs against the node service's admin surface under /api/public/v1/admin/…, which requires an authenticated administrator session (the web console drives the same endpoints). Where a control-CLI command exists it is shown as s9-admin, the cell/node CLI, distinct from the s9 Edge Agent binary.

What has a CLI, and what is API-first

s9-admin covers workspaces (create and members) fully. Catalogs, data products, and connectors are API-first, create them through the console or the admin API; there is no s9-admin create command for them today. The examples below show the API call; substitute your console's equivalent form.

The resources and how they relate​

Figure: the resource graph. A connector (neutral) brings data into a catalog; a catalog nests schemas, then assets (tables), then columns (green); a table is published as a governed data product (filled). Ceiling: each box is a real create operation on the admin surface; a data product create is deny-closed on governance (see below).

Table equivalent

ResourceCreate operationRequired inputsCLI
CatalogPOST /api/public/v1/admin/catalog/catalogsnameAPI-first
SchemaPOST /catalog/catalogs/{catalog}/schemasnameAPI-first
Asset (table)POST /catalog/catalogs/{catalog}/schemas/{schema}/assetsname (+ table_type)API-first
ColumnPOST …/assets/{asset}/columnsname, data_typeAPI-first
Data productPOST /api/public/v1/admin/data-productsschema_id, name, version, domain, owner_entity_id, team_id, governanceAPI-first
ConnectorPOST /api/public/v1/admin/connectorsconnector_type, endpointAPI-first

Step 1: Create a catalog and its structure​

Build the catalog top-down: catalog → schema (namespace) → asset (table) → columns.

# Catalog: name is required and unique within the cell
curl -X POST https://CELL_HOST:8443/api/public/v1/admin/catalog/catalogs \
-H "Content-Type: application/json" \
-d '{"name":"analytics","display_name":"Analytics","description":"Reporting catalog"}'

# Schema (namespace) under it
curl -X POST https://CELL_HOST:8443/api/public/v1/admin/catalog/catalogs/analytics/schemas \
-d '{"name":"sales"}'

# Asset (table), table_type is one of managed | external | view | mview | streaming | feature
curl -X POST https://CELL_HOST:8443/api/public/v1/admin/catalog/catalogs/analytics/schemas/sales/assets \
-d '{"name":"orders","table_type":"managed"}'

# Column, name and data_type are required
curl -X POST https://CELL_HOST:8443/api/public/v1/admin/catalog/catalogs/analytics/schemas/sales/assets/orders/columns \
-d '{"name":"order_id","data_type":"string"}'

A workspace-scoped catalog also exists (POST /catalogs under a workspace, with a scope of private, persona, or shared) for catalogs that belong to a single workspace rather than the cell. Use it when the catalog should travel with a workspace.

To inspect what exists, the read side does have a CLI:

s9-admin catalog search ...
s9-admin catalog schemas list
s9-admin catalog tables list
s9-admin catalog lineage ...

Step 2: Register a connector​

A connector brings external data in. Registration takes a connector_type (one of the built-in types) and an endpoint:

curl -X POST https://CELL_HOST:8443/api/public/v1/admin/connectors \
-H "Content-Type: application/json" \
-d '{
"connector_type":"webhook",
"endpoint":"https://source.example/events",
"poll_interval_sec":60,
"credential_id":"cred-abc",
"start_immediately":false
}'

List the available types before you register, and manage the instance afterward:

# What types are available on this cell
curl https://CELL_HOST:8443/api/public/v1/admin/connectors/types

# Start / stop / health for an instance
curl -X POST https://CELL_HOST:8443/api/public/v1/admin/connectors/{id}/start
curl https://CELL_HOST:8443/api/public/v1/admin/connectors/{id}/health
Secrets are by reference only: inline credentials are refused

A connector create with an inline secret (in the endpoint, metadata, or a nested auth block) is hard-rejected. Pass a credential_id that references a stored secret instead. This is enforced, not advisory.

The built-in connector set is broad, cloud messaging (AWS/GCP queues and pub/sub), SIEM and security sources, industrial/OT protocols, tactical/defense formats, finance and healthcare standards, and generic webhook / websocket / sse. Do not quote a fixed connector count or name a specific connector as "supported" to a customer without a dated test, a registered type is a capability the platform ships, not a validated end-to-end integration. Query /connectors/types for the live set on your build.

Step 3: Publish a data product​

A data product turns a table into a governed, owned, contract-bearing asset. Creation requires the identifying fields and a governance disposition:

curl -X POST https://CELL_HOST:8443/api/public/v1/admin/data-products \
-H "Content-Type: application/json" \
-d '{
"schema_id":"analytics.sales",
"name":"orders_daily",
"version":"1.0.0",
"domain":"sales",
"owner_entity_id":"entity:acme",
"team_id":"team:analytics",
"sharing_policy":"restricted",
"governance":{"classification":"INTERNAL"}
}'
Data-product creation is deny-closed on governance

A create is rejected unless it supplies either a classification or an explicit share_unrestricted. There is no ungoverned data product, the platform refuses to mint one. Then move it through its lifecycle:

curl -X POST .../data-products/{id}/publish
curl -X POST .../data-products/{id}/certify

A joint result computed in a clean room can be published directly as a data product via POST /data-products/from-clean-room. See Use workspaces and clean rooms.

Step 4: Offer it on the Data Exchange (optional)​

To share a data product across organizations, the Data Exchange runs a governed access-request → approve/deny → grant/revoke handshake:

curl -X POST https://CELL_HOST:8443/api/public/v1/admin/exchange/access-requests -d '{...}'

See the Data Exchange hub for the marketplace, signed listings, offline verification, and settlement.

Verify it worked​

#CheckHow
1The catalog is boundIt appears in the workspace's bindings with the privilege you set, read or read-write
2The resource exists where you expectScoped to the workspace, not to the node
3Policy appliesA query as a less-privileged principal returns fewer rows or masked columns, not an error
4Lineage capturedThe write shows up on the asset's lineage rather than having to be reconstructed
5The product is discoverableIt appears to the audience its sharing tier allows, and no wider

Step 3 is the one people skip. Confirming that policy applies matters more than confirming that it was configured.

When it does not work​

SymptomMost likely causeWhat to do
A quota refuses the createThe workspace is at its ceilingOver quota raises a provisioning request rather than over-allocating. Approve it or raise the quota
A catalog is not visibleIt is not bound into this workspaceBinding is explicit and symmetric, never inherited by proximity
A product publishes narrower than expectedThe sharing tier is cappedEach tier above private maps to its own capability, and a locked tier shows its reason
A table is missing from a listingEnumeration is need-to-know filteredThis is the surface refusing to advertise something you could not query, not a fault
A clean-room asset shows an unfamiliar nameAssets are aliasedCollaborators see the alias, never the source. That is the contract

Across the deployment matrix​

  • Single-cell: every resource is created and enforced on the one cell.
  • Multi-cell: a catalog can span cells through federation; a data product's governance travels with it as it replicates.
  • Sovereign / air-gapped: creation is a local admin operation with no vendor control plane in the path; catalog objects can also be admitted by couriered signed bundle.
  • Cloud-enabled: the same admin surface, reachable from cloud-hosted operators.