LeveredDocs
API Reference

Warehouse

Endpoints for managing your data warehouse connection.

All endpoints are under /api/v2/warehouse. All requests require an Authorization: Bearer <token> header.

Create or update connection

POST /api/v2/warehouse/connections

Auth: Required

Creates or updates the warehouse connection for your organization. Each organization has a single active connection.

Request body:

{
  "provider": "bigquery",
  "project_id": "my-gcp-project",
  "dataset_id": "levered",
  "credentials": {
    "type": "service_account",
    "project_id": "my-gcp-project",
    "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
    "client_email": "levered@my-gcp-project.iam.gserviceaccount.com"
  }
}
FieldTypeRequiredDescription
providerstringYesWarehouse provider: bigquery, snowflake, or postgres
project_idstringVariesGCP project ID (BigQuery) or account identifier (Snowflake)
dataset_idstringVariesDefault dataset or schema
credentialsobjectYesProvider-specific credentials
exposure_columnsobjectNoWhich columns of the exposures table hold the SDK id, the exposure time and the variant: {"anonymous_id": "...", "timestamp": "...", "variant": "..."}. Defaults to anonymous_id, timestamp_utc, variant for a new connection; an update without it keeps the current setting. See Set exposure columns.

Provider-specific credential fields:

BigQuery: Service account JSON key (type, project_id, private_key, client_email).

Snowflake: account, username, password, warehouse, database, schema.

Postgres: host, port, database, username, password.

Response (201):

{
  "id": "connection-uuid",
  "provider": "bigquery",
  "project_id": "my-gcp-project",
  "dataset_id": "levered",
  "meta": {
    "request_id": "req_abc123",
    "organization_id": "org_xyz"
  }
}

Get connection

GET /api/v2/warehouse/connections

Auth: Required

Returns the current warehouse connection. Credentials are not included in the response.

Response:

{
  "connection": {
    "id": "connection-uuid",
    "provider": "bigquery",
    "project_id": "my-gcp-project",
    "dataset_id": "levered",
    "exposures_table": "exposures",
    "rewards_table": "rewards",
    "exposure_columns": {
      "anonymous_id": "anonymous_id",
      "timestamp": "timestamp_utc",
      "variant": "variant"
    },
    "managed": false,
    "created_at": "2026-03-28T14:00:00Z"
  },
  "meta": {
    "request_id": "req_abc123",
    "organization_id": "org_xyz"
  }
}

If no connection is configured, connection is null.

Set exposure columns

PATCH /api/v2/warehouse/connections/exposure-columns

Auth: Required

Sets which columns of your exposures table hold the id your app passes to the SDK, the exposure time and the variant. Optimizations created afterwards read their exposures with these columns. Existing optimizations keep their exposure source.

Request body:

{
  "anonymous_id": "USER_ID",
  "timestamp": "TIMESTAMP",
  "variant": "VARIANT"
}

All three are required, each a plain column name (letters, digits and _).

Response:

{
  "exposure_columns": {
    "anonymous_id": "USER_ID",
    "timestamp": "TIMESTAMP",
    "variant": "VARIANT"
  },
  "meta": { "request_id": "req_abc123", "organization_id": "org_xyz" }
}

Verify managed test events

GET /api/v2/warehouse/verify?optimization_id=<id>&anonymous_id=<test-user-id>

Auth: Required. Managed Warehouse only; a connected customer warehouse returns 409.

Read-only confirmation that raw exposure and reward events exist for the supplied visitor. The server scopes the exposure to the caller's organization and optimization; rewards are scoped to that organization and either the same optimization or an untagged reward. Use a fresh test visitor for each run: this endpoint has no timestamp or reward-goal filter. It reads raw events, including test rewards excluded from the training metric, and does not run aggregate identity verification.

{
  "exposure": true,
  "reward": true,
  "meta": { "request_id": "req_abc123", "organization_id": "org_xyz" }
}

Both booleans must be true for arrival. The response has no ok field. Query failures return an error, not a successful arrival result. levered verify --anonymous-id combines this read with the identity check below, so its top-level ok and exit status also reflect identity failures. See Test before launch for handling aggregate checks that are pending representative data.

Identity check

GET /api/v2/warehouse/identity-check?optimization_id=<id>&days=14

Auth: Required

Read-only check that an optimization's exposure id is the id the SDK is called with. It reads the last days days (1 to 90, default 14) of the optimization's exposure source and reports:

  • reward: how many distinct exposure ids also appear as ids in the optimization's reward metric.
  • holdout: if the exposures have an is_holdout column, how many is_holdout = true rows Levered's holdout hash also puts in the holdout. null when there is no such column.

low is true when a share is below 1% (reward) or 90% (holdout); warnings explains it, and ok is false. Query errors also produce warnings and ok: false. levered verify shows the same report.

Response:

{
  "optimization_id": "6da01473-97bb-4fa1-84b4-17ff7ddf4705",
  "days": 14,
  "since": "2026-10-15T09:00:00.000Z",
  "exposures": { "source": "LEVERED_EXPOSURE", "id_column": "USER_ID", "timestamp_column": "TIMESTAMP" },
  "reward": { "total": 5200, "matched": 1430, "share": 0.275, "low": false, "error": null, "metric_name": "Document uploaded", "id_column": "USER_ID" },
  "holdout": { "total": 540, "matched": 540, "share": 1, "low": false, "error": null },
  "warnings": [],
  "ok": true
}

Test connection

POST /api/v2/warehouse/connections/test

Auth: Required

Tests the current warehouse connection by executing a lightweight query.

Response (success):

{
  "success": true,
  "meta": {
    "request_id": "req_abc123",
    "organization_id": "org_xyz"
  }
}

Response (failure, 400):

{
  "success": false,
  "error": "Permission denied for dataset 'levered'"
}

Delete connection

DELETE /api/v2/warehouse/connections

Auth: Required

Removes the warehouse connection. Metrics that depend on this connection will stop working.

Response: 204 No Content