> ## Documentation Index
> Fetch the complete documentation index at: https://deepline.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Customer Data Access

> How to connect, read, and build app features on your workspace customer data. Use it when you need exact IDs, inputs, and API calls.

This guide is for building product features on your workspace data quickly. It
covers two access paths:

* `query_customer_db`, the agent-callable tool for bounded SQL reads and
  `storage`-scoped writes.
* Direct PostgreSQL connection URIs for apps, BI tools, and admin workflows.

Start with the tool path when an agent is working inside Deepline. Use direct
connection URIs when your own application needs a Postgres connection string.

## What You Get

* One dedicated database per workspace.
* Ready-to-query views for people and companies.
* An agent-writable `storage` schema for `query_customer_db`.
* Direct connection roles for application and reporting access.

## Agent Tool: `query_customer_db`

Use `query_customer_db` when Claude, Codex, or another agent needs to inspect
workspace data through Deepline APIs.

```bash theme={null}
deepline tools execute query_customer_db --payload '{
  "sql": "SELECT domain, company_name FROM enrichments.companies ORDER BY updated_at DESC LIMIT 20"
}'
```

`query_customer_db` runs one SQL statement at a time. It supports:

* `SELECT`, `EXPLAIN`, and read-only `WITH` queries.
* Aggregate queries such as `SELECT count(*) ...`.
* `INSERT`, `UPDATE`, `DELETE`, `CREATE TABLE`, `CREATE INDEX`,
  `ALTER TABLE`, `DROP TABLE`, and `TRUNCATE` only for schema-qualified
  `storage.<table>` targets.

The `storage` schema is the safe write path for agent-created tables and
scratch state:

```bash theme={null}
deepline tools execute query_customer_db --payload '{
  "sql": "CREATE TABLE IF NOT EXISTS storage.agent_notes (id text PRIMARY KEY, note text NOT NULL, created_at timestamptz NOT NULL DEFAULT now())"
}'
```

Then query or update that table through the same tool:

```bash theme={null}
deepline tools execute query_customer_db --payload '{
  "sql": "INSERT INTO storage.agent_notes (id, note) VALUES ('\''run-123'\'', '\''ready for review'\'') ON CONFLICT (id) DO UPDATE SET note = EXCLUDED.note"
}'
```

```bash theme={null}
deepline tools execute query_customer_db --payload '{
  "sql": "SELECT id, note, created_at FROM storage.agent_notes ORDER BY created_at DESC LIMIT 20"
}'
```

Do not use `query_customer_db` for arbitrary DDL or migrations. These examples
are blocked:

```sql theme={null}
CREATE TABLE agent_notes (...);
CREATE TABLE tenant_custom.agent_notes (...);
DELETE FROM enrichments.companies WHERE domain = 'example.com';
```

If you see `Only read statements or schema-qualified storage tables are
supported.` or `Customer DB writes are only allowed for schema-qualified storage
tables.`, rewrite the statement to target `storage.<table>` exactly, or make the
query read-only.

## Quick Start: Get Access in Minutes

Use this flow when you need a direct PostgreSQL connection string.

### 1) Check workspace database status

Use:

```bash theme={null}
GET /api/v2/ingestion/status
```

### 2) Provision if needed

If not provisioned, run:

```bash theme={null}
POST /api/v2/ingestion/provision
```

You are ready when `provisioned` is `true` and plane status is `active`.

### 3) Reveal a connection URI

Use:

```bash theme={null}
POST /api/v2/ingestion/connection-uris/reveal
{
  "kind": "customer_db",
  "pooled": true
}
```

The revealed customer DB URI uses the workspace-scoped customer database role.
It can read permitted workspace schemas and can write to the `storage` schema.
Use the same `storage.<table>` convention for app-created tables unless you are
working through a separate admin/runtime migration path.

### 4) Connect from your app

```ts theme={null}
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.

### Store app-specific objects through the agent tool

Create agent-owned tables in `storage`:

```sql theme={null}
CREATE TABLE IF NOT EXISTS storage.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 a pooled URI for `customer_db` (dashboard/admin session).
* `POST /api/v2/ingestion/connection-uris/rotate`
  * Rotate the customer DB role password (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`

### Agent storage schema

* `storage`
  * DDL and DML allowed for `query_customer_db` and the customer DB role.
  * Always schema-qualify writes as `storage.<table>`.

## Deep Reference: Role Access

* Customer DB role
  * Read access to permitted workspace schemas.
  * DDL and DML on `storage.*`.
* Runtime role
  * 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.
* `query_customer_db` accepts a single SQL statement. Do not prepend
  `SET search_path`; schema-qualify table names instead.
