Audit
HatiData maintains two separate audit trails: Query Audit for all SQL queries executed through the proxy, and IAM Audit for all administrative actions. Both are immutable and tamper-evident.
Query Audit
List Query Audit Entries
GET /v1/environments/{env_id}/audit/queries
Returns paginated query audit entries. Requires Owner, Admin, or Auditor role.
Request:
curl "https://api.hatidata.com/v1/environments/env_prod_x1y2/audit/queries?limit=20&start_date=2026-02-15" \
-H "Authorization: Bearer <jwt>"
Response 200 OK:
{
"data": [
{
"query_id": "qry_a1b2c3d4",
"user_id": "usr_x1y2z3",
"source_ip": "10.0.1.50",
"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,
"cache_hit": false,
"policy_verdicts": [
{
"policy_id": "pol_a1b2c3",
"policy_name": "pii-masking",
"action": "mask",
"columns": ["email"]
}
],
"agent_metadata": {
"agent_id": "data-analyst-v2",
"framework": "langchain"
},
"timestamp": "2026-02-16T10:30:00Z"
},
{
"query_id": "qry_e5f6g7h8",
"user_id": "usr_a4b5c6",
"source_ip": "10.0.1.51",
"sql": "SELECT COUNT(*) FROM orders WHERE status = 'completed'",
"tables_accessed": ["orders"],
"rows_returned": 1,
"columns_masked": [],
"execution_time_ms": 3,
"credits_consumed": 1,
"cache_hit": true,
"policy_verdicts": [],
"agent_metadata": null,
"timestamp": "2026-02-16T10:29:00Z"
}
],
"pagination": {
"cursor": "cur_abc123",
"has_more": true,
"total": 1250
}
}
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | string (ISO 8601) | 24 hours ago | Start of date range |
end_date | string (ISO 8601) | Now | End of date range |
user_id | string | -- | Filter by user |
agent_id | string | -- | Filter by agent |
table | string | -- | Filter by table accessed |
cache_hit | boolean | -- | Filter by cache status |
min_duration_ms | integer | -- | Filter slow queries |
limit | integer | 50 | Results per page (max 200) |
cursor | string | -- | Pagination cursor |
Get Query Details
GET /v1/environments/{env_id}/audit/queries/{query_id}
Returns full details for a single query, including the complete execution plan and any error information.
Request:
curl https://api.hatidata.com/v1/environments/env_prod_x1y2/audit/queries/qry_a1b2c3d4 \
-H "Authorization: Bearer <jwt>"
Response 200 OK:
{
"query_id": "qry_a1b2c3d4",
"user_id": "usr_x1y2z3",
"source_ip": "10.0.1.50",
"sql_original": "SELECT name, email FROM customers WHERE region = '[EMAIL_REDACTED]'",
"sql_transpiled": "SELECT name, email FROM customers WHERE region = '[EMAIL_REDACTED]'",
"sql_with_rls": "SELECT name, email FROM customers WHERE region = '[EMAIL_REDACTED]' AND org_id = 'org_a1b2c3d4'",
"tables_accessed": ["customers"],
"rows_returned": 42,
"columns_masked": ["email"],
"execution_time_ms": 12,
"transpilation_time_ms": 0.5,
"credits_consumed": 1,
"cache_hit": false,
"cache_key": "sha256:a1b2c3d4...",
"policy_verdicts": [
{
"policy_id": "pol_a1b2c3",
"policy_name": "pii-masking",
"action": "mask",
"columns": ["email"],
"function": "full"
}
],
"abac_evaluation": {
"decision": "allow",
"policies_evaluated": 2,
"evaluation_time_ms": 0.3
},
"agent_metadata": {
"agent_id": "data-analyst-v2",
"framework": "langchain"
},
"timestamp": "2026-02-16T10:30:00Z"
}
IAM Audit
List Admin Actions
GET /v1/environments/{env_id}/audit/admin
Returns hash-chained IAM audit events. Each event includes a SHA-256 hash linking it to the previous event for tamper detection. Requires Owner, Admin, or Auditor role.
Request:
curl "https://api.hatidata.com/v1/environments/env_prod_x1y2/audit/admin?limit=10" \
-H "Authorization: Bearer <jwt>"
Response 200 OK:
{
"data": [
{
"event_id": "iam_a1b2c3",
"event_type": "policy.created",
"actor_id": "usr_x1y2z3",
"actor_email": "alice@acme.com",
"actor_role": "admin",
"source_ip": "10.0.1.50",
"resource_type": "policy",
"resource_id": "pol_g7h8i9",
"changes": {
"after": {
"name": "payment-masking",
"type": "column_masking",
"rules_count": 2
}
},
"hash": "sha256:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
"previous_hash": "sha256:z6y5x4w3v2u1t0s9r8q7p6o5n4m3l2k1j0i9h8g7f6e5d4c3b2a1",
"timestamp": "2026-02-16T10:00:00Z"
},
{
"event_id": "iam_d4e5f6",
"event_type": "user.role_changed",
"actor_id": "usr_x1y2z3",
"actor_email": "alice@acme.com",
"actor_role": "owner",
"source_ip": "10.0.1.50",
"resource_type": "user",
"resource_id": "usr_a4b5c6",
"changes": {
"before": { "role": "developer" },
"after": { "role": "admin" }
},
"hash": "sha256:z6y5x4w3v2u1t0s9r8q7p6o5n4m3l2k1j0i9h8g7f6e5d4c3b2a1",
"previous_hash": "sha256:m3n4o5p6q7r8s9t0u1v2w3x4y5z6a1b2c3d4e5f6g7h8i9j0k1l2",
"timestamp": "2026-02-16T09:45:00Z"
}
],
"pagination": {
"cursor": "cur_def456",
"has_more": true,
"total": 87
}
}
IAM Event Types
| Category | Event Types |
|---|---|
| Users | user.invited, user.removed, user.role_changed, user.suspended, user.reactivated |
| API Keys | key.created, key.rotated, key.revoked |
| Policies | policy.created, policy.updated, policy.deleted, abac_policy.created, abac_policy.updated, abac_policy.deleted |
| SSO | sso.configured, sso.updated, sso.disabled |
| Webhooks | webhook.created, webhook.updated, webhook.deleted |
| Environments | environment.created, environment.promoted, environment.suspended |
| JIT Access | jit.requested, jit.approved, jit.denied, jit.revoked |
| Agent | agent_capability.granted, agent_capability.revoked |
| Organization | org.settings_updated, org.mfa_enforced |
Verify Chain Integrity
GET /v1/environments/{env_id}/audit/admin/verify-chain
Verifies the integrity of the IAM audit hash chain. Each event's hash is computed from the event content plus the previous_hash, forming a tamper-evident chain.
Request:
curl https://api.hatidata.com/v1/environments/env_prod_x1y2/audit/admin/verify-chain \
-H "Authorization: Bearer <jwt>"
Response 200 OK:
{
"chain_valid": true,
"events_verified": 87,
"first_event": {
"event_id": "iam_genesis",
"timestamp": "2026-01-15T10:00:00Z"
},
"last_event": {
"event_id": "iam_a1b2c3",
"timestamp": "2026-02-16T10:00:00Z"
},
"verified_at": "2026-02-16T10:05:00Z"
}
If the chain has been tampered with:
{
"chain_valid": false,
"events_verified": 45,
"break_detected_at": {
"event_id": "iam_x9y8z7",
"expected_hash": "sha256:expected...",
"actual_hash": "sha256:actual...",
"timestamp": "2026-02-10T14:30:00Z"
},
"verified_at": "2026-02-16T10:05:00Z"
}
Export Audit Logs
POST /v1/environments/{env_id}/audit/export
Triggers an export of audit logs for a date range. Logs are written to the configured S3 bucket in JSONL format.
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:
{
"export_id": "exp_p7q8r9",
"type": "query",
"status": "processing",
"date_range": {
"start": "2026-02-01T00:00:00Z",
"end": "2026-02-15T23:59:59Z"
},
"estimated_records": 42000,
"s3_path": "s3://acme-hatidata-audit/exports/exp_p7q8r9/",
"created_at": "2026-02-16T10:00:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | query or admin |
start_date | string | Yes | ISO 8601 start date |
end_date | string | Yes | ISO 8601 end date |
format | string | No | jsonl (default) or csv |
Error Responses
| Status | Code | Description |
|---|---|---|
401 | UNAUTHORIZED | Missing or invalid authentication |
403 | FORBIDDEN | Insufficient role (must be Owner, Admin, or Auditor) |
404 | NOT_FOUND | Environment or query not found |
422 | INVALID_DATE_RANGE | Start date after end date or range exceeds 90 days |