Skip to main content

Customer Data Access

This guide is for building product features on your workspace data quickly. Start with the access flow, then use the schema reference further down when you need implementation detail.

What You Get

  • One dedicated database per workspace.
  • Ready-to-query views for people and companies.
  • Safe write path for customer overrides.
  • A custom schema (tenant_custom) for your app-specific tables.

Quick Start: Get Access in Minutes

1) Check workspace database status

Use:
GET /api/v2/ingestion/status

2) Provision if needed

If not provisioned, run:
POST /api/v2/ingestion/provision
You are ready when provisioned is true and plane status is active.

3) Reveal a connection URI

Use:
POST /api/v2/ingestion/connection-uris/reveal
{
  "kind": "read",
  "pooled": true
}
Use kind: "runtime" when your app needs write access or to create custom tables.

4) Connect from your app

import { Client } from 'pg'

const client = new Client({ connectionString: process.env.DB_URI })
await client.connect()

const { rows } = await client.query(
  'SELECT identity_key, display_name FROM dl_resolved.people ORDER BY updated_at DESC LIMIT 20'
)

Build Features Fast (Vibe-Coding Patterns)

Read customer records for app screens

Use:
  • dl_resolved.people
  • dl_resolved.companies
These views already merge base records and customer overrides.

Let users correct data in your app

Write to:
  • dl_override.person_overrides
  • dl_override.company_overrides
Pattern:
INSERT INTO dl_override.person_overrides (
  identity_key,
  status,
  identity_payload_patch,
  raw_payload_patch,
  tombstoned,
  updated_at
) VALUES (
  $1, $2, $3::jsonb, $4::jsonb, false, now()
)
ON CONFLICT (identity_key) DO UPDATE
SET status = EXCLUDED.status,
    identity_payload_patch = EXCLUDED.identity_payload_patch,
    raw_payload_patch = EXCLUDED.raw_payload_patch,
    tombstoned = false,
    updated_at = now();

Store app-specific objects

Create your own tables in tenant_custom:
CREATE TABLE IF NOT EXISTS tenant_custom.account_segments (
  id text PRIMARY KEY,
  segment text NOT NULL,
  created_at timestamptz NOT NULL DEFAULT now()
);

API Endpoints You Will Use

  • GET /api/v2/ingestion/status
    • Check whether your workspace database is provisioned and active (API key or session auth).
  • POST /api/v2/ingestion/provision
    • Create database resources for the current workspace (dashboard/admin session).
  • GET /api/v2/ingestion/connection-uris/metadata
    • Return project/database/role metadata for active workspaces (dashboard/admin session).
  • POST /api/v2/ingestion/connection-uris/reveal
    • Reveal pooled URI for read or runtime (dashboard/admin session).
  • POST /api/v2/ingestion/connection-uris/rotate
    • Rotate password for read or runtime (dashboard/admin session).

Deep Reference: Schema Contract

Managed schemas (platform-owned)

  • dl_cache
    • person_enrichments
    • company_enrichments
  • dl_override
    • person_overrides
    • company_overrides
  • dl_resolved
    • people (view)
    • companies (view)
  • dl_meta
    • schema_migrations
    • tenant_settings

Customer schema (you own this)

  • tenant_custom
    • Full DDL + DML allowed for override role.

Deep Reference: Role Access

  • dl_tenant_read
    • SELECT on dl_resolved.*
  • dl_tenant_override
    • SELECT on dl_resolved.*
    • SELECT/INSERT/UPDATE/DELETE on dl_override.*
    • Full DDL + DML on tenant_custom.*
  • dl_platform_runtime
    • Internal app/runtime operations across managed schemas

Operational Notes

  • Database access is workspace-scoped, not user-scoped.
  • If the backing project was deleted manually, run POST /api/v2/ingestion/provision again.
  • Branch lifecycle is platform-managed for this tenant model.