Control Plane API
The HatiData control plane exposes a RESTful API for all management operations. The dashboard is itself a client of these endpoints. Every request that is not a live query goes through the control plane.
Overview
Base URL
https://api.hatidata.com/v1
All endpoints are prefixed with /v1. Request and response bodies are JSON.
Authentication
Every request must include one of three authentication methods:
| Method | Header | Use Case |
|---|---|---|
| JWT | Authorization: Bearer <jwt_token> | Dashboard users, SSO sessions |
| API Key | Authorization: ApiKey hd_live_... | Programmatic access, SDKs, agents |
| Federated | Authorization: Bearer <cloud_token> | AWS STS, GCP Workload Identity, Azure AD |
# API key authentication
curl -H "Authorization: ApiKey hd_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
https://api.hatidata.com/v1/organizations/org_abc
# JWT authentication
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
https://api.hatidata.com/v1/organizations/org_abc
Rate Limits
Rate limits are applied per authentication identity:
| Tier | Requests/min | Burst |
|---|---|---|
| Free | 60 | 10 |
| Cloud | 300 | 50 |
| Growth | 1,000 | 100 |
| Enterprise | 10,000 | 500 |
Rate limit headers are included in every response:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 298
X-RateLimit-Reset: 1708000060
When rate limited, the API returns 429 Too Many Requests with a Retry-After header.
Error Format
All errors follow a consistent structure:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Field 'email' is required",
"details": { "field": "email", "constraint": "required" },
"request_id": "req_a1b2c3d4"
}
}
| HTTP Status | Code | Description |
|---|---|---|
400 | VALIDATION_ERROR | Invalid request body or parameters |
401 | UNAUTHORIZED | Missing or invalid authentication |
403 | FORBIDDEN | Insufficient permissions or scope |
404 | NOT_FOUND | Resource does not exist |
409 | CONFLICT | Resource already exists or state conflict |
422 | POLICY_VIOLATION | Request blocked by ABAC policy |
429 | RATE_LIMITED | Too many requests |
500 | INTERNAL_ERROR | Unexpected server error |
Pagination
List endpoints use cursor-based pagination:
{
"data": [...],
"pagination": {
"cursor": "cur_next123",
"has_more": true,
"total": 1250
}
}
Pass ?limit=50&cursor=cur_xyz to paginate. Default limit is 50; maximum is 200.
Health Check
GET /health — public, no authentication required.
{ "status": "healthy", "version": "1.0.0", "uptime_seconds": 86400 }
Query Proxy
The proxy accepts SQL over the Postgres wire protocol (port 5439) and via REST. All paths share the same 15-stage pipeline: semaphore → table extract → policy check → cost estimate → quota check → row filter → vector embed → transpile → snapshot pin → execute → dirty track + WAL → AI heal → column mask → meter → audit.
Execute Query
POST /v1/environments/{env_id}/query
Execute SQL and receive results as JSON. Requires query:read scope (or query:write for DDL/DML).
Request:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/query \
-H "Authorization: ApiKey hd_live_..." \
-H "Content-Type: application/json" \
-d '{
"sql": "SELECT name, region FROM customers WHERE region = '\''US'\'' LIMIT 5",
"agent_id": "data-analyst-v2",
"agent_framework": "langchain"
}'
Response 200 OK:
{
"query_id": "qry_a1b2c3d4",
"columns": [
{ "name": "name", "type": "VARCHAR" },
{ "name": "region", "type": "VARCHAR" }
],
"rows": [["Alice Chen", "US"], ["Bob Smith", "US"]],
"row_count": 2,
"execution_time_ms": 8,
"credits_consumed": 1,
"columns_masked": [],
"cache_hit": false
}
| Field | Type | Required | Description |
|---|---|---|---|
sql | string | Yes | SQL query (Snowflake syntax auto-transpiled) |
agent_id | string | No | Agent identifier for policy targeting |
agent_framework | string | No | Framework name (langchain, crewai, etc.) |
timeout_ms | integer | No | Query timeout (default: 30000, max: 300000) |
format | string | No | json (default), csv, or arrow |
Execute Query — Arrow Format
POST /v1/environments/{env_id}/query/arrow
Execute SQL and receive results as base64-encoded Apache Arrow format. Eliminates JSON serialization overhead for large analytical result sets. Requires query:read scope. Available on Cloud and Enterprise tiers.
Request:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/query/arrow \
-H "Authorization: ApiKey hd_live_..." \
-H "Content-Type: application/json" \
-d '{ "sql": "SELECT * FROM orders LIMIT 10000" }'
Response 200 OK:
{
"format": "arrow_ipc_base64",
"data": "QVJST1cxAAAAAAoAAAAA...",
"rows": 10000,
"execution_time_ms": 14
}
Decode in Python: pyarrow.ipc.open_stream(io.BytesIO(base64.b64decode(result["data"]))).read_all().
Organizations
Organizations are the top-level resource. Every user, environment, policy, and API key belongs to an organization.
| Method | Path | Description | Role |
|---|---|---|---|
POST | /v1/organizations | Create organization | Authenticated |
GET | /v1/organizations/{org_id} | Get organization details | Member |
PUT | /v1/organizations/{org_id} | Update name, billing email, settings | Owner / Admin |
Create organization — request:
curl -X POST https://api.hatidata.com/v1/organizations \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"slug": "acme-corp",
"billing_email": "billing@acme.com",
"cloud_region": "us-east-1"
}'
Response 201 Created:
{
"org_id": "org_a1b2c3d4",
"name": "Acme Corp",
"slug": "acme-corp",
"tier": "free",
"status": "active",
"cloud_region": "us-east-1",
"created_at": "2026-02-16T10:00:00Z"
}
Organization status values: active, pending_payment, provisioning, suspended, cancelled.
The slug and cloud_region fields are immutable after creation.
Users
Users belong to an organization and carry a role that governs all access decisions.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/users | List users | Owner / Admin |
POST | /v1/organizations/{org_id}/users/invite | Invite user by email | Owner / Admin |
PUT | /v1/organizations/{org_id}/users/{user_id}/role | Change role | Owner / Admin |
DELETE | /v1/organizations/{org_id}/users/{user_id} | Remove user | Owner / Admin |
Available roles:
| Role | Description |
|---|---|
owner | Full access including billing and org deletion |
admin | Manage users, environments, policies, API keys |
developer | Create and run queries; manage schemas; write access |
analyst | Read-only query access to all non-restricted tables |
auditor | Read-only access to audit logs, policies, and compliance data |
service_account | Access governed by API key scopes (for programmatic integrations) |
Invite user — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/users/invite \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{ "email": "bob@acme.com", "role": "developer" }'
Response 201 Created:
{
"user_id": "usr_a4b5c6",
"email": "bob@acme.com",
"role": "developer",
"status": "invited",
"invited_at": "2026-02-16T10:00:00Z"
}
API Keys
API keys are scoped to environments, hashed with Argon2id, and support rotation with a configurable grace period.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/environments/{env_id}/api-keys | List keys (metadata only) | Owner / Admin |
POST | /v1/environments/{env_id}/api-keys | Create key | Owner / Admin |
POST | /v1/environments/{env_id}/api-keys/{key_id}/rotate | Rotate key | Owner / Admin |
DELETE | /v1/environments/{env_id}/api-keys/{key_id} | Revoke key immediately | Owner / Admin |
Create key — request:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/api-keys \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "langchain-agent",
"scopes": ["query:read", "query:write", "schema:read", "agent:*"],
"ip_allowlist": ["10.0.1.0/24"],
"expires_in_days": 90
}'
Response 201 Created:
{
"key_id": "key_g7h8i9",
"name": "langchain-agent",
"key": "hd_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"scopes": ["query:read", "query:write", "schema:read", "agent:*"],
"expires_at": "2026-05-17T10:00:00Z",
"created_at": "2026-02-16T10:00:00Z"
}
The key field is returned only once. Key values cannot be retrieved after creation — rotate to replace a lost key.
Common scopes: query:read, query:write, schema:read, schema:write, policy:read, policy:write, audit:read, billing:read, agent:*. Use * suffix to grant all sub-scopes.
Rotate key — response:
{
"key_id": "key_a1b2c3",
"new_key": "hd_live_n3w5ecr3t...",
"old_key_expires_at": "2026-02-18T10:00:00Z",
"grace_period_hours": 48
}
Both old and new keys remain valid during the grace period (default 72 hours, max 168).
Policies
Two policy systems are available: standard policies (column masking and row-level security) and ABAC policies (attribute-based access control).
Standard Policies
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/environments/{env_id}/policies | List policies | Member |
POST | /v1/environments/{env_id}/policies | Create policy | Owner / Admin |
PUT | /v1/environments/{env_id}/policies/{policy_id} | Update policy | Owner / Admin |
DELETE | /v1/environments/{env_id}/policies/{policy_id} | Delete policy | Owner / Admin |
Create column masking policy — request:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/policies \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "pii-masking",
"type": "column_masking",
"rules": [
{ "table": "customers", "column": "email", "function": "full", "exempt_roles": ["owner"] },
{ "table": "customers", "column": "ssn", "function": "hash", "exempt_roles": [] }
],
"enabled": true
}'
Masking functions: full (replace with ***), partial (show last N chars), hash (cryptographic hash hex), null (return NULL).
ABAC Policies
ABAC policy management endpoints are deprecated and will be removed in a future release. Use Organization Settings to configure access policies at the org level.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/environments/{env_id}/abac-policies | List ABAC policies | Member |
POST | /v1/environments/{env_id}/abac-policies | Create ABAC policy | Owner / Admin |
POST | /v1/environments/{env_id}/abac-policies/simulate | Simulate policy evaluation | Owner / Admin |
Create ABAC policy — request:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/abac-policies \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "weekend-read-only",
"rules": [
{
"condition": "DayOfWeek",
"values": ["Saturday", "Sunday"],
"action": "read_only"
}
],
"priority": 20,
"enabled": true
}'
Simulate — response:
{
"decision": "deny",
"reason": "Write operations are not permitted on weekends",
"matching_policies": [{ "policy_id": "abac_m3n4o5", "name": "weekend-read-only" }],
"evaluation_time_ms": 0.2
}
Audit
Two immutable audit trails: query audit (every SQL execution) and IAM audit (every administrative action, cryptographic hash-chained).
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/environments/{env_id}/audit/queries | List query audit entries | Owner / Admin / Auditor |
GET | /v1/environments/{env_id}/audit/queries/{query_id} | Get single query detail | Owner / Admin / Auditor |
GET | /v1/environments/{env_id}/audit/admin | List IAM audit events | Owner / Admin / Auditor |
GET | /v1/environments/{env_id}/audit/admin/verify-chain | Verify hash chain integrity | Owner / Admin / Auditor |
POST | /v1/environments/{env_id}/audit/export | Export logs to object storage | Owner / Admin |
List query audit — request:
curl "https://api.hatidata.com/v1/environments/env_prod_x1y2/audit/queries?limit=20&agent_id=data-analyst-v2" \
-H "Authorization: Bearer <jwt>"
Response 200 OK:
{
"data": [
{
"query_id": "qry_a1b2c3d4",
"sql": "SELECT name, email FROM customers WHERE region = '[REDACTED]'",
"tables_accessed": ["customers"],
"rows_returned": 42,
"columns_masked": ["email"],
"execution_time_ms": 12,
"credits_consumed": 1,
"agent_metadata": { "agent_id": "data-analyst-v2", "framework": "langchain" },
"timestamp": "2026-02-16T10:30:00Z"
}
],
"pagination": { "cursor": "cur_abc123", "has_more": true, "total": 1250 }
}
Query parameters: start_date, end_date, user_id, agent_id, table, min_duration_ms, limit, cursor.
Export audit — request:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/audit/export \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"type": "query",
"start_date": "2026-02-01T00:00:00Z",
"end_date": "2026-02-15T23:59:59Z",
"format": "jsonl"
}'
Response: 202 Accepted with an export_id and the destination object storage path.
Billing
Credit-based billing. Queries consume credits based on complexity (tables scanned, rows returned, query type).
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/billing/usage | Usage for current billing period | Owner |
GET | /v1/organizations/{org_id}/billing/quotas | Current quota limits | Owner |
PUT | /v1/organizations/{org_id}/billing/quotas | Update alert thresholds | Owner |
Get usage — response:
{
"org_id": "org_a1b2c3d4",
"tier": "cloud",
"billing_period": { "start": "2026-02-01T00:00:00Z", "end": "2026-02-28T23:59:59Z" },
"credits": {
"limit": 10000,
"used": 3250,
"remaining": 6750,
"usage_percent": 32.5
},
"breakdown": {
"queries": { "total": 45200, "select": 42100, "insert": 2800 },
"by_environment": [
{ "env_id": "env_prod_x1y2", "name": "production", "credits_used": 2800 }
]
}
}
Tier quotas:
| Quota | Free | Cloud | Growth | Enterprise |
|---|---|---|---|---|
| Monthly credits | 1,000 | 10,000 | 100,000 | Custom |
| Concurrent queries | 10 | 100 | 500 | Custom |
| Max rows/query | 100,000 | 1,000,000 | 10,000,000 | Unlimited |
| Storage (GB) | 10 | 500 | 5,000 | Custom |
| Environments | 1 | 5 | 20 | Unlimited |
| Users | 3 | 25 | 100 | Unlimited |
Billing alerts are delivered via webhooks. Configure billing.warning and billing.critical event subscriptions to receive notifications.
Environments
Environment creation and management endpoints are deprecated. Environment configuration has moved to Organization Settings. Existing environments continue to function normally.
Environments provide isolated workspaces within an organization. Each has independent policies, API keys, and connection credentials.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/environments | List environments | Member |
POST | /v1/organizations/{org_id}/environments | Create environment | Owner / Admin |
GET | /v1/organizations/{org_id}/environments/{env_id} | Get environment | Member |
PUT | /v1/organizations/{org_id}/environments/{env_id} | Update settings | Owner / Admin |
POST | /v1/organizations/{org_id}/environments/{env_id}/promote | Promote to next stage | Owner / Admin |
GET | /v1/organizations/{org_id}/environments/{env_id}/connection-info | Get connection strings for psql, dbt, CLI, SDK | Member |
Create environment — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/environments \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "staging",
"slug": "staging",
"settings": { "query_timeout_ms": 30000, "cache_enabled": true }
}'
Response 201 Created:
{
"env_id": "env_stg_a3b4",
"name": "staging",
"org_id": "org_a1b2c3d4",
"status": "active",
"connection": {
"host": "acme-corp-staging.proxy.hatidata.com",
"port": 5439,
"database": "hatidata"
},
"created_at": "2026-02-16T10:00:00Z"
}
Webhooks
Webhook management endpoints are deprecated. Use Semantic Triggers for event-driven notifications, or configure webhooks via Organization Settings.
Webhooks deliver real-time event notifications. Every payload is signed with HMAC-SHA256.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/webhooks | List webhooks | Owner / Admin |
POST | /v1/organizations/{org_id}/webhooks | Create webhook | Owner / Admin |
PUT | /v1/organizations/{org_id}/webhooks/{webhook_id} | Update events or URL | Owner / Admin |
DELETE | /v1/organizations/{org_id}/webhooks/{webhook_id} | Delete webhook | Owner / Admin |
POST | /v1/organizations/{org_id}/webhooks/{webhook_id}/test | Send test event | Owner / Admin |
Create webhook — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/webhooks \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.acme.com/hatidata",
"events": ["key.rotated", "billing.warning", "policy.changed"]
}'
Response 201 Created:
{
"webhook_id": "wh_d4e5f6",
"url": "https://hooks.acme.com/hatidata",
"events": ["key.rotated", "billing.warning", "policy.changed"],
"signing_secret": "whsec_a1b2c3d4...",
"status": "active"
}
The signing_secret is shown only once. Store it to verify incoming payloads.
Payload envelope:
{
"event_id": "evt_m3n4o5p6",
"event_type": "key.rotated",
"org_id": "org_a1b2c3d4",
"timestamp": "2026-02-16T10:00:00Z",
"data": { "key_id": "key_a1b2c3", "name": "analytics-dashboard" }
}
Signature verification (Python):
import hmac, hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
Available event types: key.created/rotated/expiring/revoked, user.invited/removed/role_changed, policy.created/updated/deleted, billing.warning/critical/quota_exceeded, jit.requested/approved/denied, environment.created/promoted, auth.failed.
Failed deliveries are retried with exponential backoff (1 min → 5 min → 30 min → 2 hr → 12 hr) before the webhook is marked failed.
Provisioning
Three provisioning capabilities: JIT (Just-In-Time) temporary access, agent capability grants, and shadow mode for risk-free migration testing.
JIT Access
JIT Access endpoints are deprecated. Use the Agent Registry to manage agent trust levels and access promotion.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/environments/{env_id}/jit-access | List requests | Owner / Admin / Auditor |
POST | /v1/environments/{env_id}/jit-access | Request JIT escalation | Any authenticated user |
POST | /v1/environments/{env_id}/jit-access/{request_id}/approve | Approve request | Owner / Admin |
POST | /v1/environments/{env_id}/jit-access/{request_id}/deny | Deny request | Owner / Admin |
POST | /v1/environments/{env_id}/jit-access/{request_id}/revoke | Revoke active grant | Owner / Admin |
Request JIT access:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/jit-access \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"requested_role": "admin",
"reason": "Update column masking policy for PCI audit",
"duration_minutes": 60
}'
Agent Capabilities
Fine-grained permissions for AI agents beyond API key scopes:
| Method | Path | Description | Role |
|---|---|---|---|
POST | /v1/environments/{env_id}/agent-capabilities | Grant capability | Owner / Admin |
GET | /v1/environments/{env_id}/agent-capabilities | List grants | Owner / Admin |
DELETE | /v1/environments/{env_id}/agent-capabilities/{grant_id} | Revoke grant | Owner / Admin |
Grant capability — request:
curl -X POST https://api.hatidata.com/v1/environments/env_prod_x1y2/agent-capabilities \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "data-analyst-v2",
"capabilities": {
"allowed_tables": ["public.customers", "public.orders"],
"allowed_operations": ["SELECT"],
"max_queries_per_hour": 500,
"max_rows_per_query": 10000
},
"expires_at": "2026-03-16T00:00:00Z"
}'
Shadow Mode
Replay production queries against HatiData to validate compatibility before cutting over.
| Method | Path | Description |
|---|---|---|
POST | /v1/environments/{env_id}/shadow-mode/start | Start session |
GET | /v1/environments/{env_id}/shadow-mode/status | Get live statistics |
POST | /v1/environments/{env_id}/shadow-mode/upload | Upload query log (JSONL) |
POST | /v1/environments/{env_id}/shadow-mode/replay | Replay uploaded log |
GET | /v1/environments/{env_id}/shadow-mode/report | Get comparison report |
POST | /v1/environments/{env_id}/shadow-mode/stop | Stop session |
Status response:
{
"statistics": {
"queries_replayed": 4200,
"match_rate": 0.988,
"avg_latency_source_ms": 450,
"avg_latency_hatidata_ms": 12
}
}
Authentication
Endpoints for user authentication, session management, and SSO. All login endpoints are unauthenticated; session management requires a valid JWT or API key.
| Method | Path | Description | Auth |
|---|---|---|---|
POST | /v1/auth/login | Email/password login, returns JWT | None |
POST | /v1/auth/token/refresh | Refresh expired JWT | None |
POST | /v1/auth/magic-link | Send magic link email | None |
GET | /v1/auth/magic-link/callback | Magic link callback | None |
POST | /v1/auth/verify-email | Verify email with token | None |
POST | /v1/auth/verify-email/resend | Resend verification email | None |
POST | /v1/auth/forgot-password | Initiate password reset | None |
POST | /v1/auth/reset-password | Complete password reset | None |
GET | /v1/auth/me | Get current user profile | JWT / API Key |
POST | /v1/auth/logout | Logout (invalidate session) | JWT / API Key |
POST | /v1/auth/sso/initiate | Initiate SSO flow (Clerk) | None |
GET | /v1/auth/sso/callback | SSO callback handler | None |
POST | /v1/auth/exchange-token | Exchange external token for JWT | None |
Login — request:
curl -X POST https://api.hatidata.com/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "alice@acme.com",
"password": "s3cur3P@ssword"
}'
Response 200 OK:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "rt_a1b2c3d4e5f6...",
"expires_in": 3600,
"token_type": "Bearer",
"user": {
"user_id": "usr_a1b2c3",
"email": "alice@acme.com",
"org_id": "org_a1b2c3d4",
"role": "admin"
}
}
Signup
Create a new account and organization. For paid tiers, the response includes a Stripe checkout URL for payment.
| Method | Path | Description | Auth |
|---|---|---|---|
POST | /v1/signup | Create account + org; optionally redirect to Stripe checkout | None |
Signup — request:
curl -X POST https://api.hatidata.com/v1/signup \
-H "Content-Type: application/json" \
-d '{
"email": "alice@acme.com",
"password": "s3cur3P@ssword",
"org_name": "Acme Corp",
"tier": "cloud"
}'
Response 201 Created:
{
"user_id": "usr_a1b2c3",
"org_id": "org_a1b2c3d4",
"tier": "cloud",
"status": "pending_payment",
"checkout_url": "https://checkout.stripe.com/c/pay/cs_live_..."
}
For free tier signups, status is active and no checkout_url is returned.
Agent Registry
The agent registry tracks all AI agents that connect to HatiData. Agents are auto-registered on first connection via the proxy and can be managed through these endpoints.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/agents | List registered agents | Member |
GET | /v1/agents/{agent_id} | Get agent detail | Member |
PATCH | /v1/agents/{agent_id} | Update agent metadata | Owner / Admin |
POST | /v1/agents/{agent_id}/promote | Promote trust level | Owner / Admin |
POST | /v1/agents/{agent_id}/suspend | Suspend agent | Owner / Admin |
POST | /v1/agents/{agent_id}/revoke | Revoke agent permanently | Owner / Admin |
POST | /v1/agents/{agent_id}/keys | Generate agent-scoped API key | Owner / Admin |
POST | /v1/internal/agent-connect | Auto-register on connect (proxy internal) | Internal |
List agents — request:
curl https://api.hatidata.com/v1/agents \
-H "Authorization: ApiKey hd_live_..."
Response 200 OK:
{
"data": [
{
"agent_id": "data-analyst-v2",
"framework": "langchain",
"trust_level": "standard",
"status": "active",
"fingerprint": "fp_a1b2c3d4",
"last_seen_at": "2026-03-07T10:30:00Z",
"registered_at": "2026-02-16T10:00:00Z"
}
],
"pagination": { "cursor": null, "has_more": false, "total": 1 }
}
Promote trust level — request:
curl -X POST https://api.hatidata.com/v1/agents/data-analyst-v2/promote \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{ "trust_level": "elevated", "reason": "Verified production agent" }'
Trust levels: untrusted, standard, elevated, admin. Newly auto-registered agents start at standard. The agent_registration_policy in Organization Settings controls whether auto-registration is open, approval-required, or disabled.
Generate agent-scoped key — request:
curl -X POST https://api.hatidata.com/v1/agents/data-analyst-v2/keys \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"scopes": ["query:read", "schema:read", "agent:*"],
"expires_in_days": 90
}'
Response 201 Created:
{
"key_id": "agk_x1y2z3",
"key": "hd_agent_a1b2c3d4e5f6...",
"agent_id": "data-analyst-v2",
"scopes": ["query:read", "schema:read", "agent:*"],
"expires_at": "2026-06-07T10:00:00Z"
}
Agent Keys
Agent keys are identity-scoped API keys tied to a specific AI agent. They carry metadata about the agent's framework and restrict access to specific tables.
| Method | Path | Description | Role |
|---|---|---|---|
POST | /v1/organizations/{org_id}/agent-keys | Create agent-specific API key | Owner / Admin |
GET | /v1/organizations/{org_id}/agent-keys | List agent keys | Owner / Admin |
GET | /v1/organizations/{org_id}/agent-keys/{key_id} | Get agent key details | Owner / Admin |
PUT | /v1/organizations/{org_id}/agent-keys/{key_id} | Update agent key | Owner / Admin |
POST | /v1/organizations/{org_id}/agent-keys/{key_id}/rotate | Rotate agent key | Owner / Admin |
DELETE | /v1/organizations/{org_id}/agent-keys/{key_id} | Revoke agent key | Owner / Admin |
Create agent key — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/agent-keys \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"agent_name": "data-analyst-v2",
"framework": "langchain",
"allowed_tables": ["public.customers", "public.orders"],
"scopes": ["query:read", "schema:read"],
"expires_in_days": 90
}'
Response 201 Created:
{
"key_id": "agk_a1b2c3d4",
"agent_name": "data-analyst-v2",
"key": "hd_agent_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"framework": "langchain",
"allowed_tables": ["public.customers", "public.orders"],
"scopes": ["query:read", "schema:read"],
"expires_at": "2026-06-07T10:00:00Z",
"created_at": "2026-03-07T10:00:00Z"
}
The key field is returned only once. Agent keys use the hd_agent_ prefix to distinguish them from environment API keys.
Agent Memory
Long-term agent memory with hybrid search (SQL + vector). Memories are stored per-organization and searchable by content, agent, or metadata.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/agent-memory | List agent memories | Member |
POST | /v1/organizations/{org_id}/agent-memory | Store new memory | Member |
GET | /v1/organizations/{org_id}/agent-memory/search | Hybrid search (vector + text) | Member |
DELETE | /v1/organizations/{org_id}/agent-memory/{memory_id} | Delete memory | Member |
Search memory — request:
curl "https://api.hatidata.com/v1/organizations/org_a1b2c3d4/agent-memory/search?q=customer+churn+analysis&agent_id=data-analyst-v2&limit=5" \
-H "Authorization: Bearer <jwt>"
Response 200 OK:
{
"data": [
{
"memory_id": "mem_x1y2z3",
"agent_id": "data-analyst-v2",
"content": "Customer churn correlates with support ticket count > 5 in last 30 days",
"relevance_score": 0.92,
"created_at": "2026-03-01T14:30:00Z"
}
],
"pagination": { "cursor": null, "has_more": false, "total": 1 }
}
Branches
Schema-based branch isolation for agents. Branches provide zero-copy-on-create workspaces that are merged back to main after validation.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/branches | List branches | Member |
POST | /v1/organizations/{org_id}/branches | Create branch | Member |
GET | /v1/organizations/{org_id}/branches/{branch_id} | Get branch details | Member |
DELETE | /v1/organizations/{org_id}/branches/{branch_id} | Discard branch | Member |
POST | /v1/organizations/{org_id}/branches/{branch_id}/merge | Merge to main | Member |
GET | /v1/organizations/{org_id}/branches/{branch_id}/diff | Get diff from main | Member |
GET | /v1/organizations/{org_id}/branches/{branch_id}/conflicts | Get merge conflicts | Member |
Create branch — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/branches \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "experiment-churn-model",
"agent_id": "data-analyst-v2",
"ttl_hours": 24
}'
Response 201 Created:
{
"branch_id": "br_a1b2c3d4",
"name": "experiment-churn-model",
"agent_id": "data-analyst-v2",
"status": "active",
"schema": "branch_a1b2c3d4",
"expires_at": "2026-03-08T10:00:00Z",
"created_at": "2026-03-07T10:00:00Z"
}
Semantic Triggers
Event-driven rules that fire when query content or agent behavior matches a semantic concept. Triggers use two-stage evaluation: ANN pre-filter followed by exact cosine verification.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/triggers | List triggers | Member |
POST | /v1/organizations/{org_id}/triggers | Create trigger | Member |
PUT | /v1/organizations/{org_id}/triggers/{trigger_id} | Update trigger | Member |
DELETE | /v1/organizations/{org_id}/triggers/{trigger_id} | Delete trigger | Member |
POST | /v1/organizations/{org_id}/triggers/{trigger_id}/test | Test trigger (dry-run) | Member |
Create trigger — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/triggers \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "pii-access-alert",
"concept": "accessing personally identifiable information",
"threshold": 0.85,
"action": "webhook",
"action_config": { "url": "https://hooks.acme.com/pii-alert" },
"cooldown_seconds": 300
}'
Response 201 Created:
{
"trigger_id": "trg_a1b2c3d4",
"name": "pii-access-alert",
"concept": "accessing personally identifiable information",
"threshold": 0.85,
"action": "webhook",
"cooldown_seconds": 300,
"status": "active",
"created_at": "2026-03-07T10:00:00Z"
}
Chain-of-Thought
Immutable, hash-chained reasoning traces for AI agent decision audit. Each step is SHA-256 linked to the previous step in its session, forming a tamper-evident ledger.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/cot/sessions | List CoT sessions | Member |
POST | /v1/cot/ingest | Ingest reasoning traces | Member |
GET | /v1/cot/sessions/{session_id}/replay | Replay full session | Member |
GET | /v1/cot/sessions/{session_id}/verify | Verify hash chain | Member |
POST | /v1/cot/approvals | Record human approval/rejection | Admin |
Ingest reasoning trace — request:
curl -X POST https://api.hatidata.com/v1/cot/ingest \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "ses_a1b2c3d4",
"agent_id": "data-analyst-v2",
"steps": [
{
"step_type": "reasoning",
"content": "User asked for churn analysis. I need to query customer and support_tickets tables.",
"timestamp": "2026-03-07T10:00:00Z"
},
{
"step_type": "tool_call",
"content": "SELECT c.name, COUNT(t.id) FROM customers c JOIN support_tickets t ON c.id = t.customer_id GROUP BY c.name",
"timestamp": "2026-03-07T10:00:01Z"
}
]
}'
Response 201 Created:
{
"ingested": 2,
"session_id": "ses_a1b2c3d4",
"chain_valid": true,
"latest_hash": "sha256:a1b2c3d4e5f6..."
}
Sessions
Manage active user and agent sessions. Sessions are created on login and can be individually or bulk revoked.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/sessions | List active sessions | Member |
DELETE | /v1/sessions/{session_id} | Revoke session | Member |
DELETE | /v1/sessions | Revoke all sessions | Member |
List sessions — response:
{
"data": [
{
"session_id": "ses_a1b2c3",
"user_id": "usr_a1b2c3",
"ip_address": "10.0.1.42",
"user_agent": "Mozilla/5.0...",
"created_at": "2026-03-07T08:00:00Z",
"last_active_at": "2026-03-07T09:45:00Z"
}
]
}
Federation
Configure federated identity providers for cloud-native authentication. Supports AWS STS, GCP Workload Identity, and Azure Managed Identity.
| Method | Path | Description | Role |
|---|---|---|---|
POST | /v1/organizations/{org_id}/federation | Configure federation provider | Owner / Admin |
GET | /v1/organizations/{org_id}/federation | List providers | Owner / Admin |
DELETE | /v1/organizations/{org_id}/federation/{provider} | Remove provider | Owner / Admin |
POST | /v1/organizations/{org_id}/federation/{provider}/test | Test connection | Owner / Admin |
Configure GCP Workload Identity — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/federation \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"provider": "gcp",
"config": {
"project_id": "acme-analytics",
"workload_identity_pool": "projects/123456/locations/global/workloadIdentityPools/hatidata",
"allowed_service_accounts": ["agent@acme-analytics.iam.gserviceaccount.com"]
}
}'
Response 201 Created:
{
"provider": "gcp",
"status": "active",
"config": {
"project_id": "acme-analytics",
"workload_identity_pool": "projects/123456/locations/global/workloadIdentityPools/hatidata"
},
"created_at": "2026-03-07T10:00:00Z"
}
Tenants (Multi-Tenancy)
Hierarchical multi-tenancy for SaaS platforms. Parent organizations can create child tenants with isolated data and policies.
| Method | Path | Description | Role |
|---|---|---|---|
POST | /v1/organizations/{org_id}/tenants | Create child tenant | Owner / Admin |
GET | /v1/organizations/{org_id}/tenants | List child tenants | Owner / Admin |
PUT | /v1/organizations/{org_id}/tenants/config | Configure isolation | Owner / Admin |
Create tenant — request:
curl -X POST https://api.hatidata.com/v1/organizations/org_a1b2c3d4/tenants \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Tenant Alpha",
"slug": "tenant-alpha",
"isolation": "schema"
}'
Response 201 Created:
{
"tenant_id": "tnt_a1b2c3d4",
"name": "Tenant Alpha",
"slug": "tenant-alpha",
"isolation": "schema",
"parent_org_id": "org_a1b2c3d4",
"status": "active",
"created_at": "2026-03-07T10:00:00Z"
}
Cost Intelligence
Query cost analysis and optimization recommendations. Tracks credit consumption at the query, environment, and organization level.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/cost/summary | Cost summary | Owner / Admin |
GET | /v1/organizations/{org_id}/cost/daily | Daily breakdown | Owner / Admin |
GET | /v1/organizations/{org_id}/cost/top-queries | Top expensive queries | Owner / Admin |
GET | /v1/organizations/{org_id}/cost/optimizations | Optimization recommendations | Owner / Admin |
Cost summary — response:
{
"org_id": "org_a1b2c3d4",
"period": { "start": "2026-03-01T00:00:00Z", "end": "2026-03-07T23:59:59Z" },
"total_credits": 1250,
"estimated_monthly": 5360,
"top_cost_drivers": [
{ "category": "full_table_scans", "credits": 420, "query_count": 15 },
{ "category": "large_result_sets", "credits": 310, "query_count": 8 }
]
}
Performance Analytics
Query performance metrics including latency timelines, cache hit rates, slow query analysis, and per-stage pipeline latency.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/environments/{env_id}/performance/latency-timeline | Latency over time | Member |
GET | /v1/environments/{env_id}/performance/cache-metrics | L1/L2/L3 cache stats | Member |
GET | /v1/environments/{env_id}/performance/slow-queries | Top slow queries | Member |
GET | /v1/environments/{env_id}/performance/pipeline-stages | Pipeline stage latency | Member |
Cache metrics — response:
{
"env_id": "env_prod_x1y2",
"period": "last_24h",
"memory_cache": { "hit_rate": 0.42, "entries": 1250, "size_mb": 128 },
"disk_cache": { "hit_rate": 0.78, "entries": 340, "size_mb": 2048 },
"object_cache": { "hit_rate": 0.95, "entries": 45, "size_mb": 512 },
"overall_hit_rate": 0.72
}
Settings
Organization-level configuration including general settings, agent registration policy, GDPR data export, and account deletion.
| Method | Path | Description | Role |
|---|---|---|---|
GET | /v1/organizations/{org_id}/settings | Get org settings | Owner / Admin |
PATCH | /v1/organizations/{org_id}/settings | Update settings | Owner / Admin |
POST | /v1/organizations/{org_id}/settings/export-data | GDPR data export | Owner |
POST | /v1/organizations/{org_id}/settings/delete | Delete organization | Owner |
Update settings — request:
curl -X PATCH https://api.hatidata.com/v1/organizations/org_a1b2c3d4/settings \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"default_query_timeout_ms": 30000,
"audit_retention_days": 365,
"require_mfa": true,
"allowed_ip_ranges": ["10.0.0.0/8", "172.16.0.0/12"],
"agent_registration_policy": "open"
}'
Response 200 OK:
{
"org_id": "org_a1b2c3d4",
"settings": {
"default_query_timeout_ms": 30000,
"audit_retention_days": 365,
"require_mfa": true,
"allowed_ip_ranges": ["10.0.0.0/8", "172.16.0.0/12"],
"agent_registration_policy": "open"
},
"updated_at": "2026-03-07T10:00:00Z"
}
The agent_registration_policy field controls how new agents are handled when they first connect:
| Value | Behavior |
|---|---|
open | Agents auto-register on first connect (default) |
approval_required | Agents are queued for admin approval before they can execute queries |
disabled | Only pre-registered agents (created via the Agent Registry API) can connect |
---
## AI Providers (BYOL)
Bring Your Own LLM (BYOL) configuration. Organizations can configure their own embedding models and LLMs for agent memory, semantic triggers, and AI healing.
| Method | Path | Description | Role |
|--------|------|-------------|------|
| `GET` | `/v1/organizations/{org_id}/ai-providers` | Get configured providers | Owner / Admin |
| `PUT` | `/v1/organizations/{org_id}/ai-providers/embedding` | Configure embedding model | Owner / Admin |
| `PUT` | `/v1/organizations/{org_id}/ai-providers/llm` | Configure LLM | Owner / Admin |
| `POST` | `/v1/organizations/{org_id}/ai-providers/test` | Test provider connection | Owner / Admin |
**Configure embedding provider — request:**
```bash
curl -X PUT https://api.hatidata.com/v1/organizations/org_a1b2c3d4/ai-providers/embedding \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"provider": "openai",
"model": "text-embedding-3-small",
"api_key": "sk-...",
"dimensions": 1536
}'
Response 200 OK:
{
"provider": "openai",
"model": "text-embedding-3-small",
"dimensions": 1536,
"status": "verified",
"updated_at": "2026-03-07T10:00:00Z"
}
Internal Endpoints
These endpoints are used by the proxy for communication with the control plane. They are not intended for external use but are documented here for self-hosted operators.
| Method | Path | Description | Auth |
|---|---|---|---|
POST | /v1/internal/metering | Ingest query metering records | Internal |
POST | /v1/internal/agent-activity | Ingest agent activity telemetry | Internal |
POST | /v1/internal/agent-connect | Auto-register agent on first connection | Internal |
GET | /v1/internal/sync | Fetch policy/quota sync bundle | Internal |
POST | /v1/internal/validate-key | Validate API key hash | Internal |
Internal endpoints authenticate via a shared secret (X-Internal-Token header) configured between the proxy and control plane. They are not exposed through the public API gateway.
Sync bundle — response:
{
"policies": [ { "policy_id": "pol_a1b2c3", "type": "column_masking", "rules": [...] } ],
"quotas": { "monthly_credit_limit": 10000, "used": 3250 },
"abac_policies": [...],
"agent_capabilities": [...],
"last_updated_at": "2026-03-07T10:00:00Z"
}