{"components":{"parameters":{"AgentId":{"description":"Unique agent credential identifier (prefixed, e.g. agt_xxx).","in":"path","name":"agent_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"AnomalyId":{"description":"Unique anomaly alert identifier (prefixed, e.g. ano_xxx).","in":"path","name":"anomaly_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"ApprovalId":{"description":"Unique approval request identifier (prefixed, e.g. apr_xxx).","in":"path","name":"approval_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"AuditCredentialId":{"description":"Filter to a single agent credential.","in":"query","name":"credential_id","schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"AuditDecision":{"description":"Coarse outcome filter that groups events. `allow` = query; `block` = blocked, budget_exhausted, auth_failed, credential_expired; `mask` = masked; `truncate` = truncated.","in":"query","name":"decision","schema":{"$ref":"#/components/schemas/AuditDecision"}},"AuditEnd":{"description":"Return entries strictly older than this timestamp (cursor / upper bound).","in":"query","name":"end","schema":{"format":"date-time","type":"string"}},"AuditEvent":{"description":"Filter to a single event type (e.g. blocked, masked, query).","in":"query","name":"event","schema":{"pattern":"^[a-z_]+$","type":"string"}},"AuditSessionId":{"description":"Session identifier from an audit entry's session_id field. Unique per connection within a proxy instance, not over time.","in":"path","name":"session_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"AuditSource":{"description":"Filter by statement origin (wire, mcp, rest, or control).","in":"query","name":"source","schema":{"$ref":"#/components/schemas/AuditSource"}},"AuditStart":{"description":"Return entries at or after this timestamp (inclusive lower bound).","in":"query","name":"start","schema":{"format":"date-time","type":"string"}},"BranchId":{"description":"Unique sandbox branch identifier (prefixed, e.g. brn_xxx).","in":"path","name":"branch_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"CrmArtifactId":{"description":"Unique CRM artifact identifier (prefixed, e.g. art_xxx).","in":"path","name":"artifact_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"CrmCompanyId":{"description":"Unique CRM company identifier (prefixed, e.g. cmp_xxx).","in":"path","name":"company_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"CrmContactId":{"description":"Unique CRM contact identifier (prefixed, e.g. cnt_xxx).","in":"path","name":"contact_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"CrmDealId":{"description":"Unique CRM deal identifier (prefixed, e.g. dl_xxx).","in":"path","name":"deal_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"CrmTaskId":{"description":"Unique CRM research task identifier (prefixed, e.g. ctk_xxx).","in":"path","name":"task_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"DatabaseId":{"description":"Unique database identifier (prefixed, e.g. db_xxx).","in":"path","name":"database_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"DomainId":{"description":"Unique custom domain identifier (prefixed, e.g. dom_xxx).","in":"path","name":"domain_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"HoneytokenId":{"description":"Unique honeytoken identifier (prefixed, e.g. hnt_xxx).","in":"path","name":"honeytoken_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"OrgId":{"description":"Unique organization identifier.","in":"path","name":"org_id","required":true,"schema":{"example":"org_abc123","pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"PageSize":{"description":"Maximum number of items to return (1-100, default 20).","in":"query","name":"page_size","schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},"PageToken":{"description":"Opaque token for cursor-based pagination.","in":"query","name":"page_token","schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"PolicyId":{"description":"Unique policy profile identifier (prefixed, e.g. pol_xxx).","in":"path","name":"policy_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"ProjectId":{"description":"Unique project identifier (prefixed, e.g. prj_xxx).","in":"path","name":"project_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"ReplicaId":{"description":"Unique replica identifier (prefixed, e.g. rep_xxx).","in":"path","name":"replica_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"SupportCaseId":{"description":"Unique support case identifier (prefixed, e.g. sc_xxx).","in":"path","name":"case_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}},"WebhookId":{"description":"Unique webhook endpoint identifier (prefixed, e.g. whk_xxx).","in":"path","name":"webhook_id","required":true,"schema":{"pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}}},"responses":{"BadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request parameters."},"Conflict":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Resource already exists or conflicts with current state."},"Forbidden":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Operation not allowed by current plan limits."},"NotFound":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Resource not found."},"ServiceUnavailable":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Service temporarily unavailable."},"TooManyRequests":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited. Try again later.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"example":60,"type":"integer"}}}},"Unauthorized":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid authentication."}},"schemas":{"AccountExport":{"description":"Full account data export for privacy and data-portability requests.","properties":{"audit_logs":{"description":"Recent audit log entries associated with the account.","items":{"properties":{"action":{"description":"Action captured by the audit log entry.","type":"string"},"created_at":{"description":"When the audit log entry was recorded.","format":"date-time","type":"string"},"id":{"description":"Audit log entry identifier.","type":"string"},"ip_address":{"description":"IP address associated with the action, if known.","type":"string"},"resource_id":{"description":"Identifier of the affected resource.","type":"string"},"resource_type":{"description":"Type of resource affected by the action.","type":"string"}},"required":["id","action","created_at"],"type":"object"},"type":"array"},"consents":{"description":"Recorded legal-document acceptances for the user.","items":{"properties":{"accepted_at":{"description":"When the document was accepted.","format":"date-time","type":"string"},"document_type":{"description":"Legal document type accepted by the user.","type":"string"},"document_version":{"description":"Accepted document version.","type":"string"},"id":{"description":"Consent record identifier.","type":"string"},"ip_address":{"description":"IP address captured when consent was recorded.","type":"string"}},"required":["id","document_type","document_version","accepted_at"],"type":"object"},"type":"array"},"databases":{"description":"Databases registered under the exported projects.","items":{"properties":{"created_at":{"description":"When the database registration was created.","format":"date-time","type":"string"},"host":{"description":"Upstream PostgreSQL host.","type":"string"},"id":{"description":"Database identifier.","type":"string"},"name":{"description":"Upstream PostgreSQL database name.","type":"string"},"port":{"description":"Upstream PostgreSQL port.","type":"integer"},"project_id":{"description":"Owning project identifier.","type":"string"},"role":{"description":"Database role within the project.","type":"string"},"ssl_mode":{"description":"PostgreSQL SSL mode in use for the database.","type":"string"}},"required":["id","project_id","host","port","name","ssl_mode","role","created_at"],"type":"object"},"type":"array"},"email_preferences":{"description":"User communication preferences.","properties":{"marketing_emails":{"description":"Whether marketing emails are enabled.","type":"boolean"},"usage_limit_alerts":{"description":"Whether usage alert emails are enabled.","type":"boolean"}},"type":"object"},"exported_at":{"description":"When the export was generated.","format":"date-time","type":"string"},"organizations":{"description":"Organizations the user belongs to.","items":{"properties":{"created_at":{"description":"When the organization membership was created.","format":"date-time","type":"string"},"id":{"description":"Organization identifier.","type":"string"},"name":{"description":"Organization display name.","type":"string"},"role":{"description":"User role within the organization.","type":"string"},"slug":{"description":"Organization slug used in URLs and routing.","type":"string"}},"required":["id","name","slug","role","created_at"],"type":"object"},"type":"array"},"projects":{"description":"Projects owned through the user's organizations.","items":{"properties":{"created_at":{"description":"When the project was created.","format":"date-time","type":"string"},"description":{"description":"Project description at export time.","type":"string"},"id":{"description":"Project identifier.","type":"string"},"name":{"description":"Project display name.","type":"string"},"org_id":{"description":"Owning organization identifier.","type":"string"},"status":{"description":"Project lifecycle status.","type":"string"}},"required":["id","org_id","name","description","status","created_at"],"type":"object"},"type":"array"},"sessions":{"description":"Auth sessions associated with the user.","items":{"properties":{"created_at":{"description":"When the session was created.","format":"date-time","type":"string"},"expires_at":{"description":"When the session expires.","format":"date-time","type":"string"},"id":{"description":"Session identifier.","type":"string"},"ip_address":{"description":"IP address used to create the session, if known.","type":"string"},"user_agent":{"description":"User agent captured for the session, if known.","type":"string"}},"required":["id","expires_at","created_at"],"type":"object"},"type":"array"},"user":{"description":"Core user profile data.","properties":{"created_at":{"description":"When the user account was created.","format":"date-time","type":"string"},"email":{"description":"Primary account email address.","format":"email","type":"string"},"email_verified":{"description":"Whether the email address has been verified.","type":"boolean"},"id":{"description":"User identifier.","type":"string"},"image":{"description":"Avatar image URL, if present.","type":"string"},"name":{"description":"Display name for the user.","type":"string"},"updated_at":{"description":"When the user profile was last updated.","format":"date-time","type":"string"}},"required":["id","name","email","email_verified","created_at","updated_at"],"type":"object"}},"required":["user","organizations","projects","databases","sessions","email_preferences","consents","audit_logs","exported_at"],"type":"object"},"Activity":{"description":"A single entry in an entity's activity timeline.","properties":{"actor":{"description":"Who performed the action (\"agent\" or a user identifier).","type":"string"},"at":{"description":"When the action happened.","format":"date-time","type":"string"},"id":{"description":"Unique activity identifier.","example":"act_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"org_id":{"description":"Organization the activity belongs to.","type":"string"},"subject_id":{"description":"ID of the company/contact/deal this activity is about.","type":"string"},"subject_type":{"$ref":"#/components/schemas/ResearchTaskSubjectType"},"verb":{"description":"What happened (created, enriched, drafted, approved, sent).","type":"string"}},"required":["id","org_id","subject_type","subject_id","actor","verb","at"],"type":"object"},"AgentCredential":{"description":"A PgBeam-issued, scoped Postgres login plus hosted MCP token for an AI agent.","properties":{"auth_method":{"default":"scram-sha-256","description":"Postgres auth method the proxy presents for this credential.","enum":["cleartext","scram-sha-256"],"readOnly":true,"type":"string"},"created_at":{"description":"When the credential was created.","format":"date-time","type":"string"},"expires_at":{"description":"When the credential expires and becomes unusable. Null means it never expires. Enforcement is fail-closed in the proxy the instant this time passes, before any cleanup sweep runs.","format":"date-time","nullable":true,"type":"string"},"id":{"description":"Unique agent credential identifier (prefixed).","example":"agt_01h455vb4pex5vsknk084sn02q","type":"string"},"last_used_at":{"description":"When the credential was last used to connect, if ever.","format":"date-time","nullable":true,"type":"string"},"name":{"description":"Human-readable label for the credential.","example":"Claude Code (analytics)","type":"string"},"pg_username":{"description":"The Postgres username this credential presents to the proxy.","example":"agent_a1b2c3d4e5f6","type":"string"},"policy_profile_id":{"description":"Policy profile enforced for this credential.","example":"pol_01h455vb4pex5vsknk084sn02q","type":"string"},"principal_type":{"default":"agent","description":"Whether this credential represents an autonomous agent or a human operator.","enum":["agent","human"],"type":"string"},"project_id":{"description":"Owning project ID.","example":"prj_01h455vb4pex5vsknk084sn02q","type":"string"},"status":{"description":"Lifecycle status of the credential.","enum":["active","disabled","revoked"],"type":"string"},"updated_at":{"description":"When the credential was last updated.","format":"date-time","type":"string"}},"required":["id","project_id","policy_profile_id","name","pg_username","status","created_at","updated_at"],"type":"object"},"AgentCredentialSecrets":{"description":"One-time secrets returned only at creation. The connection string and MCP token are not retrievable again.","properties":{"connection_string":{"description":"Guarded Postgres connection string for this agent credential.","example":"postgresql://agent_a1b2c3d4e5f6:secret@abc.proxy.pgbeam.app:5432/mydb","type":"string"},"credential":{"$ref":"#/components/schemas/AgentCredential"},"mcp_token":{"description":"Bearer token for the hosted MCP endpoint (shown once).","example":"pba_a1b2c3d4e5f6g7h8","type":"string"},"mcp_url":{"description":"Hosted agent-database MCP endpoint for this project, served by the edge proxy on the same per-project host the agent connects to over the wire. Paste into an MCP client (Claude Code, Cursor, …) with the mcp_token as a bearer token.","example":"https://abc.proxy.pgbeam.app/mcp","type":"string"}},"required":["credential","connection_string","mcp_url","mcp_token"],"type":"object"},"AgentRole":{"description":"Specialist agent role that owns a task. The researcher is the lead, the enricher fills in graph edges, and outreach drafts.\n","enum":["researcher","enricher","outreach"],"type":"string"},"AgentUsageDropMarkers":{"description":"Evidence that the trail lost entries in this window. Nothing about the surviving rows looks wrong when this happens, so it is reported explicitly.","properties":{"entries_dropped":{"description":"Entries the markers account for. A floor: it counts only markers whose count could be read.","format":"int64","type":"integer"},"markers":{"description":"Number of gap markers read, capped at 1000.","type":"integer"},"markers_unparsed":{"description":"Markers whose count could not be read, so their entries are missing from entries_dropped. Reported rather than assumed zero.","type":"integer"},"reasons":{"description":"Distinct marker reasons, sorted, so an operator can tell the two buffers apart.","items":{"type":"string"},"type":"array"},"truncated":{"description":"True when the window held more gap markers than the cap, so entries_dropped accounts for only the ones read and the real gap is larger. Reported rather than left to look like an exact count.","type":"boolean"}},"required":["markers","truncated","entries_dropped","markers_unparsed","reasons"],"type":"object"},"AgentUsageLine":{"description":"One usage line. The four decision counts partition every statement-shaped entry; entries carrying no statement decision (approval progress rows, gap markers) are in entries but in none of the four, which is why entries is reported separately rather than derived.","properties":{"allowed":{"description":"Statements that ran and returned unmodified rows.","format":"int64","type":"integer"},"blocked":{"description":"Statements the gateway refused, including budget, honeytoken and approval refusals.","format":"int64","type":"integer"},"bytes_out":{"description":"Bytes returned to the client, the quantity the bytes meter bills on.","format":"int64","type":"integer"},"cache_bypass":{"description":"Not eligible for cache, so no lookup was attempted.","format":"int64","type":"integer"},"cache_hit":{"description":"Served from cache.","format":"int64","type":"integer"},"cache_miss":{"description":"Went upstream after a cache lookup found nothing.","format":"int64","type":"integer"},"cache_none":{"description":"No cache outcome recorded, which is what a refused statement looks like: it never reached the cache. Present so the five cache counts sum to entries and no statement is silently outside the breakdown.","format":"int64","type":"integer"},"cache_stale":{"description":"Served from cache while a refresh ran behind it.","format":"int64","type":"integer"},"credential_id":{"description":"The agent credential, or null on the unattributed and totals lines.","nullable":true,"type":"string"},"entries":{"description":"Audit entries of every kind, including ones carrying no decision. Not a statement count: a statement held for approval writes a progress row before its outcome, and a gap marker is not a statement at all.","format":"int64","type":"integer"},"first_seen":{"description":"First entry for this line. Null when the line covers no entries.","format":"date-time","nullable":true,"type":"string"},"last_seen":{"description":"Last entry for this line. Null when the line covers no entries.","format":"date-time","nullable":true,"type":"string"},"latency_measured":{"description":"Entries that ran and carried a finite latency, so they fed the percentiles and the total. Only the three executing decisions count: allowed, masked and truncated.","format":"int64","type":"integer"},"latency_ms_total":{"description":"Sum of finite latencies, in milliseconds.","format":"double","type":"number"},"latency_p50_ms":{"description":"Median finite latency. Zero when nothing was measured.","format":"double","type":"number"},"latency_p95_ms":{"description":"95th percentile finite latency. Zero when nothing was measured.","format":"double","type":"number"},"latency_p99_ms":{"description":"99th percentile finite latency. Zero when nothing was measured.","format":"double","type":"number"},"latency_unmeasured":{"description":"Entries excluded from the percentiles and the total, counted rather than dropped. Two kinds. Entries that never executed carry a literal zero latency because there was nothing to time: every refusal, the approval progress rows, and the gap markers. Including those would drag an agent's percentiles toward zero in proportion to how often it was refused, so the heavily blocked agent would report the fastest queries. Entries whose recorded latency was NaN or an infinity are excluded too, because in PostgreSQL NaN sorts above every other value and so corrupts the upper percentiles first and the sum unconditionally.","format":"int64","type":"integer"},"masked":{"description":"Statements that ran with a column mask applied.","format":"int64","type":"integer"},"rows_returned":{"description":"Rows returned to the client.","format":"int64","type":"integer"},"truncated":{"description":"Statements that ran and had their result capped.","format":"int64","type":"integer"}},"required":["entries","allowed","blocked","masked","truncated","rows_returned","bytes_out","cache_hit","cache_stale","cache_miss","cache_bypass","cache_none","latency_measured","latency_unmeasured","latency_ms_total","latency_p50_ms","latency_p95_ms","latency_p99_ms"],"type":"object"},"AgentUsageMarginalRates":{"description":"The organization's plan limits and marginal overage rates, resolved for both of the zero meanings a limit carries. Supplied as context for a caller that wants to price usage itself; this endpoint deliberately prices nothing.","properties":{"bytes_overage_billable":{"description":"True only when a bytes limit exists and overage past it was purchased.","type":"boolean"},"bytes_per_month":{"description":"Monthly transfer limit in bytes. Zero means no limit at all.","format":"int64","type":"integer"},"overage_per_1k_queries":{"description":"Rate per 1000 queries past the limit. Zero means the plan is a hard cap with no overage purchased, which is a different thing from no limit.","format":"double","type":"number"},"overage_per_gb":{"description":"Rate per GB past the limit. Zero means a hard cap with no overage.","format":"double","type":"number"},"plan":{"description":"Plan name the rates come from.","type":"string"},"queries_per_day":{"description":"Daily query limit. Zero means no limit at all, not a limit of zero.","format":"int64","type":"integer"},"query_overage_billable":{"description":"True only when a query limit exists and overage past it was purchased. Both gates resolved, so a caller cannot reproduce the bug where an organization with unlimited queries had its whole usage metered.","type":"boolean"}},"required":["plan","queries_per_day","bytes_per_month","overage_per_1k_queries","overage_per_gb","query_overage_billable","bytes_overage_billable"],"type":"object"},"AgentUsageReport":{"description":"Per-agent usage for one project over a window, derived from the audit trail. Reports usage, not money: see the endpoint description for why no dollar figure is attributed to an agent.","properties":{"agents":{"description":"One line per agent credential that appears in the window, busiest first. A credential with no traffic is absent rather than zero.","items":{"$ref":"#/components/schemas/AgentUsageLine"},"type":"array"},"complete":{"description":"False when the trail lost entries in this window, which means the totals below are a floor rather than a measurement. Derived from drop_markers, never assumed.","type":"boolean"},"drop_markers":{"$ref":"#/components/schemas/AgentUsageDropMarkers"},"marginal_rates":{"$ref":"#/components/schemas/AgentUsageMarginalRates"},"project_id":{"description":"Project the usage belongs to.","type":"string"},"requested_end":{"description":"End of the window that was actually queried, defaulting to now. The window is half-open, so an entry exactly at this instant is excluded. A window longer than 92 days is refused rather than truncated.","format":"date-time","type":"string"},"requested_start":{"description":"Start of the window that was actually queried. Echoed because both parameters are optional: omitting start defaults it to 30 days before the end, and a caller that did not ask for a window still needs to know which one it got before reading the totals as the whole picture.","format":"date-time","type":"string"},"totals":{"allOf":[{"$ref":"#/components/schemas/AgentUsageLine"}],"description":"The whole window. Equal to the sum of agents plus unattributed."},"unattributed":{"allOf":[{"$ref":"#/components/schemas/AgentUsageLine"}],"description":"Usage recorded against no credential: refused connections that never resolved one, control-plane sweep entries, and gap markers. Reported as its own line and never smeared across agents or dropped, so that the sum of agents plus unattributed equals totals exactly."},"window_end":{"description":"Last entry timestamp actually covered, not the requested end.","format":"date-time","type":"string"},"window_start":{"description":"First entry timestamp actually covered, not the requested start. Equal to window_end when the window held no entries.","format":"date-time","type":"string"}},"required":["project_id","requested_start","requested_end","window_start","window_end","complete","agents","unattributed","totals","marginal_rates","drop_markers"],"type":"object"},"AnomalyAlert":{"description":"A surfaced anomalous-behavior alert for review.","properties":{"acknowledged_at":{"description":"When the alert was acknowledged, if any.","format":"date-time","nullable":true,"type":"string"},"acknowledged_by":{"description":"User who acknowledged the alert, if any.","nullable":true,"type":"string"},"created_at":{"description":"When the alert was raised.","format":"date-time","type":"string"},"credential_id":{"description":"Agent credential implicated, if any.","nullable":true,"type":"string"},"details":{"additionalProperties":true,"description":"Structured details about the anomaly.","type":"object"},"id":{"description":"Unique anomaly alert identifier (prefixed).","example":"ano_01h455vb4pex5vsknk084sn02q","type":"string"},"kind":{"description":"Machine-readable anomaly kind (e.g. egress_spike, novel_query_shape).","type":"string"},"project_id":{"description":"Owning project ID.","type":"string"},"severity":{"description":"Alert severity.","enum":["info","warning","critical"],"type":"string"},"status":{"description":"Triage state of the alert.","enum":["open","acknowledged","resolved"],"type":"string"},"title":{"description":"Human-readable summary.","type":"string"},"window_end":{"description":"End of the observation window, if applicable.","format":"date-time","nullable":true,"type":"string"},"window_start":{"description":"Start of the observation window, if applicable.","format":"date-time","nullable":true,"type":"string"}},"required":["id","project_id","kind","severity","title","status","created_at"],"type":"object"},"ApprovalDecisionRequest":{"description":"Optional note attached to an approve/reject decision.","properties":{"reason":{"description":"Human-readable note explaining the decision.","maxLength":500,"type":"string"}},"type":"object"},"ApprovalRequest":{"description":"A statement held by the gateway awaiting a human approval decision.","properties":{"credential_id":{"description":"Agent credential that submitted the statement, if known.","nullable":true,"type":"string"},"decided_at":{"description":"When a decision was recorded, if any.","format":"date-time","nullable":true,"type":"string"},"decided_by":{"description":"User who decided, if any.","nullable":true,"type":"string"},"estimated_rows":{"description":"Best-effort estimate of how many rows the statement would affect, attached by the data plane when the statement was held. Either the planner estimate from EXPLAIN or the exact count observed in a rolled-back trial execution. Null when no estimate could be made; treat it as an estimate, not a guarantee.","format":"int64","nullable":true,"type":"integer"},"expires_at":{"description":"When the request expires if undecided.","format":"date-time","type":"string"},"id":{"description":"Unique approval request identifier (prefixed).","example":"apr_01h455vb4pex5vsknk084sn02q","type":"string"},"normalized_sql":{"description":"Statement with literals replaced by placeholders.","type":"string"},"policy_profile_id":{"description":"Policy profile that required approval.","type":"string"},"project_id":{"description":"Owning project ID.","type":"string"},"reason":{"description":"Human-readable note attached to a decision.","type":"string"},"region":{"description":"Data plane region that held the statement.","type":"string"},"requested_at":{"description":"When the statement was first held.","format":"date-time","type":"string"},"session_id":{"description":"Identifier grouping a connection's statements.","type":"string"},"sql":{"description":"The held statement text.","type":"string"},"statement_kind":{"description":"Parsed statement kind (e.g. update, delete, ddl).","type":"string"},"status":{"description":"Current state of the approval request.","enum":["pending","approved","rejected","expired","executed","failed"],"type":"string"},"target_tables":{"description":"Relations the statement touches, from the gateway's parse analysis.","items":{"type":"string"},"type":"array"}},"required":["id","project_id","policy_profile_id","sql","status","requested_at","expires_at"],"type":"object"},"Artifact":{"description":"Long-form agent output (a drafted email, an account brief) for human review.","properties":{"body":{"description":"Long-form content.","type":"string"},"created_at":{"description":"When the artifact was created.","format":"date-time","type":"string"},"id":{"description":"Unique artifact identifier.","example":"art_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"kind":{"description":"Kind of artifact (e.g. outreach_email, account_brief).","type":"string"},"org_id":{"description":"Organization the artifact belongs to.","type":"string"},"status":{"$ref":"#/components/schemas/ArtifactStatus"},"subject_id":{"description":"ID of the company/contact/deal this artifact is about.","type":"string"},"subject_type":{"$ref":"#/components/schemas/ResearchTaskSubjectType"},"task_id":{"description":"Research task that produced this artifact, if any.","nullable":true,"type":"string"},"title":{"description":"Short title.","type":"string"},"updated_at":{"description":"When the artifact was last updated.","format":"date-time","type":"string"}},"required":["id","org_id","subject_type","subject_id","kind","title","body","status","created_at","updated_at"],"type":"object"},"ArtifactStatus":{"description":"Lifecycle state of an artifact.","enum":["draft","approved","sent","discarded"],"type":"string"},"AuditChainVerification":{"description":"Result of recomputing the project's tamper-evident audit hash chain over a time range. The chain links each entry to its predecessor, so editing or deleting any row breaks it.","properties":{"chain_end_seq":{"description":"Sequence number of the last chained entry checked. Null when none.","format":"int64","nullable":true,"type":"integer"},"chain_start_seq":{"description":"Sequence number of the first chained entry checked. Null when none.","format":"int64","nullable":true,"type":"integer"},"failure_reason":{"description":"Machine-readable failure kind. Decided by the chain walk: hash_mismatch (entry content edited), broken_link (prev_hash does not match the predecessor), missing_entry (a sequence number was deleted), unknown_key (the entry was signed with a key this deployment does not hold, so it can be neither confirmed nor called tampered), key_downgrade (the chain ends in unsigned entries that follow a signed one with nothing signed after them, which is what truncating a signed chain and continuing it without the key looks like). Decided by the external anchor: truncated (the chain is shorter than a signed checkpoint says it was, which is entries deleted from the tip with nothing written after them), root_mismatch (the chain is long enough but its first checkpointed entries no longer produce the signed Merkle root, so the interior was rewritten), checkpoint_unverifiable (a stored checkpoint does not open under this deployment's anchor key, reported rather than skipped because an unverifiable claim is not an absent one). Null when ok.","nullable":true,"type":"string"},"first_broken_seq":{"description":"Sequence number where verification first failed (a tampered or deleted entry). Null when ok.","format":"int64","nullable":true,"type":"integer"},"keyed_count":{"description":"How many of the checked entries were signed with an HMAC key rather than hashed unkeyed. An unkeyed entry is still tamper-evident against anyone who cannot write to the database, but a writer can recompute it; a keyed one they cannot. Lower than verified_count over a range that predates the deployment's signing key.","format":"int64","type":"integer"},"ok":{"description":"True when every chained entry in the range links correctly and no tampering or deletion was detected.","type":"boolean"},"unchained_count":{"description":"Pre-chain (legacy) entries in the range that predate the hash chain and were skipped rather than treated as tampering.","format":"int64","type":"integer"},"verified_at":{"description":"When verification ran.","format":"date-time","type":"string"},"verified_count":{"description":"Number of chained entries checked.","format":"int64","type":"integer"}},"required":["ok","verified_count","keyed_count","unchained_count","verified_at"],"type":"object"},"AuditDecision":{"description":"Coarse outcome filter that groups audit events. `allow` = query; `block` = blocked, budget_exhausted, auth_failed, credential_expired, canary_tripped, rejected, approval_expired; `mask` = masked; `truncate` = truncated. The progress events approval_requested, approved and migration_flagged group under no decision: each belongs to a statement that goes on to record its own outcome, so grouping them would count that statement twice.","enum":["allow","block","mask","truncate"],"type":"string"},"AuditLogEntry":{"description":"One agent statement recorded by the gateway.","properties":{"bytes_out":{"description":"Bytes sent to the agent.","format":"int64","type":"integer"},"cache_status":{"description":"Cache outcome for the statement.","type":"string"},"client_ip":{"description":"Source IP of the agent connection.","type":"string"},"credential_id":{"description":"Agent credential that issued the statement, if known.","nullable":true,"type":"string"},"decision_rule":{"description":"Machine-readable rule that produced a block, if any.","type":"string"},"entry_hash":{"description":"Hex SHA-256 of this entry's canonical content chained onto prev_hash. Empty for pre-chain legacy entries.","type":"string"},"event":{"description":"Event type (query, blocked, masked, truncated, budget_exhausted, canary_tripped, rejected, approval_expired, auth_failed, credential_expired, approval_requested, approved, migration_flagged).","type":"string"},"id":{"description":"Unique audit entry identifier.","example":"aud_01h455vb4pex5vsknk084sn02q","type":"string"},"latency_ms":{"description":"Statement latency in milliseconds.","type":"number"},"normalized_sql":{"description":"Statement with literals replaced by placeholders.","type":"string"},"prev_hash":{"description":"Hex SHA-256 of the previous chained entry (a fixed genesis value for the first entry). Empty for pre-chain legacy entries.","type":"string"},"project_id":{"description":"Owning project ID.","type":"string"},"query_hash":{"description":"Hash of the normalized statement.","type":"string"},"reason":{"description":"Human-readable explanation of the decision.","type":"string"},"region":{"description":"Data plane region that served the statement.","type":"string"},"rows_returned":{"description":"Rows returned to the agent.","format":"int64","type":"integer"},"seq":{"description":"Monotonic per-project position in the tamper-evident hash chain.","format":"int64","type":"integer"},"session_id":{"description":"Identifier grouping a connection's statements.","type":"string"},"source":{"description":"Statement origin (wire, mcp, rest, or control for control-plane lifecycle events).","type":"string"},"sql":{"description":"The statement text (truncated).","type":"string"},"statement_kind":{"description":"Parsed statement kind.","type":"string"},"ts":{"description":"When the statement executed.","format":"date-time","type":"string"}},"required":["id","project_id","event","ts"],"type":"object"},"AuditSessionSummary":{"description":"Deterministic summary of one agent session's recorded statements: what it touched, how much it moved, and how often the policy engine stepped in. Computed from the project's audit log with no model in the loop, so the same entries always summarize the same way. Carries schema metadata (table names) and counts only, never row values.","properties":{"allowed":{"description":"Statements that ran unmodified (event `query`).","format":"int64","type":"integer"},"blocked":{"description":"Statements refused (events `blocked`, `budget_exhausted`, `auth_failed`, `credential_expired`), the same grouping the audit list's `block` decision filter uses.","format":"int64","type":"integer"},"bytes_out":{"description":"Bytes sent to the agent across the session.","format":"int64","type":"integer"},"credential_ids":{"description":"Agent credentials that issued statements in this session, sorted. A session normally has exactly one. More than one means the session ID was reused, because it is unique per connection within a proxy instance and not over time: narrow the window with start/end to separate them.","items":{"type":"string"},"type":"array"},"duration_ms":{"description":"Milliseconds between the first and last scanned entry.","type":"number"},"ended_at":{"description":"Timestamp of the session's last scanned entry.","format":"date-time","type":"string"},"entries_scanned":{"description":"Audit entries read for this session, including non-statement lifecycle events.","format":"int64","type":"integer"},"latency_ms_total":{"description":"Summed statement latency in milliseconds.","type":"number"},"masked":{"description":"Statements whose results had a column masked (event `masked`). One statement records one event, and truncation outranks masking, so a statement that was both masked and truncated counts under truncated only.","format":"int64","type":"integer"},"other":{"description":"Scanned entries carrying no statement decision, e.g. control-plane lifecycle events recorded against the session.","format":"int64","type":"integer"},"project_id":{"description":"Owning project ID.","type":"string"},"rows_returned":{"description":"Rows returned to the agent across the session.","format":"int64","type":"integer"},"scan_truncated":{"description":"True when the session has more entries than one summary reads. The counts and tables then cover the oldest entries in the window only; narrow it with start/end.","type":"boolean"},"session_id":{"description":"Identifier grouping the connection's statements.","example":"0000a41f","type":"string"},"sources":{"description":"Statement origins seen in the session (wire, mcp, rest, control), sorted.","items":{"type":"string"},"type":"array"},"started_at":{"description":"Timestamp of the session's first scanned entry.","format":"date-time","type":"string"},"statements":{"description":"Entries carrying a statement decision, the sum of allowed, blocked, masked and truncated.","format":"int64","type":"integer"},"tables_blocked":{"description":"Tables and views referenced by statements the policy engine refused, sorted. These were attempted, not read, which is why they are kept out of tables_read and tables_written.","items":{"type":"string"},"type":"array"},"tables_read":{"description":"Tables and views referenced by statements that executed as reads, sorted and schema-qualified when the statement qualified them.","items":{"type":"string"},"type":"array"},"tables_written":{"description":"Tables and views referenced by statements that executed as writes, sorted. A write that reads from another table (`UPDATE ... FROM`, a data-modifying CTE) lists that table here too: the audit record keeps the statement, not its write target, so the two cannot be told apart after the fact.","items":{"type":"string"},"type":"array"},"truncated":{"description":"Statements whose results hit a row cap (event `truncated`).","format":"int64","type":"integer"},"unparsed_statements":{"description":"Statements whose recorded SQL could not be parsed, because the audit writer truncated it or because it never parsed. Their tables are missing from the three table lists, so a non-zero count means those lists are incomplete.","format":"int64","type":"integer"}},"required":["session_id","project_id","credential_ids","sources","started_at","ended_at","duration_ms","entries_scanned","statements","allowed","blocked","masked","truncated","other","rows_returned","bytes_out","latency_ms_total","tables_read","tables_written","tables_blocked","unparsed_statements","scan_truncated"],"type":"object"},"AuditSource":{"description":"Statement origin (wire, mcp, rest, or control).","enum":["wire","mcp","rest","control"],"type":"string"},"BillingHealthSummary":{"description":"Aggregate billing health metrics grouped by plan and provider.","properties":{"entries":{"description":"Aggregate counts for each billing segment.","items":{"properties":{"billing_provider":{"description":"Billing provider for the segment.","type":"string"},"org_count":{"description":"Number of organizations in the segment.","format":"int64","type":"integer"},"plan":{"description":"Plan tier for the segment.","type":"string"},"subscription_status":{"description":"Subscription status for the segment.","type":"string"}},"required":["plan","billing_provider","subscription_status","org_count"],"type":"object"},"type":"array"}},"required":["entries"],"type":"object"},"CacheConfig":{"description":"Query cache configuration.","properties":{"enabled":{"default":true,"description":"Whether query caching is enabled. When false, all queries bypass the cache.","type":"boolean"},"max_entries":{"default":10000,"description":"Maximum number of cached query results.","maximum":1000000,"minimum":0,"type":"integer"},"swr_seconds":{"default":30,"description":"Stale-while-revalidate window in seconds.","maximum":86400,"minimum":0,"type":"integer"},"ttl_seconds":{"default":60,"description":"Cache TTL in seconds for query results.","maximum":86400,"minimum":0,"type":"integer"}},"required":["enabled","ttl_seconds","max_entries","swr_seconds"],"type":"object"},"CacheRuleEntry":{"description":"Observed query shape and its cache recommendation for a database.","properties":{"avg_latency_ms":{"description":"Average query latency in milliseconds.","format":"double","type":"number"},"avg_response_bytes":{"description":"Average response size in bytes.","format":"int64","type":"integer"},"cache_enabled":{"description":"Whether caching is enabled for this query shape.","type":"boolean"},"cache_swr_seconds":{"description":"SWR override in seconds. Null means use project default.","example":60,"minimum":0,"nullable":true,"type":"integer"},"cache_ttl_seconds":{"description":"TTL override in seconds. Null means use project default.","example":300,"minimum":0,"nullable":true,"type":"integer"},"call_count":{"description":"Total number of executions observed.","format":"int64","type":"integer"},"first_seen_at":{"description":"When this query was first observed.","format":"date-time","type":"string"},"last_seen_at":{"description":"When this query was last observed.","format":"date-time","type":"string"},"normalized_sql":{"description":"SQL with literals replaced by $N placeholders.","example":"SELECT * FROM users WHERE id = $1","type":"string"},"p95_latency_ms":{"description":"95th percentile latency in milliseconds.","format":"double","type":"number"},"query_hash":{"description":"xxhash64 hex of the normalized SQL.","example":"a1b2c3d4e5f60718","type":"string"},"query_type":{"description":"Query classification.","enum":["read","write","other"],"type":"string"},"recommendation":{"description":"Cache recommendation based on frequency, latency, and stability.","enum":["great","good","fair","poor"],"type":"string"},"stability_rate":{"description":"Response stability rate (0.0 to 1.0). Higher means more stable.","format":"double","type":"number"}},"required":["query_hash","normalized_sql","query_type","cache_enabled","call_count","avg_latency_ms","p95_latency_ms","avg_response_bytes","stability_rate","recommendation","first_seen_at","last_seen_at"],"type":"object"},"CacheSummary":{"description":"Aggregate cache performance metrics for the selected time range.","properties":{"hit_rate":{"description":"Cache hit rate as a fraction (0.0 to 1.0).","format":"double","type":"number"},"total_hits":{"description":"Total number of cache hits in the selected time range.","format":"int64","type":"integer"},"total_misses":{"description":"Total number of cache misses in the selected time range.","format":"int64","type":"integer"}},"required":["total_hits","total_misses","hit_rate"],"type":"object"},"CancellationFeedbackRequest":{"description":"Request body for capturing cancellation feedback from a user.","properties":{"feedback":{"description":"Free-text feedback from the user.","example":"Switching to a self-hosted solution.","type":"string"},"reason":{"description":"Predefined cancellation reason.","example":"too-expensive","type":"string"}},"type":"object"},"CidrEntry":{"description":"An IP filtering rule with a CIDR range and optional human-readable label.","properties":{"cidr":{"description":"CIDR range in IPv4 (e.g. 203.0.113.0/24) or IPv6 (e.g. 2001:db8::/32) notation. A plain IP without prefix length defaults to /32 (IPv4) or /128 (IPv6).\n","example":"10.0.0.0/8","pattern":"^[0-9a-fA-F.:]+(/[0-9]+)?$","type":"string"},"label":{"description":"Optional human-readable label for this CIDR entry (e.g. \"Office\", \"VPC\").","example":"Office network","maxLength":100,"type":"string"}},"required":["cidr"],"type":"object"},"Company":{"description":"A company (customer, prospect, or partner) tracked in the CRM.","properties":{"created_at":{"description":"When the company was created.","format":"date-time","type":"string"},"description":{"description":"Free-form description or research notes.","type":"string"},"domain":{"description":"Primary web domain, normalized to lowercase.","example":"acme.com","nullable":true,"type":"string"},"id":{"description":"Unique company identifier.","example":"cmp_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"industry":{"description":"Industry or sector the company operates in.","example":"Software","nullable":true,"type":"string"},"location":{"description":"Primary location (city, region, or country).","example":"San Francisco, CA","nullable":true,"type":"string"},"logo_url":{"description":"URL of the company logo.","nullable":true,"type":"string"},"name":{"description":"Company name.","example":"Acme Corp","type":"string"},"org_id":{"description":"Organization the company belongs to.","example":"org_abc123","type":"string"},"updated_at":{"description":"When the company was last updated.","format":"date-time","type":"string"}},"required":["id","org_id","name","description","created_at","updated_at"],"type":"object"},"CompanyInput":{"description":"Request body for creating or updating a company.","properties":{"description":{"description":"Free-form description or research notes.","maxLength":10000,"type":"string"},"domain":{"description":"Primary web domain.","example":"acme.com","maxLength":255,"nullable":true,"type":"string"},"industry":{"description":"Industry or sector.","maxLength":255,"nullable":true,"type":"string"},"location":{"description":"Primary location.","maxLength":255,"nullable":true,"type":"string"},"logo_url":{"description":"URL of the company logo.","maxLength":2048,"nullable":true,"type":"string"},"name":{"description":"Company name.","example":"Acme Corp","maxLength":255,"minLength":1,"type":"string"}},"required":["name"],"type":"object"},"ConsentRecord":{"description":"Persisted legal-consent record for a user.","properties":{"accepted_at":{"description":"When the document was accepted.","format":"date-time","type":"string"},"document_type":{"description":"Accepted legal document type.","type":"string"},"document_version":{"description":"Accepted document version.","type":"string"},"id":{"description":"Consent record identifier.","type":"string"},"ip_address":{"description":"IP address captured when consent was recorded.","type":"string"},"user_id":{"description":"User identifier the consent belongs to.","type":"string"}},"required":["id","user_id","document_type","document_version","accepted_at"],"type":"object"},"Contact":{"description":"A person tracked in the CRM, optionally attached to a company.","properties":{"company_id":{"description":"Company this contact belongs to, if any.","example":"cmp_01j9x8y7z6w5v4u3t2s1r0q9p8","nullable":true,"type":"string"},"created_at":{"description":"When the contact was created.","format":"date-time","type":"string"},"email":{"description":"Contact email address.","example":"jane@acme.com","nullable":true,"type":"string"},"id":{"description":"Unique contact identifier.","example":"cnt_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"linkedin_url":{"description":"LinkedIn profile URL.","nullable":true,"type":"string"},"name":{"description":"Contact full name.","example":"Jane Doe","type":"string"},"notes":{"description":"Free-form notes about the contact.","type":"string"},"org_id":{"description":"Organization the contact belongs to.","example":"org_abc123","type":"string"},"phone":{"description":"Phone number.","nullable":true,"type":"string"},"title":{"description":"Job title or role.","example":"VP Engineering","nullable":true,"type":"string"},"updated_at":{"description":"When the contact was last updated.","format":"date-time","type":"string"}},"required":["id","org_id","name","notes","created_at","updated_at"],"type":"object"},"ContactInput":{"description":"Request body for creating or updating a contact.","properties":{"company_id":{"description":"Company to attach this contact to, if any.","maxLength":255,"nullable":true,"type":"string"},"email":{"description":"Contact email address.","maxLength":320,"nullable":true,"type":"string"},"linkedin_url":{"description":"LinkedIn profile URL.","maxLength":2048,"nullable":true,"type":"string"},"name":{"description":"Contact full name.","maxLength":255,"minLength":1,"type":"string"},"notes":{"description":"Free-form notes about the contact.","maxLength":10000,"type":"string"},"phone":{"description":"Phone number.","maxLength":64,"nullable":true,"type":"string"},"title":{"description":"Job title or role.","maxLength":255,"nullable":true,"type":"string"}},"required":["name"],"type":"object"},"CreateAgentCredentialRequest":{"description":"Request body for issuing a new agent credential.","properties":{"expires_at":{"description":"Optional expiry. When set, the credential becomes unusable at this time (must be in the future). Omit or set null for a credential that never expires.","format":"date-time","nullable":true,"type":"string"},"name":{"description":"Human-readable label for the credential.","maxLength":128,"minLength":1,"type":"string"},"policy_profile_id":{"description":"The policy profile to enforce for this credential.","type":"string"},"principal_type":{"default":"agent","description":"Whether this credential represents an autonomous agent or a human operator.","enum":["agent","human"],"type":"string"}},"required":["name","policy_profile_id"],"type":"object"},"CreateCustomDomainRequest":{"description":"Request body for attaching a custom domain to a project.","properties":{"domain":{"description":"The custom domain name to add (e.g., db.example.com).","example":"db.example.com","maxLength":253,"minLength":1,"pattern":"^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$","type":"string"}},"required":["domain"],"type":"object"},"CreateDatabaseRequest":{"description":"Request body for registering an upstream database.","properties":{"auto_read_routing":{"default":false,"description":"Auto-route SELECT queries to read replicas.\n","type":"boolean"},"cache_config":{"$ref":"#/components/schemas/CacheConfig"},"host":{"description":"PostgreSQL host.","example":"db.example.com","minLength":1,"pattern":"^[^\\s\\x00]+$","type":"string"},"name":{"description":"PostgreSQL database name.","example":"mydb","minLength":1,"pattern":"^[^\\x00]+$","type":"string"},"password":{"description":"PostgreSQL password. Stored encrypted at rest.","format":"password","minLength":1,"pattern":"^[^\\x00]+$","type":"string","writeOnly":true},"pool_config":{"$ref":"#/components/schemas/PoolConfig"},"pool_region":{"description":"Region where the connection pool is maintained (near the database). When set and different from the client's edge region, queries are relayed through the pool region's data plane. Empty means direct connection.\n","example":"us-east-1","type":"string"},"port":{"description":"PostgreSQL port.","example":5432,"maximum":65535,"minimum":1,"type":"integer"},"query_timeout_ms":{"default":0,"description":"Query timeout in milliseconds. 0 means disabled (default).\n","maximum":300000,"minimum":0,"type":"integer"},"role":{"$ref":"#/components/schemas/DatabaseRole"},"ssl_mode":{"$ref":"#/components/schemas/SSLMode"},"username":{"description":"PostgreSQL username.","example":"pgbeam","minLength":1,"pattern":"^[^\\x00]+$","type":"string"}},"required":["host","port","name","username","password"],"type":"object"},"CreateProjectRequest":{"description":"Request body for creating a project and its primary database, which are created atomically.","properties":{"cloud":{"default":"aws","description":"Cloud provider for the project.","enum":["aws","azure","gcp"],"type":"string"},"database":{"$ref":"#/components/schemas/CreateDatabaseRequest"},"description":{"description":"Optional project description.","example":"Production database proxy","maxLength":500,"type":"string"},"name":{"description":"Human-readable project name.","example":"my-app","maxLength":100,"minLength":1,"pattern":"^[^\\x00]*$","type":"string"},"org_id":{"description":"Better Auth organization ID.","example":"org_abc123","minLength":1,"pattern":"^[^\\x00]+$","type":"string"},"self_hosted":{"default":false,"description":"Mark this project as running on a self-hosted (BYOC) data plane in the customer's own VPC/cluster. Requires the Scale or enterprise plan.\n","type":"boolean"},"tags":{"description":"User-defined labels to attach to the project.","example":["production","us-east-1"],"items":{"maxLength":50,"type":"string"},"maxItems":10,"type":"array"}},"required":["name","org_id","database"],"type":"object"},"CreateProjectResponse":{"description":"Response returned after creating a project and its primary database.","properties":{"database":{"$ref":"#/components/schemas/Database"},"project":{"$ref":"#/components/schemas/Project"}},"required":["project"],"type":"object"},"CreateReplicaRequest":{"description":"Request body for adding a read replica to a database.","properties":{"host":{"description":"PostgreSQL replica host.","example":"replica.us-west-2.rds.amazonaws.com","minLength":1,"pattern":"^[^\\s\\x00]+$","type":"string"},"port":{"description":"PostgreSQL replica port.","example":5432,"maximum":65535,"minimum":1,"type":"integer"},"ssl_mode":{"$ref":"#/components/schemas/SSLMode"}},"required":["host","port"],"type":"object"},"CreateSelfHostEnrollmentRequest":{"description":"Request body for issuing a self-host enrollment token.","properties":{"description":{"description":"Optional human-readable note.","example":"prod cluster","maxLength":500,"pattern":"^[^\\x00]*$","type":"string"},"expires_at":{"description":"Optional expiry. When set, the enrollment token stops authenticating new proxy connections at this time (must be in the future). Omit or set null for a token that never expires.","format":"date-time","nullable":true,"type":"string"},"region_label":{"description":"Operator-supplied label for where the proxy runs.","example":"customer-vpc-us-east","maxLength":100,"pattern":"^[^\\x00]*$","type":"string"}},"type":"object"},"CreateSupportCaseRequest":{"description":"Request body for creating a support case.","properties":{"body":{"description":"Initial message body.","maxLength":50000,"minLength":1,"type":"string"},"org_id":{"description":"Organization ID.","type":"string"},"severity":{"default":4,"description":"Severity level: 1=Critical, 2=High, 3=Normal, 4=Low.","maximum":4,"minimum":1,"type":"integer"},"title":{"description":"Brief summary of the issue.","maxLength":500,"minLength":1,"type":"string"}},"required":["org_id","title","body"],"type":"object"},"CreateSupportMessageRequest":{"description":"Request body for adding a message to a support case.","properties":{"body":{"description":"Message content.","maxLength":50000,"minLength":1,"type":"string"}},"required":["body"],"type":"object"},"CrmContext":{"description":"Shared per-org CRM context the research agent reads to ground its work.","properties":{"icp":{"description":"Ideal customer profile.","type":"string"},"notes":{"description":"Any other durable facts the agent should know.","type":"string"},"org_id":{"description":"Organization this context belongs to.","example":"org_abc123","type":"string"},"positioning":{"description":"How the org positions itself (one-liner or short paragraph).","type":"string"},"tone":{"description":"Preferred voice and tone for drafted content.","type":"string"},"updated_at":{"description":"When the context was last updated.","format":"date-time","type":"string"}},"required":["org_id","positioning","icp","tone","notes","updated_at"],"type":"object"},"CrmContextInput":{"description":"Request body for updating the org CRM context.","properties":{"icp":{"description":"Ideal customer profile.","maxLength":10000,"type":"string"},"notes":{"description":"Any other durable facts.","maxLength":20000,"type":"string"},"positioning":{"description":"How the org positions itself.","maxLength":10000,"type":"string"},"tone":{"description":"Preferred voice and tone.","maxLength":10000,"type":"string"}},"type":"object"},"CustomDomain":{"description":"Custom database hostname attached to a project.","properties":{"created_at":{"description":"When the custom domain was created.","format":"date-time","type":"string"},"dns_instructions":{"$ref":"#/components/schemas/DnsInstructions"},"dns_verification_token":{"description":"Token value for the DNS TXT record verification.","type":"string"},"domain":{"description":"The custom domain name.","example":"db.example.com","type":"string"},"id":{"description":"Unique domain identifier (prefixed).","example":"dom_01h455vb4pex5vsknk084sn02q","type":"string"},"project_id":{"description":"Owning project ID.","example":"prj_01h455vb4pex5vsknk084sn02q","type":"string"},"tls_cert_expiry":{"description":"When the TLS certificate expires.","format":"date-time","nullable":true,"type":"string"},"updated_at":{"description":"When the custom domain was last updated.","format":"date-time","type":"string"},"verified":{"description":"Whether DNS ownership has been verified.","type":"boolean"},"verified_at":{"description":"When DNS verification was completed.","format":"date-time","nullable":true,"type":"string"}},"required":["id","project_id","domain","verified","dns_verification_token","created_at","updated_at"],"type":"object"},"DailyUsage":{"description":"Daily usage totals aggregated across all projects in an organization.","properties":{"bytes_transferred":{"description":"Total bytes transferred to clients.","format":"int64","type":"integer"},"cache_hits":{"description":"Total cache hits on the day.","format":"int64","type":"integer"},"cache_misses":{"description":"Total cache misses on the day.","format":"int64","type":"integer"},"connection_seconds":{"description":"Total proxy connection time consumed on the day.","format":"int64","type":"integer"},"day":{"description":"Usage date in UTC.","format":"date","type":"string"},"queries_total":{"description":"Total queries served on the day.","format":"int64","type":"integer"}},"required":["day","queries_total","cache_hits","cache_misses","connection_seconds","bytes_transferred"],"type":"object"},"DataResidency":{"default":"any","description":"Data-residency requirement for the project. \"any\" (default) lets queries be served from the nearest data-plane metro. \"us\" or \"eu\" require the serving metro to be in that jurisdiction; the proxy fails a connection closed when it is served from a metro outside the required jurisdiction, so regulated workloads never process outside their permitted region.\n","enum":["any","us","eu"],"example":"eu","type":"string"},"Database":{"description":"Registered upstream PostgreSQL database for a project.","properties":{"auto_read_routing":{"default":false,"description":"When enabled and replicas are configured, SELECT queries automatically route to read replicas without requiring the @pgbeam:replica SQL annotation.\n","type":"boolean"},"cache_config":{"$ref":"#/components/schemas/CacheConfig"},"connection_string":{"description":"Connection string for connecting through PgBeam proxy. Password is replaced with a placeholder.","example":"postgresql://myuser:YOUR_PASSWORD@myproject.proxy.pgbeam.app:5432/mydb","readOnly":true,"type":"string"},"created_at":{"description":"When the database registration was created.","format":"date-time","type":"string"},"host":{"description":"PostgreSQL host.","example":"db.example.com","type":"string"},"id":{"description":"Unique database identifier (prefixed).","example":"db_01h455vb4pex5vsknk084sn02q","type":"string"},"name":{"description":"PostgreSQL database name.","example":"mydb","type":"string"},"pool_config":{"$ref":"#/components/schemas/PoolConfig"},"pool_region":{"description":"Region where the connection pool is maintained (near the database). When set and different from the client's edge region, queries are relayed through the pool region's data plane. Empty means direct connection.\n","example":"us-east-1","type":"string"},"port":{"description":"PostgreSQL port.","example":5432,"maximum":65535,"minimum":1,"type":"integer"},"project_id":{"description":"Owning project ID.","example":"prj_01h455vb4pex5vsknk084sn02q","type":"string"},"query_timeout_ms":{"default":0,"description":"Query timeout in milliseconds. When set (> 0), the proxy sends SET statement_timeout on upstream connections. 0 means disabled (default).\n","maximum":300000,"minimum":0,"type":"integer"},"role":{"$ref":"#/components/schemas/DatabaseRole"},"ssl_mode":{"$ref":"#/components/schemas/SSLMode"},"updated_at":{"description":"When the database registration was last updated.","format":"date-time","type":"string"},"username":{"description":"PostgreSQL username.","example":"pgbeam","type":"string"}},"required":["id","project_id","host","port","name","username","ssl_mode","cache_config","pool_config","created_at","updated_at"],"type":"object"},"DatabaseBranch":{"description":"An ephemeral sandbox branch of a database used for write isolation.","properties":{"branch_name":{"description":"Generated name for the branch.","type":"string"},"created_at":{"description":"When the branch was created.","format":"date-time","type":"string"},"credential_id":{"description":"Agent credential that requested the branch, if known.","nullable":true,"type":"string"},"database_id":{"description":"Database this branch was created from.","type":"string"},"discarded_at":{"description":"When the branch was discarded, if any.","format":"date-time","nullable":true,"type":"string"},"error":{"description":"Provisioning error, if any.","type":"string"},"expires_at":{"description":"When the branch expires, if set.","format":"date-time","nullable":true,"type":"string"},"id":{"description":"Unique sandbox branch identifier (prefixed).","example":"brn_01h455vb4pex5vsknk084sn02q","type":"string"},"session_id":{"description":"Identifier grouping a connection's statements.","type":"string"},"status":{"description":"Provisioning state of the branch.","enum":["pending","ready","error","discarded"],"type":"string"}},"required":["id","database_id","branch_name","status","created_at"],"type":"object"},"DatabaseRole":{"default":"primary","description":"Database role. Primary receives writes, replicas receive reads.","enum":["primary","replica"],"type":"string"},"Deal":{"description":"A revenue opportunity moving through the sales pipeline.","properties":{"amount_cents":{"description":"Deal value in the smallest currency unit (e.g. cents).","example":5000000,"format":"int64","type":"integer"},"close_date":{"description":"Expected or actual close date.","format":"date","nullable":true,"type":"string"},"company_id":{"description":"Company the deal is with, if any.","nullable":true,"type":"string"},"created_at":{"description":"When the deal was created.","format":"date-time","type":"string"},"currency":{"description":"ISO 4217 currency code.","example":"USD","type":"string"},"id":{"description":"Unique deal identifier.","example":"dl_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"org_id":{"description":"Organization the deal belongs to.","example":"org_abc123","type":"string"},"owner":{"description":"Deal owner (free-form, e.g. a user name or email).","type":"string"},"primary_contact_id":{"description":"Primary contact on the deal, if any.","nullable":true,"type":"string"},"stage":{"$ref":"#/components/schemas/DealStage"},"title":{"description":"Deal title.","example":"Acme - Platform expansion","type":"string"},"updated_at":{"description":"When the deal was last updated.","format":"date-time","type":"string"}},"required":["id","org_id","title","stage","amount_cents","currency","owner","created_at","updated_at"],"type":"object"},"DealInput":{"description":"Request body for creating or updating a deal.","properties":{"amount_cents":{"description":"Deal value in the smallest currency unit (e.g. cents).","format":"int64","minimum":0,"type":"integer"},"close_date":{"description":"Expected or actual close date.","format":"date","nullable":true,"type":"string"},"company_id":{"description":"Company the deal is with, if any.","maxLength":255,"nullable":true,"type":"string"},"currency":{"description":"ISO 4217 currency code.","example":"USD","maxLength":3,"minLength":3,"type":"string"},"owner":{"description":"Deal owner (free-form, e.g. a user name or email).","maxLength":255,"type":"string"},"primary_contact_id":{"description":"Primary contact on the deal, if any.","maxLength":255,"nullable":true,"type":"string"},"stage":{"$ref":"#/components/schemas/DealStage"},"title":{"description":"Deal title.","maxLength":255,"minLength":1,"type":"string"}},"required":["title"],"type":"object"},"DealStage":{"description":"Pipeline stage of a deal.","enum":["lead","qualified","proposal","negotiation","won","lost"],"type":"string"},"DnsInstructions":{"description":"DNS records the user needs to create for domain verification.","properties":{"acme_cname_host":{"description":"The CNAME record host for ACME TLS certificate issuance.","example":"_acme-challenge.db.example.com","type":"string"},"acme_cname_target":{"description":"The CNAME target for ACME challenge delegation.","example":"_acme-challenge.abc.proxy.pgbeam.app","type":"string"},"cname_host":{"description":"The CNAME record host.","example":"db.example.com","type":"string"},"cname_target":{"description":"The CNAME record target.","example":"abc.proxy.pgbeam.app","type":"string"},"txt_host":{"description":"The TXT record host for verification.","example":"_pgbeam-verify.db.example.com","type":"string"},"txt_value":{"description":"The TXT record value for verification.","example":"pgbeam-verify=abc123token","type":"string"}},"type":"object"},"DryEvalInput":{"description":"A SQL statement to test plus the policy to test it against. Supply exactly one of policy_id (an existing saved policy) or policy (an unsaved draft, e.g. the in-progress editor form).","properties":{"policy":{"$ref":"#/components/schemas/PolicyProfileInput"},"policy_id":{"description":"ID of an existing saved policy profile to evaluate against.","example":"pol_01h455vb4pex5vsknk084sn02q","type":"string"},"sql":{"description":"The single SQL statement to evaluate.","example":"SELECT email FROM users WHERE id = 1","maxLength":100000,"minLength":1,"type":"string"}},"required":["sql"],"type":"object"},"DryEvalMaskedColumn":{"description":"One result column that would be masked, with the mask kind applied.","properties":{"column":{"description":"The output column name (post-alias) the client would see masked.","example":"email","type":"string"},"kind":{"description":"How the column is masked.","enum":["redact","null","hash"],"type":"string"}},"required":["column","kind"],"type":"object"},"DryEvalResult":{"description":"The decision the proxy would reach for the supplied statement under the supplied policy. verdict is the headline outcome; the remaining fields detail why.","properties":{"hint":{"description":"What the author could do instead (present on block verdicts).","type":"string"},"masked_columns":{"description":"Result columns that would be masked. Present on mask/row-filter verdicts.","items":{"$ref":"#/components/schemas/DryEvalMaskedColumn"},"type":"array"},"notes":{"description":"Informational caveats about stateful enforcement a single-statement preview cannot model (per-region budgets, approvals, write-mode routing).","items":{"type":"string"},"type":"array"},"reason":{"description":"Human-readable explanation of the verdict.","type":"string"},"rewritten_sql":{"description":"The statement as it would be sent upstream after row-filter injection.","type":"string"},"row_filter_predicate":{"description":"The row-filter predicate ANDed into the statement's WHERE clause.","example":"tenant_id = current_setting('pgbeam.tenant')","type":"string"},"rule":{"description":"Machine-readable decision tag. For a block, the blocking rule (e.g. read_only, table_denied, table_not_allowed, statement_denied, row_filter_unsafe). Otherwise \"ok\".","example":"ok","type":"string"},"verdict":{"description":"allow — permitted unchanged; block — rejected; mask — permitted but listed result columns are masked; row-filter — permitted but a WHERE predicate is injected (and any listed columns are also masked).","enum":["allow","block","mask","row-filter"],"type":"string"}},"required":["verdict","rule","reason"],"type":"object"},"EnterprisePlanRequest":{"description":"Internal request body for assigning a custom enterprise plan.","properties":{"audit_retention_days":{"description":"Agent audit-log retention window in days.","minimum":1,"type":"integer"},"billing_provider":{"description":"Billing provider for the enterprise org.","enum":["stripe","manual"],"type":"string"},"bytes_per_month":{"description":"Monthly data transfer allowance in bytes. 0 means unlimited.","format":"int64","minimum":0,"type":"integer"},"included_seats":{"description":"Number of seats included in the enterprise plan.","minimum":1,"type":"integer"},"max_agent_credentials":{"description":"Maximum agent credentials for the enterprise plan. 0 means unlimited.","minimum":0,"type":"integer"},"max_connections":{"description":"Maximum concurrent connections allowed per project. 0 means unlimited.","minimum":0,"type":"integer"},"max_databases":{"description":"Maximum databases allowed per project.","minimum":1,"type":"integer"},"max_projects":{"description":"Maximum active projects allowed.","minimum":1,"type":"integer"},"max_query_shapes":{"description":"Maximum query shapes in cache rules. 0 means unlimited.","minimum":0,"type":"integer"},"org_id":{"description":"Organization identifier to update.","minLength":1,"type":"string"},"overage_per_1k":{"description":"Overage price in dollars per 1,000 queries.","format":"double","minimum":0,"type":"number"},"overage_per_gb":{"description":"Overage price in dollars per gigabyte transferred.","format":"double","minimum":0,"type":"number"},"queries_per_day":{"description":"Daily query allowance for the enterprise plan. 0 means unlimited.","format":"int64","minimum":0,"type":"integer"},"queries_per_second":{"description":"Maximum sustained queries per second per project. 0 means unlimited.","minimum":0,"type":"integer"}},"required":["org_id","billing_provider"],"type":"object"},"Error":{"description":"Standard error response envelope for PgBeam API requests.","properties":{"error":{"description":"Error metadata for the failed request.","properties":{"code":{"description":"Machine-readable error code.","type":"string"},"message":{"description":"Human-readable error message.","type":"string"}},"required":["code","message"],"type":"object"}},"required":["error"],"type":"object"},"GetSupportCaseResponse":{"description":"Support case with its message thread.","properties":{"case":{"$ref":"#/components/schemas/SupportCase"},"messages":{"description":"Messages in the support case thread.","items":{"$ref":"#/components/schemas/SupportMessage"},"type":"array"}},"required":["case","messages"],"type":"object"},"HealthResponse":{"description":"Health status and build metadata for the API service.","properties":{"image_sha":{"description":"Resolved image SHA (digest or SHA tag).","example":"f1f01eda9e1bc25a3a1d28b1e18c5579fa9a128fede12169d3a392504f9729e4","type":"string"},"status":{"description":"Overall service health.","enum":["ok","degraded"],"type":"string"},"timestamp":{"description":"Server time.","format":"date-time","type":"string"},"version":{"description":"API server version.","example":"1.0.0","type":"string"}},"required":["status","version","image_sha"],"type":"object"},"Honeytoken":{"description":"A decoy (canary) relation. Any agent statement that references it is blocked (fail closed) and recorded as a canary_tripped audit event.\n","properties":{"action":{"description":"Response when tripped. audit_only blocks the statement, records the event, and fires webhooks. kill additionally disables the tripping credential via the kill-switch.\n","enum":["audit_only","kill"],"type":"string"},"created_at":{"description":"When the honeytoken was registered.","format":"date-time","type":"string"},"id":{"description":"Unique honeytoken identifier.","example":"hnt_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"project_id":{"description":"Project the honeytoken belongs to.","example":"prj_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"relation_name":{"description":"Relation (table or view) name of the decoy.","example":"customer_ssns","type":"string"},"schema_name":{"description":"Optional schema. Null matches the unqualified/public form, mirroring the relation allowlist normalization.\n","example":"public","nullable":true,"type":"string"},"updated_at":{"description":"When the honeytoken was last updated.","format":"date-time","type":"string"}},"required":["id","project_id","relation_name","action","created_at","updated_at"],"type":"object"},"HoneytokenInput":{"description":"Request body for creating or updating a honeytoken.","properties":{"action":{"description":"Response when the honeytoken is tripped.","enum":["audit_only","kill"],"type":"string"},"relation_name":{"description":"Relation (table or view) name of the decoy.","example":"customer_ssns","maxLength":255,"minLength":1,"type":"string"},"schema_name":{"description":"Optional schema. Null or empty matches the unqualified/public form.","example":"public","maxLength":255,"nullable":true,"type":"string"}},"required":["relation_name","action"],"type":"object"},"LatencySummary":{"description":"Aggregate latency metrics for the selected time range.","properties":{"avg_ms":{"description":"Average latency in milliseconds across all queries.","format":"double","type":"number"},"p99_ms":{"description":"P99 latency in milliseconds across all queries.","format":"double","type":"number"}},"required":["avg_ms","p99_ms"],"type":"object"},"ListActivitiesResponse":{"description":"Most-recent-first activities for an organization.","properties":{"activities":{"description":"Activities, newest first.","items":{"$ref":"#/components/schemas/Activity"},"type":"array"}},"required":["activities"],"type":"object"},"ListAgentCredentialsResponse":{"description":"Cursor-paginated list of agent credentials for a project.","properties":{"agents":{"description":"Agent credentials on the current page.","items":{"$ref":"#/components/schemas/AgentCredential"},"type":"array"},"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"}},"required":["agents"],"type":"object"},"ListAnomalyAlertsResponse":{"description":"Cursor-paginated list of anomaly alerts for a project.","properties":{"anomalies":{"description":"Anomaly alerts on the current page.","items":{"$ref":"#/components/schemas/AnomalyAlert"},"type":"array"},"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"}},"required":["anomalies"],"type":"object"},"ListApprovalRequestsResponse":{"description":"Cursor-paginated list of approval requests for a project.","properties":{"approvals":{"description":"Approval requests on the current page.","items":{"$ref":"#/components/schemas/ApprovalRequest"},"type":"array"},"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"}},"required":["approvals"],"type":"object"},"ListArtifactsResponse":{"description":"Cursor-paginated artifacts for an organization.","properties":{"artifacts":{"description":"Artifacts returned for the current page.","items":{"$ref":"#/components/schemas/Artifact"},"type":"array"},"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"}},"required":["artifacts"],"type":"object"},"ListAuditLogsResponse":{"description":"Time-ordered page of audit entries (newest first).","properties":{"entries":{"description":"Audit entries on the current page.","items":{"$ref":"#/components/schemas/AuditLogEntry"},"type":"array"},"next_page_token":{"description":"Cursor for the next page. Empty if no more results.","type":"string"}},"required":["entries"],"type":"object"},"ListCacheRulesResponse":{"description":"Cursor-paginated cache-rule entries for a database.","properties":{"entries":{"description":"Query shapes returned for the current page.","items":{"$ref":"#/components/schemas/CacheRuleEntry"},"type":"array"},"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"}},"required":["entries"],"type":"object"},"ListCompaniesResponse":{"description":"Cursor-paginated companies for an organization.","properties":{"companies":{"description":"Companies returned for the current page.","items":{"$ref":"#/components/schemas/Company"},"type":"array"},"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"}},"required":["companies"],"type":"object"},"ListContactsResponse":{"description":"Cursor-paginated contacts for an organization.","properties":{"contacts":{"description":"Contacts returned for the current page.","items":{"$ref":"#/components/schemas/Contact"},"type":"array"},"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"}},"required":["contacts"],"type":"object"},"ListCustomDomainsResponse":{"description":"Cursor-paginated list of custom domains for a project.","properties":{"domains":{"description":"Custom domains on the current page.","items":{"$ref":"#/components/schemas/CustomDomain"},"type":"array"},"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"}},"required":["domains"],"type":"object"},"ListDatabaseBranchesResponse":{"description":"Cursor-paginated list of sandbox branches for a project.","properties":{"branches":{"description":"Sandbox branches on the current page.","items":{"$ref":"#/components/schemas/DatabaseBranch"},"type":"array"},"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"}},"required":["branches"],"type":"object"},"ListDatabasesResponse":{"description":"Cursor-paginated list of databases attached to a project.","properties":{"databases":{"description":"Databases on the current page.","items":{"$ref":"#/components/schemas/Database"},"type":"array"},"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"}},"required":["databases"],"type":"object"},"ListDealsResponse":{"description":"Cursor-paginated deals for an organization.","properties":{"deals":{"description":"Deals returned for the current page.","items":{"$ref":"#/components/schemas/Deal"},"type":"array"},"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"}},"required":["deals"],"type":"object"},"ListHoneytokensResponse":{"description":"Cursor-paginated honeytokens for a project.","properties":{"honeytokens":{"description":"Honeytokens returned for the current page.","items":{"$ref":"#/components/schemas/Honeytoken"},"type":"array"},"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"}},"required":["honeytokens"],"type":"object"},"ListOrganizationsResponse":{"description":"Organizations visible to the caller's credential.","properties":{"organizations":{"description":"Organizations the caller can access.","items":{"$ref":"#/components/schemas/OrganizationSummary"},"type":"array"}},"required":["organizations"],"type":"object"},"ListPlansResponse":{"description":"Response envelope for listing available billing plans.","properties":{"plans":{"description":"Billing plans available for self-serve signups.","items":{"$ref":"#/components/schemas/PlanInfo"},"type":"array"}},"required":["plans"],"type":"object"},"ListPolicyProfilesResponse":{"description":"Cursor-paginated list of policy profiles for a project.","properties":{"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"},"policies":{"description":"Policy profiles on the current page.","items":{"$ref":"#/components/schemas/PolicyProfile"},"type":"array"}},"required":["policies"],"type":"object"},"ListProjectsResponse":{"description":"Cursor-paginated list of projects for an organization.","properties":{"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"},"projects":{"description":"Projects on the current page.","items":{"$ref":"#/components/schemas/Project"},"type":"array"},"total":{"description":"Total number of projects (across all pages).","type":"integer"}},"required":["projects","total"],"type":"object"},"ListRegionsResponse":{"description":"Response envelope for available region queries.","properties":{"regions":{"description":"Regions currently known to the control plane.","items":{"$ref":"#/components/schemas/Region"},"type":"array"}},"required":["regions"],"type":"object"},"ListReplicasResponse":{"description":"Response envelope for listing registered replicas.","properties":{"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"},"replicas":{"description":"Read replicas attached to the database.","items":{"$ref":"#/components/schemas/Replica"},"type":"array"}},"required":["replicas"],"type":"object"},"ListResearchTasksResponse":{"description":"Cursor-paginated research tasks for an organization.","properties":{"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"},"tasks":{"description":"Research tasks returned for the current page.","items":{"$ref":"#/components/schemas/ResearchTask"},"type":"array"}},"required":["tasks"],"type":"object"},"ListSchemaAnnotationsResponse":{"description":"Cursor-paginated schema annotations for a project.","properties":{"annotations":{"description":"Annotations returned for the current page.","items":{"$ref":"#/components/schemas/SchemaAnnotation"},"type":"array"},"next_page_token":{"description":"Opaque token for cursor-based pagination.","type":"string"}},"required":["annotations"],"type":"object"},"ListSelfHostEnrollmentsResponse":{"description":"List of self-host enrollments for an organization.","properties":{"enrollments":{"description":"The organization's self-host enrollments, newest first.","items":{"$ref":"#/components/schemas/SelfHostEnrollment"},"type":"array"}},"required":["enrollments"],"type":"object"},"ListSupportCasesResponse":{"description":"Paginated list of support cases.","properties":{"cases":{"description":"Support cases for the current page.","items":{"$ref":"#/components/schemas/SupportCase"},"type":"array"},"total":{"description":"Total number of cases matching the filter.","format":"int64","type":"integer"}},"required":["cases","total"],"type":"object"},"ListWebhookEndpointsResponse":{"description":"Cursor-paginated list of webhook endpoints for a project.","properties":{"next_page_token":{"description":"Token for the next page. Empty if no more results.","type":"string"},"webhooks":{"description":"Webhook endpoints on the current page.","items":{"$ref":"#/components/schemas/WebhookEndpoint"},"type":"array"}},"required":["webhooks"],"type":"object"},"MaskingRule":{"description":"A column masking rule applied to agent query results.","properties":{"column":{"description":"Column to mask.","example":"email","type":"string"},"kind":{"description":"How to mask. redact replaces with a token, null returns NULL, hash returns a SHA-256 hex.","enum":["redact","null","hash"],"type":"string"},"table":{"description":"Relation name, optionally schema-qualified (e.g. \"public.users\" or \"users\").","example":"users","type":"string"}},"required":["table","column","kind"],"type":"object"},"MetricsSnapshot":{"description":"Aggregated project metrics captured for a point in time.","properties":{"active_connections":{"description":"Current active proxy connections.","type":"integer"},"avg_connect_ms":{"description":"Average upstream connection acquisition latency in milliseconds.","format":"double","type":"number"},"avg_latency_ms":{"description":"Average end-to-end query latency in milliseconds.","format":"double","type":"number"},"avg_query_ms":{"description":"Average upstream query execution latency in milliseconds.","format":"double","type":"number"},"cache_hits":{"description":"Number of queries served from cache.","format":"int64","type":"integer"},"cache_misses":{"description":"Number of queries forwarded upstream.","format":"int64","type":"integer"},"created_at":{"description":"When the snapshot was recorded.","format":"date-time","type":"string"},"id":{"description":"Unique metrics snapshot identifier.","type":"string"},"p99_latency_ms":{"description":"99th percentile end-to-end query latency in milliseconds.","format":"double","type":"number"},"project_id":{"description":"Project that produced the metrics snapshot.","type":"string"},"queries_total":{"description":"Total queries served during the snapshot interval.","format":"int64","type":"integer"},"region":{"description":"Region where the traffic was served.","type":"string"}},"required":["id","project_id","region","queries_total","cache_hits","cache_misses","active_connections","avg_latency_ms","p99_latency_ms","created_at"],"type":"object"},"MigrationFinding":{"description":"A single issue found while linting a migration.","properties":{"hint":{"description":"Suggested safer alternative, if any.","type":"string"},"message":{"description":"Human-readable description of the issue.","type":"string"},"rule":{"description":"Machine-readable rule identifier (e.g. drop_table, add_not_null_no_default).","type":"string"},"severity":{"description":"How serious the finding is. error indicates an unsafe change.","enum":["info","warning","error"],"type":"string"},"statement":{"description":"The statement that triggered the finding.","type":"string"}},"required":["severity","rule","message"],"type":"object"},"MigrationLintRequest":{"description":"A migration script to lint for unsafe schema changes.","properties":{"database_id":{"description":"Optional database to scope the lint to.","type":"string"},"sql":{"description":"The migration SQL to analyze. May contain multiple statements.","maxLength":1048576,"minLength":1,"type":"string"}},"required":["sql"],"type":"object"},"MigrationLintResponse":{"description":"Result of linting a migration script.","properties":{"findings":{"description":"Findings detected across all statements.","items":{"$ref":"#/components/schemas/MigrationFinding"},"type":"array"},"safe":{"description":"True when no error-severity findings were detected.","type":"boolean"}},"required":["safe","findings"],"type":"object"},"OnboardingProgress":{"description":"Progress state for the dashboard onboarding checklist.","properties":{"agent_credential_created":{"description":"Whether an agent credential has been issued.","type":"boolean"},"completed":{"description":"Whether all onboarding steps are complete.","type":"boolean"},"completed_at":{"description":"When onboarding was completed. Null if not yet completed.","format":"date-time","nullable":true,"type":"string"},"connection_string_copied":{"description":"Whether the connection string has been copied.","type":"boolean"},"connection_tested":{"description":"Whether the database connection has been tested.","type":"boolean"},"database_added":{"description":"Whether a database has been added.","type":"boolean"},"dismissed":{"description":"Whether the user has dismissed the onboarding checklist.","type":"boolean"},"first_query_run":{"description":"Whether the first query has been run through PgBeam.","type":"boolean"},"org_created":{"description":"Whether the organization has been created.","type":"boolean"},"organization_id":{"description":"Organization ID this onboarding belongs to.","type":"string"},"project_created":{"description":"Whether a project has been created.","type":"boolean"},"steps_completed":{"description":"Number of completed onboarding steps.","type":"integer"},"steps_total":{"description":"Total number of onboarding steps.","type":"integer"}},"required":["organization_id","org_created","project_created","database_added","connection_tested","connection_string_copied","first_query_run","agent_credential_created","dismissed","completed","steps_completed","steps_total"],"type":"object"},"OrganizationPlan":{"description":"Billing state and plan limits for an organization.","properties":{"billing_provider":{"description":"Which billing provider manages this organization's subscription.","enum":["stripe","vercel","aws","manual"],"type":"string"},"created_at":{"description":"When the billing record was created.","format":"date-time","type":"string"},"current_period_end":{"description":"End of current billing period.","format":"date-time","type":"string"},"custom_pricing":{"description":"Whether the organization has custom enterprise pricing.","type":"boolean"},"enabled":{"description":"Whether the organization billing is active (false = suspended).","type":"boolean"},"limits":{"$ref":"#/components/schemas/PlanLimits"},"org_id":{"description":"Organization identifier the plan applies to.","example":"org_abc123","type":"string"},"plan":{"description":"Current plan tier.","enum":["starter","pro","scale","enterprise"],"type":"string"},"spend_capped":{"description":"Whether the organization has hit its spend limit and agent access is paused at the proxy. Lifts automatically when usage resets for the new billing period, or immediately when the spend limit is raised or removed.","type":"boolean"},"spend_capped_at":{"description":"When the spend cap was applied. Null when not capped.","format":"date-time","nullable":true,"type":"string"},"spend_limit":{"description":"Monthly spend limit in dollars. Null means no limit.","example":500,"format":"double","nullable":true,"type":"number"},"subscription_status":{"description":"Stripe subscription status.","enum":["none","active","trialing","past_due","canceled","unpaid","incomplete","incomplete_expired","paused"],"type":"string"},"updated_at":{"description":"When the billing record was last updated.","format":"date-time","type":"string"}},"required":["org_id","plan","limits"],"type":"object"},"OrganizationSummary":{"description":"An organization visible to the caller's credential.","properties":{"id":{"description":"Organization identifier.","example":"org_abc123","type":"string"},"name":{"description":"Organization display name.","example":"Acme Corp","type":"string"},"role":{"description":"The caller's role within the organization. Omitted for organization-scoped API keys, which act as the organization itself rather than as a member.","example":"owner","type":"string"},"slug":{"description":"Organization slug used in URLs and routing.","example":"acme-corp","type":"string"}},"required":["id","name","slug"],"type":"object"},"PiiSuggestion":{"description":"A single likely-PII column detected by the scanner, with a recommended masking rule. Suggestions are advisory only — nothing is applied until the operator reviews and adds it to a policy profile.","properties":{"column":{"description":"The detected column name.","example":"email","type":"string"},"confidence":{"description":"Confidence score in [0,1]. Combines column-name signal and sampled-value signal; higher is stronger evidence.","example":0.95,"format":"float","maximum":1,"minimum":0,"type":"number"},"data_type":{"description":"PostgreSQL data type of the column.","example":"text","type":"string"},"mask_kind":{"description":"Recommended masking kind for this column. hash is suggested for join/group keys (e.g. email), redact for free-text PII, null for highly sensitive secrets.","enum":["redact","null","hash"],"type":"string"},"pii_type":{"description":"The kind of personally identifiable information detected.","enum":["email","phone","ssn","credit_card","ip_address","full_name","street_address","date_of_birth","national_id","passport","bank_account","api_secret","other"],"type":"string"},"reasons":{"description":"Human-readable explanations for why the column was flagged.","example":["column name matches 'email'","8/10 sampled values look like emails"],"items":{"type":"string"},"type":"array"},"sample_match_count":{"description":"Number of sampled non-null values that matched the PII pattern.","minimum":0,"type":"integer"},"sample_size":{"description":"Number of non-null values sampled from the column.","minimum":0,"type":"integer"},"schema":{"description":"Schema the column belongs to (e.g. \"public\").","example":"public","type":"string"},"table":{"description":"Table the column belongs to.","example":"users","type":"string"}},"required":["schema","table","column","data_type","pii_type","mask_kind","confidence","reasons"],"type":"object"},"PipelineStageSummary":{"description":"Aggregate deal count and value for a single pipeline stage.","properties":{"deal_count":{"description":"Number of deals in this stage.","format":"int64","type":"integer"},"stage":{"$ref":"#/components/schemas/DealStage"},"total_amount_cents":{"description":"Total value of deals in this stage, in minor currency units.","format":"int64","type":"integer"}},"required":["stage","deal_count","total_amount_cents"],"type":"object"},"PipelineSummaryResponse":{"description":"Deal count and total value per pipeline stage.","properties":{"stages":{"description":"One entry per stage that has at least one deal.","items":{"$ref":"#/components/schemas/PipelineStageSummary"},"type":"array"}},"required":["stages"],"type":"object"},"PlanInfo":{"description":"Publicly visible plan metadata and limits.","properties":{"annual_price":{"description":"Annual price in dollars (if applicable).","type":"integer"},"description":{"description":"Short description of the plan.","type":"string"},"label":{"description":"Display label for the plan.","type":"string"},"limits":{"$ref":"#/components/schemas/PlanLimits"},"monthly_price":{"description":"Monthly price in dollars.","type":"integer"},"name":{"description":"Plan tier name (starter, pro, scale).","type":"string"},"overage_text":{"description":"Human-readable overage pricing text.","type":"string"},"trial_days":{"description":"Number of trial days for new signups.","type":"integer"}},"required":["name","label","monthly_price","limits"],"type":"object"},"PlanLimits":{"description":"Effective usage limits enforced for an organization plan.","properties":{"audit_retention_days":{"description":"Agent audit-log retention window in days.","type":"integer"},"bytes_per_month":{"description":"Monthly data transfer quota in bytes. 0 means unlimited.","format":"int64","type":"integer"},"included_seats":{"description":"Number of seats included in the plan.","type":"integer"},"max_agent_credentials":{"description":"Maximum agent credentials per organization. 0 means unlimited.","type":"integer"},"max_connections":{"description":"Maximum concurrent connections per project.","type":"integer"},"max_databases":{"description":"Maximum databases per project.","type":"integer"},"max_projects":{"description":"Maximum number of active projects.","type":"integer"},"max_query_shapes":{"description":"Maximum query shapes in cache rules. 0 means unlimited.","type":"integer"},"queries_per_day":{"description":"Maximum queries per day across all projects. 0 means unlimited.","format":"int64","type":"integer"},"queries_per_second":{"description":"Maximum queries per second per project.","type":"integer"},"sandbox_idle_seconds":{"description":"Idle time before an instant (sandbox) branch scales to zero, in seconds.","type":"integer"},"sandbox_max_branches":{"description":"Maximum concurrently active instant (sandbox) branches. 0 means no limit.","type":"integer"},"sandbox_max_upstream_bytes":{"description":"Maximum upstream source-database size a sandbox base sync accepts, in bytes. 0 means no limit.","format":"int64","type":"integer"},"sandbox_ttl_seconds":{"description":"Lifetime of an instant (sandbox) branch before the TTL sweep discards it, in seconds.","type":"integer"}},"required":["queries_per_day","max_projects","max_databases","max_connections","queries_per_second","bytes_per_month","max_query_shapes","included_seats","max_agent_credentials","audit_retention_days","sandbox_max_branches","sandbox_max_upstream_bytes","sandbox_idle_seconds","sandbox_ttl_seconds"],"type":"object"},"PolicyProfile":{"description":"A named bundle of rules enforced on agent credentials in the data plane.","properties":{"access_mode":{"description":"read_only blocks all data and schema mutations.","enum":["read_only","read_write"],"type":"string"},"approval_auto_max_rows":{"default":0,"description":"Statements touching at most this many rows are auto-approved. 0 means none.","minimum":0,"type":"integer"},"approval_mode":{"default":"off","description":"Which statement classes require human approval before execution.","enum":["off","writes","ddl","all"],"type":"string"},"approval_timeout_seconds":{"default":300,"description":"How long a held statement waits for a decision before expiring.","minimum":0,"type":"integer"},"budget_queries_per_day":{"default":0,"description":"Max queries per day window. 0 means unlimited.","type":"integer"},"budget_queries_per_hour":{"default":0,"description":"Max queries per rolling hour window. 0 means unlimited.","type":"integer"},"created_at":{"description":"When the policy profile was created.","format":"date-time","type":"string"},"egress_bytes_per_day":{"default":0,"description":"Per-day egress budget in bytes. 0 means unlimited.","format":"int64","minimum":0,"type":"integer"},"id":{"description":"Unique policy profile identifier (prefixed).","example":"pol_01h455vb4pex5vsknk084sn02q","type":"string"},"masking_rules":{"description":"Column masking rules applied to query results.","items":{"$ref":"#/components/schemas/MaskingRule"},"type":"array"},"max_affected_rows":{"default":0,"description":"Hard cap on rows a single write (INSERT/UPDATE/DELETE) may affect. A write whose affected-row count would exceed this is executed inside a transaction, checked, and rolled back so nothing persists, then blocked. Enforced independently of human approval. 0 means unlimited.","minimum":0,"type":"integer"},"max_rows":{"default":0,"description":"Max rows returned per query. 0 means unlimited.","type":"integer"},"migration_safety":{"default":"off","description":"Migration safety mode. warn surfaces findings, block refuses unsafe DDL.","enum":["off","warn","block"],"type":"string"},"name":{"description":"Human-readable name for the policy profile.","example":"Read-only analytics","type":"string"},"project_id":{"description":"Owning project ID.","example":"prj_01h455vb4pex5vsknk084sn02q","type":"string"},"row_filters":{"description":"Per-relation row filters ANDed into agent reads.","items":{"$ref":"#/components/schemas/RowFilter"},"type":"array"},"statement_rules":{"$ref":"#/components/schemas/StatementRules"},"statement_timeout_ms":{"default":0,"description":"Upstream statement timeout for agent sessions. 0 uses the project default.","type":"integer"},"table_allowlist":{"description":"If non-empty, only these relations are reachable. Entries are schema-qualified (billing.orders) or bare (orders); a bare entry grants the public schema only, so the same table name in another schema must be listed in full.","items":{"description":"A relation name.","type":"string"},"type":"array"},"table_denylist":{"description":"Relations explicitly blocked (takes precedence over the allowlist). A bare entry blocks that relation in every schema.","items":{"description":"A relation name.","type":"string"},"type":"array"},"updated_at":{"description":"When the policy profile was last updated.","format":"date-time","type":"string"},"write_mode":{"default":"normal","description":"How writes are handled. normal commits, rollback auto-rolls back, sandbox routes to an ephemeral branch.","enum":["normal","rollback","sandbox"],"type":"string"}},"required":["id","project_id","name","access_mode","table_allowlist","table_denylist","masking_rules","created_at","updated_at"],"type":"object"},"PolicyProfileInput":{"description":"Mutable fields of a policy profile (used for create and update).","properties":{"access_mode":{"default":"read_only","description":"read_only blocks all data and schema mutations.","enum":["read_only","read_write"],"type":"string"},"approval_auto_max_rows":{"default":0,"description":"Statements touching at most this many rows are auto-approved. 0 means none.","minimum":0,"type":"integer"},"approval_mode":{"default":"off","description":"Which statement classes require human approval before execution.","enum":["off","writes","ddl","all"],"type":"string"},"approval_timeout_seconds":{"default":300,"description":"How long a held statement waits for a decision before expiring.","minimum":0,"type":"integer"},"budget_queries_per_day":{"default":0,"description":"Max queries per day window. 0 means unlimited.","minimum":0,"type":"integer"},"budget_queries_per_hour":{"default":0,"description":"Max queries per rolling hour window. 0 means unlimited.","minimum":0,"type":"integer"},"egress_bytes_per_day":{"default":0,"description":"Per-day egress budget in bytes. 0 means unlimited.","format":"int64","minimum":0,"type":"integer"},"masking_rules":{"description":"Column masking rules applied to query results.","items":{"$ref":"#/components/schemas/MaskingRule"},"type":"array"},"max_affected_rows":{"default":0,"description":"Hard cap on rows a single write (INSERT/UPDATE/DELETE) may affect. A write whose affected-row count would exceed this is executed inside a transaction, checked, and rolled back so nothing persists, then blocked. Enforced independently of human approval. 0 means unlimited.","minimum":0,"type":"integer"},"max_rows":{"default":0,"description":"Max rows returned per query. 0 means unlimited.","minimum":0,"type":"integer"},"migration_safety":{"default":"off","description":"Migration safety mode. warn surfaces findings, block refuses unsafe DDL.","enum":["off","warn","block"],"type":"string"},"name":{"description":"Human-readable name for the policy profile.","maxLength":128,"minLength":1,"type":"string"},"row_filters":{"description":"Per-relation row filters ANDed into agent reads.","items":{"$ref":"#/components/schemas/RowFilter"},"type":"array"},"statement_rules":{"$ref":"#/components/schemas/StatementRules"},"statement_timeout_ms":{"default":0,"description":"Upstream statement timeout for agent sessions. 0 uses the project default.","minimum":0,"type":"integer"},"table_allowlist":{"description":"If non-empty, only these relations are reachable. A bare entry grants the public schema only; list another schema in full, as in billing.orders.","items":{"description":"A relation name.","type":"string"},"type":"array"},"table_denylist":{"description":"Relations explicitly blocked. A bare entry blocks that relation in every schema.","items":{"description":"A relation name.","type":"string"},"type":"array"},"write_mode":{"default":"normal","description":"How writes are handled. normal commits, rollback auto-rolls back, sandbox routes to an ephemeral branch.","enum":["normal","rollback","sandbox"],"type":"string"}},"required":["name"],"type":"object"},"PolicyRecommendation":{"description":"A least-privilege policy derived from an agent credential's recorded audit history, together with the replay diff that proves the candidate would not newly block any statement the credential legitimately ran. Advisory only: this endpoint never creates, updates, or otherwise mutates a policy or a credential. A good recommendation has replay.summary.newly_blocked == 0.","properties":{"candidate":{"$ref":"#/components/schemas/PolicyProfileInput"},"message":{"description":"Present when sufficient_history is false; a clear explanation of why no recommendation could be produced (e.g. no executed traffic in the window).","type":"string"},"notes":{"description":"Human-readable rationale for each tightening decision (e.g. why the candidate was downgraded to read-only, or how max_rows was chosen).","items":{"type":"string"},"type":"array"},"observed_entries":{"description":"Recorded audit entries covered by the analyzed window.","format":"int64","type":"integer"},"observed_queries":{"description":"Distinct executed query shapes the candidate was derived from (blocked attempts are excluded from derivation).","type":"integer"},"replay":{"$ref":"#/components/schemas/PolicyReplayResult"},"sufficient_history":{"description":"True when there was enough parseable, executed traffic to derive a candidate. When false, candidate and replay are omitted and message explains why no recommendation could be made.","type":"boolean"},"window_end":{"description":"End of the analyzed traffic window (exclusive).","format":"date-time","type":"string"},"window_start":{"description":"Start of the analyzed traffic window (inclusive).","format":"date-time","type":"string"}},"required":["sufficient_history","observed_queries","observed_entries","window_start","window_end"],"type":"object"},"PolicyRecommendationInput":{"description":"Optional parameters for a least-privilege policy recommendation. Every field is optional; an empty body analyzes the last 30 days of the credential's audit history.","properties":{"limit":{"default":200,"description":"Maximum number of distinct query shapes to analyze and replay, newest first. Traffic is deduplicated by normalized query hash.","maximum":500,"minimum":1,"type":"integer"},"lookback_days":{"default":30,"description":"How many days of recorded audit history to analyze.","maximum":365,"minimum":1,"type":"integer"}},"type":"object"},"PolicyReplayInput":{"description":"A window of recorded agent traffic to replay plus the candidate policy to replay it against. Supply exactly one of policy_id (an existing saved policy) or policy (an unsaved draft, e.g. the in-progress editor form).","properties":{"bound_policy_id":{"description":"Restrict the replay to traffic recorded for the agent credentials currently bound to this policy profile. Use it to preview a change to a live policy against the traffic that policy actually governs: without it the replay covers every credential in the project, including credentials bound to other profiles, whose behaviour saving this candidate cannot change. Mutually exclusive with credential_id.","example":"pol_01h455vb4pex5vsknk084sn02q","type":"string"},"credential_id":{"description":"Restrict the replay to traffic recorded for one agent credential.","example":"cred_01h455vb4pex5vsknk084sn02q","type":"string"},"end_ts":{"description":"End of the traffic window (exclusive). Defaults to now.","format":"date-time","type":"string"},"limit":{"default":200,"description":"Maximum number of distinct queries to replay, newest first. Traffic is deduplicated by normalized query hash before evaluation.","maximum":500,"minimum":1,"type":"integer"},"policy":{"$ref":"#/components/schemas/PolicyProfileInput"},"policy_id":{"description":"ID of an existing saved policy profile to replay against.","example":"pol_01h455vb4pex5vsknk084sn02q","type":"string"},"start_ts":{"description":"Start of the traffic window (inclusive). Defaults to 7 days before end_ts.","format":"date-time","type":"string"}},"type":"object"},"PolicyReplayItem":{"description":"One distinct recorded query and the decision the candidate policy would reach for it.","properties":{"change":{"description":"How the candidate decision compares to the recorded outcome. newly_blocked and newly_allowed are the changes worth reviewing before rollout; still_allowed and still_blocked are unchanged.","enum":["newly_blocked","newly_allowed","still_allowed","still_blocked"],"type":"string"},"first_seen":{"description":"Oldest occurrence in the window.","format":"date-time","type":"string"},"last_seen":{"description":"Newest occurrence in the window.","format":"date-time","type":"string"},"occurrences":{"description":"How many recorded entries share this query shape in the window.","format":"int64","type":"integer"},"query_hash":{"description":"Normalized query hash identifying this statement shape.","type":"string"},"recorded_event":{"description":"The most recent recorded outcome for this query (query, masked, truncated, or blocked).","type":"string"},"recorded_rule":{"description":"The decision rule recorded with a blocked outcome.","type":"string"},"result":{"$ref":"#/components/schemas/DryEvalResult"},"sql":{"description":"The recorded statement (normalized, literals replaced with $N placeholders), from its most recent occurrence.","type":"string"},"statement_kind":{"description":"Statement kind (select, insert, update, delete, ddl, ...).","type":"string"}},"required":["query_hash","sql","occurrences","first_seen","last_seen","recorded_event","change","result"],"type":"object"},"PolicyReplayResult":{"description":"The outcome of replaying recorded agent traffic against a candidate policy: an aggregate summary plus per-query decisions, changes first.","properties":{"items":{"description":"Per-query replay decisions, ordered changes first (newly blocked, then newly allowed), then by occurrence count.","items":{"$ref":"#/components/schemas/PolicyReplayItem"},"type":"array"},"summary":{"$ref":"#/components/schemas/PolicyReplaySummary"}},"required":["summary","items"],"type":"object"},"PolicyReplaySummary":{"description":"Aggregate outcome of a policy replay.","properties":{"bound_credentials":{"description":"How many agent credentials are bound to bound_policy_id. Set only when traffic_scope is bound_credentials. Zero means the policy governs no credential today, so an empty replay is a statement about bindings and not evidence that the change is safe.","type":"integer"},"distinct_queries":{"description":"Distinct normalized queries found in the window (capped at limit).","type":"integer"},"entries_scanned":{"description":"Recorded audit entries covered by the replayed queries.","format":"int64","type":"integer"},"evaluated":{"description":"Distinct queries actually evaluated against the candidate policy.","type":"integer"},"newly_allowed":{"description":"Queries that were blocked when recorded but the candidate policy would permit.","type":"integer"},"newly_blocked":{"description":"Queries that executed under the recorded policy but the candidate policy would block.","type":"integer"},"skipped_unparseable":{"description":"Distinct queries skipped because the stored statement was truncated at record time and can no longer be parsed faithfully.","type":"integer"},"traffic_scope":{"description":"Which recorded traffic the replay covered. \"project\" is every credential in the project, so some replayed queries may belong to credentials this candidate policy does not govern. \"bound_credentials\" is only the credentials bound to bound_policy_id, which is what actually changes when that policy is saved.","enum":["project","bound_credentials"],"type":"string"},"truncated":{"description":"True when the window contained more distinct queries than limit; only the newest were replayed.","type":"boolean"},"would_allow":{"description":"Queries the candidate policy would allow unchanged.","type":"integer"},"would_block":{"description":"Queries the candidate policy would block.","type":"integer"},"would_mask":{"description":"Queries the candidate policy would mask result columns on.","type":"integer"},"would_row_filter":{"description":"Queries the candidate policy would inject a row filter into.","type":"integer"}},"required":["entries_scanned","distinct_queries","evaluated","would_allow","would_block","would_mask","would_row_filter","newly_blocked","newly_allowed","skipped_unparseable","truncated","traffic_scope"],"type":"object"},"PoolConfig":{"description":"Connection pool configuration.","properties":{"max_active":{"default":200,"description":"Maximum concurrent upstream connections per pool.","maximum":10000,"minimum":1,"type":"integer"},"min_pool_size":{"default":1,"description":"Minimum idle connections maintained.","example":5,"maximum":10000,"minimum":1,"type":"integer"},"pool_mode":{"$ref":"#/components/schemas/PoolMode"},"pool_size":{"default":10,"description":"Maximum connections in the pool.","example":20,"maximum":10000,"minimum":1,"type":"integer"}},"required":["pool_size","min_pool_size","pool_mode"],"type":"object"},"PoolMode":{"description":"Connection pool mode.","enum":["session","transaction","statement"],"example":"transaction","type":"string"},"Project":{"description":"Project configuration and current control-plane state.","properties":{"active_connections":{"description":"Current active connections (latest metrics snapshot). 0 when no metrics data.","readOnly":true,"type":"integer"},"agents_disabled":{"description":"Project-level kill-switch. When true, ALL agent-credential connections to this project are blocked at the proxy and live agent sessions are dropped within seconds. Passthrough/human connections are unaffected.\n","example":false,"type":"boolean"},"allowed_cidrs":{"description":"IP filtering rules as CIDR ranges with optional labels. When non-empty, only connections from matching IPs are accepted. Empty array means all IPs are allowed (default). Both IPv4 (e.g. 10.0.0.0/8) and IPv6 (e.g. 2001:db8::/32) are supported.\n","example":[{"cidr":"10.0.0.0/8","label":"VPC"},{"cidr":"2001:db8::/32","label":"IPv6 range"}],"items":{"$ref":"#/components/schemas/CidrEntry"},"maxItems":50,"type":"array"},"burst_size":{"description":"Burst allowance above the steady-state rate. 0 uses queries_per_second as burst.","example":200,"format":"int32","maximum":2147483647,"minimum":0,"readOnly":true,"type":"integer"},"cloud":{"description":"Cloud provider where the project runs.","enum":["aws","azure","gcp"],"readOnly":true,"type":"string"},"created_at":{"description":"When the project was created.","format":"date-time","type":"string"},"database_count":{"description":"Number of databases attached to this project.","readOnly":true,"type":"integer"},"default_policy_profile_id":{"description":"When set, passthrough/human connections are enforced against this policy profile.","example":"pol_01h455vb4pex5vsknk084sn02q","nullable":true,"type":"string"},"description":{"description":"Optional project description.","example":"Production database proxy","maxLength":500,"type":"string"},"id":{"description":"Unique project identifier (prefixed).","example":"prj_01h455vb4pex5vsknk084sn02q","type":"string"},"max_connections":{"description":"Maximum concurrent proxy connections. 0 means unlimited.","example":500,"format":"int32","maximum":2147483647,"minimum":0,"readOnly":true,"type":"integer"},"name":{"description":"Human-readable project name.","example":"my-app","maxLength":100,"minLength":1,"type":"string"},"org_id":{"description":"Better Auth organization ID that owns this project.","example":"org_abc123","type":"string"},"proxy_host":{"description":"Proxy hostname for connecting through PgBeam (e.g., myproject.proxy.pgbeam.app).","readOnly":true,"type":"string"},"queries_per_second":{"description":"Maximum queries per second for this project. 0 means unlimited.","example":1000,"format":"int32","maximum":2147483647,"minimum":0,"readOnly":true,"type":"integer"},"residency":{"$ref":"#/components/schemas/DataResidency"},"self_hosted":{"description":"When true, this project's data plane runs in the customer's own VPC/cluster (BYOC): the control plane does not provision hosted infra, and a self-hosted proxy dials home over the config/audit gRPC stream. Requires the Scale or enterprise plan.\n","example":false,"readOnly":true,"type":"boolean"},"status":{"$ref":"#/components/schemas/ProjectStatus"},"tags":{"description":"User-defined labels applied to the project.","example":["production","us-east-1"],"items":{"maxLength":50,"type":"string"},"maxItems":10,"type":"array"},"updated_at":{"description":"When the project was last updated.","format":"date-time","type":"string"}},"required":["id","org_id","name","status","created_at","updated_at"],"type":"object"},"ProjectDailyUsage":{"description":"Daily usage totals for a single project and region.","properties":{"bytes_transferred":{"description":"Total bytes transferred to clients.","format":"int64","type":"integer"},"cache_hits":{"description":"Total cache hits on the day.","format":"int64","type":"integer"},"cache_misses":{"description":"Total cache misses on the day.","format":"int64","type":"integer"},"connection_seconds":{"description":"Total proxy connection time consumed on the day.","format":"int64","type":"integer"},"day":{"description":"Usage date in UTC.","format":"date","type":"string"},"queries_total":{"description":"Total queries served on the day.","format":"int64","type":"integer"},"region":{"description":"Region where the traffic was served.","type":"string"}},"required":["day","region","queries_total","cache_hits","cache_misses","connection_seconds","bytes_transferred"],"type":"object"},"ProjectInsights":{"description":"Query insights, cache performance, and latency for a project.","properties":{"cache":{"$ref":"#/components/schemas/CacheSummary"},"latency":{"$ref":"#/components/schemas/LatencySummary"},"queries":{"description":"Top query shapes observed for the project.","items":{"$ref":"#/components/schemas/QueryInsight"},"type":"array"}},"required":["queries","cache","latency"],"type":"object"},"ProjectMetricsResponse":{"description":"Response envelope for recent project metrics snapshots.","properties":{"snapshots":{"description":"Metrics snapshots ordered from newest to oldest.","items":{"$ref":"#/components/schemas/MetricsSnapshot"},"type":"array"}},"required":["snapshots"],"type":"object"},"ProjectStatus":{"description":"Project lifecycle status.","enum":["active","suspended","deleted"],"type":"string"},"ProjectUsageResponse":{"description":"Response envelope for project usage queries.","properties":{"usage":{"description":"Daily usage entries grouped by region for the project.","items":{"$ref":"#/components/schemas/ProjectDailyUsage"},"type":"array"}},"required":["usage"],"type":"object"},"QueryInsight":{"description":"Aggregated analytics for a normalized SQL query shape.","properties":{"avg_latency_ms":{"description":"Average query latency in milliseconds.","format":"double","type":"number"},"p99_latency_ms":{"description":"P99 query latency in milliseconds.","format":"double","type":"number"},"query_hash":{"description":"xxhash64 of the normalized SQL pattern (hex).","type":"string"},"query_pattern":{"description":"Normalized SQL pattern (truncated to 500 chars).","type":"string"},"total_cache_hits":{"description":"Total cache hits attributed to the query shape.","format":"int64","type":"integer"},"total_cache_misses":{"description":"Total cache misses attributed to the query shape.","format":"int64","type":"integer"},"total_count":{"description":"Total number of executions in the time range.","format":"int64","type":"integer"}},"required":["query_hash","query_pattern","total_count","total_cache_hits","total_cache_misses","avg_latency_ms","p99_latency_ms"],"type":"object"},"ReconcileResponse":{"description":"Result summary for an internal billing reconciliation run.","properties":{"orgs_checked":{"description":"Number of organizations inspected during reconciliation.","type":"integer"},"orgs_updated":{"description":"Number of organizations whose billing state changed.","type":"integer"},"status":{"description":"Result of the reconciliation run.","type":"string"}},"required":["status"],"type":"object"},"RecordConsentRequest":{"description":"Request body for recording acceptance of a legal document.","properties":{"document_type":{"description":"Legal document that was accepted.","enum":["terms_of_service","privacy_policy"],"type":"string"},"document_version":{"description":"Version of the accepted document.","minLength":1,"type":"string"},"ip_address":{"description":"IP address captured when consent was recorded.","type":"string"},"user_id":{"description":"User identifier the consent applies to.","minLength":1,"type":"string"}},"required":["user_id","document_type","document_version"],"type":"object"},"Region":{"description":"Data plane region available for PgBeam traffic.","properties":{"available":{"description":"Whether new projects can currently be assigned to the region.","type":"boolean"},"continent":{"description":"Continent where the region is located.","type":"string"},"country":{"description":"Country where the region is located.","type":"string"},"id":{"description":"Region identifier (e.g. us-east-1).","example":"us-east-1","type":"string"},"name":{"description":"Human-readable region name.","example":"US East (N. Virginia)","type":"string"},"provider":{"description":"Cloud provider.","enum":["aws","azure","gcp"],"example":"aws","type":"string"},"status":{"description":"Region operational status.","enum":["active","draining","inactive"],"type":"string"}},"required":["id","name","provider","status","available"],"type":"object"},"Replica":{"description":"Read replica registered for a primary database.","properties":{"created_at":{"description":"When the replica was created.","format":"date-time","type":"string"},"database_id":{"description":"Parent database ID.","example":"db_01h455vb4pex5vsknk084sn02q","type":"string"},"host":{"description":"PostgreSQL replica host.","example":"replica.db.example.com","type":"string"},"id":{"description":"Unique replica identifier (prefixed).","example":"rep_01h455vb4pex5vsknk084sn02q","type":"string"},"port":{"description":"PostgreSQL replica port.","example":5432,"maximum":65535,"minimum":1,"type":"integer"},"ssl_mode":{"$ref":"#/components/schemas/SSLMode"},"updated_at":{"description":"When the replica was last updated.","format":"date-time","type":"string"}},"required":["id","database_id","host","port","ssl_mode","created_at","updated_at"],"type":"object"},"ResearchTask":{"description":"A unit of work for the autonomous research agent. Workers lease pending tasks from the queue, do the work (enrichment), and write the result back.\n","properties":{"approved_at":{"description":"When the task was approved, if it required approval.","format":"date-time","nullable":true,"type":"string"},"attempts":{"description":"Number of attempts made so far.","type":"integer"},"created_at":{"description":"When the task was enqueued.","format":"date-time","type":"string"},"error":{"description":"Last error message, if the task has failed attempts.","type":"string"},"id":{"description":"Unique research task identifier.","example":"ctk_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"kind":{"$ref":"#/components/schemas/ResearchTaskKind"},"max_attempts":{"description":"Maximum attempts before the task is terminal.","type":"integer"},"org_id":{"description":"Organization the task belongs to.","example":"org_abc123","type":"string"},"priority":{"description":"Higher runs first.","type":"integer"},"requires_approval":{"description":"Whether this task is held for human approval before it runs.","type":"boolean"},"role":{"$ref":"#/components/schemas/AgentRole"},"status":{"$ref":"#/components/schemas/ResearchTaskStatus"},"subject_id":{"description":"ID of the company/contact/deal this task targets.","type":"string"},"subject_type":{"$ref":"#/components/schemas/ResearchTaskSubjectType"},"updated_at":{"description":"When the task was last updated.","format":"date-time","type":"string"}},"required":["id","org_id","kind","status","role","requires_approval","subject_type","subject_id","priority","attempts","max_attempts","created_at","updated_at"],"type":"object"},"ResearchTaskInput":{"description":"Request body for enqueuing a research task.","properties":{"kind":{"$ref":"#/components/schemas/ResearchTaskKind"},"priority":{"default":0,"description":"Higher runs first.","type":"integer"},"role":{"$ref":"#/components/schemas/AgentRole"},"subject_id":{"description":"ID of the company/contact/deal this task targets.","maxLength":255,"minLength":1,"type":"string"},"subject_type":{"$ref":"#/components/schemas/ResearchTaskSubjectType"}},"required":["kind","subject_type","subject_id"],"type":"object"},"ResearchTaskKind":{"description":"What the research agent should do for this task.","enum":["enrich_company","enrich_contact","research_deal","draft_outreach","custom"],"type":"string"},"ResearchTaskStatus":{"description":"Lifecycle state of a research task. awaiting_approval means the task is an irreversible action held for a human approval before it runs.\n","enum":["pending","leased","done","failed","canceled","awaiting_approval"],"type":"string"},"ResearchTaskSubjectType":{"description":"The kind of entity a research task targets.","enum":["company","contact","deal"],"type":"string"},"RowFilter":{"description":"A per-relation row filter. The predicate is a raw SQL boolean expression ANDed into the WHERE clause for the matching relation.","properties":{"predicate":{"description":"Raw SQL boolean expression ANDed into WHERE for this relation.","example":"tenant_id = current_setting('pgbeam.tenant')","type":"string"},"table":{"description":"Relation name, optionally schema-qualified (e.g. \"public.orders\").","example":"orders","type":"string"}},"required":["table","predicate"],"type":"object"},"SSLMode":{"description":"PostgreSQL SSL connection mode.","enum":["disable","allow","prefer","require","verify-ca","verify-full"],"example":"require","type":"string"},"ScanPiiResult":{"description":"Result of a PII detection scan over a database's schema.","properties":{"error":{"description":"Present when the scan failed to connect or read the schema.","type":"string"},"scanned_columns":{"description":"Number of columns inspected.","minimum":0,"type":"integer"},"scanned_tables":{"description":"Number of tables inspected.","minimum":0,"type":"integer"},"suggestions":{"description":"Ranked masking suggestions, highest confidence first. Empty when no likely-PII columns were found.","items":{"$ref":"#/components/schemas/PiiSuggestion"},"type":"array"},"truncated":{"description":"True when the scan stopped early at the column limit and some columns were not inspected.","type":"boolean"}},"required":["scanned_columns","scanned_tables","suggestions"],"type":"object"},"SchemaAnnotation":{"description":"A human-written description for a table or column, attached by a project operator and surfaced through the agent-facing MCP catalog. When present it takes precedence over the DB-native comment for the same relation or column.\n","properties":{"column_name":{"description":"Optional column. Null means the annotation describes the table itself.\n","example":"email","nullable":true,"type":"string"},"created_at":{"description":"When the annotation was created.","format":"date-time","type":"string"},"description":{"description":"The operator-written description text.","example":"Primary customer account. One row per signed-up user.","type":"string"},"id":{"description":"Unique annotation identifier.","example":"sca_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"project_id":{"description":"Project the annotation belongs to.","example":"prj_01j9x8y7z6w5v4u3t2s1r0q9p8","type":"string"},"schema_name":{"description":"Optional schema. Null matches the unqualified form, mirroring the relation allowlist normalization.\n","example":"public","nullable":true,"type":"string"},"table_name":{"description":"Relation (table or view) the annotation describes.","example":"users","type":"string"},"updated_at":{"description":"When the annotation was last updated.","format":"date-time","type":"string"}},"required":["id","project_id","table_name","description","created_at","updated_at"],"type":"object"},"SchemaAnnotationInput":{"description":"Request body for creating or replacing a schema annotation. Keyed by (schema_name, table_name, column_name); an existing annotation with the same key is replaced.\n","properties":{"column_name":{"description":"Optional column. Null describes the table itself.","example":"email","maxLength":255,"nullable":true,"type":"string"},"description":{"description":"The operator-written description text.","example":"Primary customer account. One row per signed-up user.","maxLength":4096,"minLength":1,"type":"string"},"schema_name":{"description":"Optional schema. Null or empty matches the unqualified form.","example":"public","maxLength":255,"nullable":true,"type":"string"},"table_name":{"description":"Relation (table or view) the annotation describes.","example":"users","maxLength":255,"minLength":1,"type":"string"}},"required":["table_name","description"],"type":"object"},"SchemaCatalog":{"description":"A read-only snapshot of a database's user relations (tables and views) and their columns, used to power table/column autocomplete and view-aware warnings in the policy editor. System schemas (pg_catalog, information_schema, pg_toast) are excluded.","properties":{"error":{"description":"Present when introspection failed to connect or read the schema.","type":"string"},"relations":{"description":"User relations, ordered by schema then name.","items":{"$ref":"#/components/schemas/SchemaCatalogRelation"},"type":"array"},"scanned_columns":{"description":"Number of columns in the catalog.","minimum":0,"type":"integer"},"scanned_relations":{"description":"Number of relations in the catalog.","minimum":0,"type":"integer"},"truncated":{"description":"True when the catalog stopped early at the column limit.","type":"boolean"}},"required":["relations","scanned_relations","scanned_columns"],"type":"object"},"SchemaCatalogColumn":{"description":"One column of a relation in the schema catalog.","properties":{"data_type":{"description":"PostgreSQL data type (information_schema.data_type).","example":"text","type":"string"},"is_binary":{"description":"True for binary-typed columns (e.g. bytea). Masking a binary column always returns NULL — a redact/hash token would corrupt the wire type — so the editor warns when a masking rule targets one.","type":"boolean"},"name":{"description":"Column name.","example":"email","type":"string"}},"required":["name","data_type","is_binary"],"type":"object"},"SchemaCatalogRelation":{"description":"One relation (base table or view) in the schema catalog.","properties":{"columns":{"description":"The relation's columns.","items":{"$ref":"#/components/schemas/SchemaCatalogColumn"},"type":"array"},"kind":{"description":"Relation kind. Allowlists, masking, and row-filters are enforced against the named relation itself, NOT through a view to its base tables — so a view over a row-filtered base table can leak. The editor warns when a policy entry targets a view.","enum":["table","view","materialized_view","other"],"type":"string"},"name":{"description":"Relation name.","example":"users","type":"string"},"schema":{"description":"Schema the relation belongs to.","example":"public","type":"string"}},"required":["schema","name","kind","columns"],"type":"object"},"SelfHostEnrollment":{"description":"An enrollment that lets a self-hosted (BYOC) proxy authenticate to the control plane's config/audit gRPC stream on behalf of an organization. The token itself is never returned after creation, only its metadata.\n","properties":{"created_at":{"description":"When the enrollment was created.","format":"date-time","type":"string"},"created_by":{"description":"User ID that created the enrollment.","nullable":true,"type":"string"},"description":{"description":"Optional human-readable note.","example":"prod cluster","type":"string"},"expires_at":{"description":"When the enrollment token expires and stops authenticating new proxy connections. Null means it never expires. Enforcement is fail-closed at the gRPC auth gate the instant this time passes.","format":"date-time","nullable":true,"type":"string"},"id":{"description":"Unique enrollment identifier.","example":"she_01h455vb4pex5vsknk084sn02q","type":"string"},"last_seen_at":{"description":"Last time a proxy authenticated with this enrollment.","format":"date-time","nullable":true,"type":"string"},"org_id":{"description":"Organization that owns this enrollment.","example":"org_abc123","type":"string"},"region_label":{"description":"Operator-supplied label for where the proxy runs (informational).","example":"customer-vpc-us-east","type":"string"},"revoked_at":{"description":"When the enrollment was revoked. Null means active.","format":"date-time","nullable":true,"type":"string"}},"required":["id","org_id","created_at"],"type":"object"},"SelfHostEnrollmentSecret":{"description":"Response returned once when an enrollment is created or its token is rotated. The token is shown a single time and cannot be retrieved again; set it as GRPC_AUTH_TOKEN on the self-hosted proxy.\n","properties":{"enrollment":{"$ref":"#/components/schemas/SelfHostEnrollment"},"token":{"description":"The plaintext enrollment token (pbh_...). Shown once.","example":"pbh_01h455vb4pex5vsknk084sn02q9zk3m7","type":"string"}},"required":["enrollment","token"],"type":"object"},"SlackEventPayload":{"description":"Slack event forwarded from the dashboard webhook handler.","properties":{"channel_id":{"description":"Slack channel ID where the message was posted.","type":"string"},"text":{"description":"Message text from Slack.","type":"string"},"thread_ts":{"description":"Slack thread timestamp identifying the support case thread.","type":"string"},"user_id":{"description":"Slack user ID of the message author.","type":"string"}},"required":["channel_id","thread_ts","user_id","text"],"type":"object"},"StatementRules":{"description":"Per-statement-kind allow/deny lists. Empty allow means all kinds permitted by the access mode.","properties":{"allow":{"description":"Allowed statement kinds (select, insert, update, delete, ddl, copy, set, show, explain, transaction).","items":{"description":"A statement kind.","type":"string"},"type":"array"},"deny":{"description":"Denied statement kinds (takes precedence over allow).","items":{"description":"A statement kind.","type":"string"},"type":"array"}},"type":"object"},"SupportCase":{"description":"A support case filed by an organization member.","properties":{"case_number":{"description":"Human-readable sequential case number.","readOnly":true,"type":"integer"},"closed_at":{"description":"When the case was closed, if applicable.","format":"date-time","nullable":true,"type":"string"},"created_at":{"description":"When the case was created.","format":"date-time","type":"string"},"id":{"description":"Unique support case identifier (prefixed).","example":"sc_01h455vb4pex5vsknk084sn02q","type":"string"},"message_count":{"description":"Number of messages in the case.","format":"int64","readOnly":true,"type":"integer"},"org_id":{"description":"Organization that owns this case.","type":"string"},"severity":{"description":"Severity level: 1=Critical, 2=High, 3=Normal, 4=Low.","maximum":4,"minimum":1,"type":"integer"},"slack_channel_id":{"description":"Slack channel where the case thread lives.","type":"string"},"slack_thread_ts":{"description":"Slack thread timestamp for the case.","type":"string"},"status":{"$ref":"#/components/schemas/SupportCaseStatus"},"title":{"description":"Brief summary of the issue.","type":"string"},"updated_at":{"description":"When the case was last updated.","format":"date-time","type":"string"},"user_id":{"description":"User who created the case.","type":"string"}},"required":["id","case_number","org_id","user_id","title","severity","status","created_at","updated_at"],"type":"object"},"SupportCaseStatus":{"description":"Current status of the support case.","enum":["open","closed"],"type":"string"},"SupportMessage":{"description":"A message within a support case thread.","properties":{"author_image":{"description":"URL to the author's avatar.","nullable":true,"type":"string"},"author_name":{"description":"Display name of the message author.","type":"string"},"body":{"description":"Message content.","type":"string"},"case_id":{"description":"Parent support case ID.","type":"string"},"created_at":{"description":"When the message was created.","format":"date-time","type":"string"},"id":{"description":"Unique message identifier (prefixed).","example":"sm_01h455vb4pex5vsknk084sn02q","type":"string"},"slack_user_id":{"description":"Slack user ID (for Slack-sourced messages).","nullable":true,"type":"string"},"source":{"$ref":"#/components/schemas/SupportMessageSource"}},"required":["id","case_id","source","author_name","body","created_at"],"type":"object"},"SupportMessageSource":{"description":"Origin of the message.","enum":["user","slack"],"type":"string"},"SyncPlanRequest":{"description":"Internal request body for syncing a subscription plan from the dashboard.","properties":{"org_id":{"description":"Organization identifier to update.","minLength":1,"type":"string"},"plan":{"description":"Plan tier to apply.","enum":["starter","pro","scale"],"type":"string"},"status":{"description":"Current subscription lifecycle status.","enum":["none","active","trialing","past_due","canceled","unpaid","incomplete","incomplete_expired","paused"],"type":"string"},"stripe_customer_id":{"description":"Stripe customer identifier, if billing is managed in Stripe.","type":"string"},"stripe_subscription_id":{"description":"Stripe subscription identifier, if present.","type":"string"}},"required":["org_id","plan","status"],"type":"object"},"SyncPlanResponse":{"description":"Result returned after syncing subscription state from the dashboard.","properties":{"status":{"description":"Result of the sync operation (synced, skipped_custom_pricing).","type":"string"}},"required":["status"],"type":"object"},"TestConnectionResult":{"description":"Result of testing connectivity to an upstream database.","properties":{"error":{"description":"Error message if the connection test failed.","type":"string"},"latency_ms":{"description":"Round-trip connection time in milliseconds.","nullable":true,"type":"number"},"ok":{"description":"Whether the connection test succeeded.","type":"boolean"},"server_version":{"description":"PostgreSQL server version string, if available.","type":"string"}},"required":["ok"],"type":"object"},"UpdateAgentCredentialStatusRequest":{"description":"Request body for enabling or disabling an agent credential.","properties":{"status":{"description":"Set active to re-enable or disabled to kill-switch. Use DELETE to revoke permanently.","enum":["active","disabled"],"type":"string"}},"required":["status"],"type":"object"},"UpdateAnomalyAlertRequest":{"description":"Request body for triaging an anomaly alert.","properties":{"status":{"description":"New triage state for the alert.","enum":["acknowledged","resolved"],"type":"string"}},"required":["status"],"type":"object"},"UpdateCacheRuleRequest":{"description":"Request body for updating cache behavior of a query shape.","properties":{"cache_enabled":{"description":"Whether to enable caching for this query shape.","type":"boolean"},"cache_swr_seconds":{"description":"SWR override in seconds. Null to use project default.","example":60,"maximum":86400,"minimum":0,"nullable":true,"type":"integer"},"cache_ttl_seconds":{"description":"TTL override in seconds. Null to use project default.","example":300,"maximum":86400,"minimum":0,"nullable":true,"type":"integer"}},"required":["cache_enabled"],"type":"object"},"UpdateCacheRuleResponse":{"description":"Response returned after updating a cache rule.","properties":{"entry":{"$ref":"#/components/schemas/CacheRuleEntry"}},"required":["entry"],"type":"object"},"UpdateDatabaseRequest":{"description":"Request body for partially updating an upstream database.","properties":{"auto_read_routing":{"description":"Auto-route SELECT queries to read replicas.\n","type":"boolean"},"cache_config":{"$ref":"#/components/schemas/CacheConfig"},"host":{"description":"Updated PostgreSQL host.","example":"db.example.com","minLength":1,"pattern":"^[^\\x00]+$","type":"string"},"name":{"description":"Updated PostgreSQL database name.","example":"mydb","pattern":"^[^\\x00]*$","type":"string"},"password":{"description":"Updated PostgreSQL password.","format":"password","pattern":"^[^\\x00]*$","type":"string","writeOnly":true},"pool_config":{"$ref":"#/components/schemas/PoolConfig"},"pool_region":{"description":"Region where the connection pool is maintained (near the database). When set and different from the client's edge region, queries are relayed through the pool region's data plane. Empty means direct connection.\n","example":"us-east-1","type":"string"},"port":{"description":"Updated PostgreSQL port.","example":5432,"maximum":65535,"minimum":1,"type":"integer"},"query_timeout_ms":{"description":"Query timeout in milliseconds. 0 means disabled.\n","maximum":300000,"minimum":0,"type":"integer"},"role":{"$ref":"#/components/schemas/DatabaseRole"},"ssl_mode":{"$ref":"#/components/schemas/SSLMode"},"username":{"description":"Updated PostgreSQL username.","example":"pgbeam","pattern":"^[^\\x00]*$","type":"string"}},"type":"object"},"UpdateOnboardingRequest":{"description":"Request body for advancing or dismissing onboarding.","properties":{"dismiss":{"description":"Set to true to dismiss the onboarding checklist.","type":"boolean"},"step":{"description":"The onboarding step to mark as complete.","enum":["project_created","database_added","connection_tested","connection_string_copied","first_query_run","agent_credential_created"],"example":"project_created","type":"string"}},"type":"object"},"UpdateProjectRequest":{"description":"Request body for partially updating a project.","properties":{"agents_disabled":{"description":"Project-level kill-switch. Set true to block ALL agent-credential connections to this project (live agent sessions are dropped within seconds); set false to re-enable them. Passthrough/human connections are unaffected. Engaging the kill-switch emits a kill_switch webhook event.\n","example":true,"type":"boolean"},"allowed_cidrs":{"description":"IP filtering rules as CIDR ranges with optional labels. Empty array means allow all. Both IPv4 and IPv6 CIDR notation are supported.\n","example":[{"cidr":"10.0.0.0/8","label":"VPC"},{"cidr":"203.0.113.5/32","label":"Office"}],"items":{"$ref":"#/components/schemas/CidrEntry"},"maxItems":50,"type":"array"},"default_policy_profile_id":{"description":"When set, passthrough/human connections are enforced against this policy profile. Send an empty string to clear.\n","example":"pol_01h455vb4pex5vsknk084sn02q","nullable":true,"type":"string"},"description":{"description":"Updated project description.","example":"Production database proxy","maxLength":500,"type":"string"},"name":{"description":"Updated project name.","example":"my-app","maxLength":100,"minLength":1,"pattern":"^[^\\x00]*$","type":"string"},"residency":{"$ref":"#/components/schemas/DataResidency"},"status":{"$ref":"#/components/schemas/ProjectStatus"},"tags":{"description":"Replacement set of user-defined project labels.","example":["production","us-east-1"],"items":{"maxLength":50,"type":"string"},"maxItems":10,"type":"array"}},"type":"object"},"UpdateSpendLimitRequest":{"description":"Request body for updating an organization's monthly spend cap.","properties":{"spend_limit":{"description":"Monthly spend limit in dollars. Null to remove the limit.","example":500,"format":"double","nullable":true,"type":"number"}},"type":"object"},"UpdateSupportCaseRequest":{"description":"Request body for updating a support case status.","properties":{"status":{"$ref":"#/components/schemas/SupportCaseStatus"}},"type":"object"},"UsageResponse":{"description":"Response envelope for organization usage queries.","properties":{"usage":{"description":"Daily usage entries aggregated across the organization.","items":{"$ref":"#/components/schemas/DailyUsage"},"type":"array"}},"required":["usage"],"type":"object"},"VercelInstallationStatus":{"description":"Vercel Marketplace installation status for an organization, including its resources.","properties":{"created_at":{"description":"When the installation was created.","format":"date-time","type":"string"},"installation_id":{"description":"Vercel installation (integration configuration) identifier.","type":"string"},"plan":{"description":"Current plan tier for the organization.","type":"string"},"resources":{"description":"Resources (projects) provisioned under this installation.","items":{"$ref":"#/components/schemas/VercelResourceStatus"},"type":"array"},"status":{"description":"Installation status (active).","type":"string"},"vercel_account_id":{"description":"Vercel account/team identifier that owns the installation.","type":"string"}},"required":["installation_id","vercel_account_id","plan","status","resources"],"type":"object"},"VercelResourceStatus":{"description":"A PgBeam project provisioned as a Vercel Marketplace resource, with current-period usage.","properties":{"billing_plan_id":{"description":"Plan tier the resource is billed on.","type":"string"},"name":{"description":"Human-readable resource/project name.","type":"string"},"period_bytes":{"description":"Bytes transferred by this resource in the current billing period.","format":"int64","type":"integer"},"period_queries":{"description":"Queries this resource has served in the current billing period.","format":"int64","type":"integer"},"project_id":{"description":"PgBeam project identifier backing the resource.","type":"string"},"resource_id":{"description":"Vercel resource identifier.","type":"string"},"status":{"description":"Current resource lifecycle status.","enum":["ready","suspended","deleted"],"type":"string"}},"required":["resource_id","project_id","name","billing_plan_id","status","period_queries","period_bytes"],"type":"object"},"VerifyCustomDomainResponse":{"description":"Result of checking DNS ownership for a custom domain.","properties":{"domain":{"$ref":"#/components/schemas/CustomDomain"},"error":{"description":"Error message if verification failed.","type":"string"},"verified":{"description":"Whether DNS verification succeeded.","type":"boolean"}},"required":["verified"],"type":"object"},"WebhookEndpoint":{"description":"A delivery target for project audit/event notifications.","properties":{"created_at":{"description":"When the endpoint was created.","format":"date-time","type":"string"},"description":{"description":"Human-readable label for the endpoint.","type":"string"},"enabled":{"description":"Whether deliveries are active for this endpoint.","type":"boolean"},"event_types":{"description":"Event types to deliver. Empty means all events.","items":{"description":"An event type (e.g. blocked, anomaly, approval).","type":"string"},"type":"array"},"format":{"description":"Payload format for delivered events.","enum":["json","splunk_hec","datadog","elastic"],"type":"string"},"id":{"description":"Unique webhook endpoint identifier (prefixed).","example":"whk_01h455vb4pex5vsknk084sn02q","type":"string"},"project_id":{"description":"Owning project ID.","type":"string"},"updated_at":{"description":"When the endpoint was last updated.","format":"date-time","type":"string"},"url":{"description":"HTTPS endpoint that receives event deliveries.","example":"https://example.com/hooks/pgbeam","type":"string"}},"required":["id","project_id","url","format","enabled","created_at","updated_at"],"type":"object"},"WebhookEndpointInput":{"description":"Mutable fields of a webhook endpoint (used for create and update).","properties":{"description":{"description":"Human-readable label for the endpoint.","maxLength":256,"type":"string"},"enabled":{"default":true,"description":"Whether deliveries are active for this endpoint.","type":"boolean"},"event_types":{"description":"Event types to deliver. Empty means all events.","items":{"description":"An event type.","type":"string"},"type":"array"},"format":{"default":"json","description":"Payload format for delivered events.","enum":["json","splunk_hec","datadog","elastic"],"type":"string"},"secret":{"description":"Shared secret used to sign delivery payloads. Write-only.","maxLength":256,"type":"string","writeOnly":true},"url":{"description":"HTTPS endpoint that receives event deliveries.","example":"https://example.com/hooks/pgbeam","maxLength":2048,"minLength":1,"type":"string"}},"required":["url"],"type":"object"},"WebhookTestResponse":{"description":"Result of sending a synthetic test event to a webhook endpoint.","properties":{"delivery_id":{"description":"Identifier of the test delivery.","type":"string"},"error":{"description":"Error detail when the test delivery failed.","type":"string"},"status":{"description":"Outcome of the test delivery (delivered or failed).","type":"string"},"status_code":{"description":"HTTP status code returned by the endpoint, if a response was received.","type":"integer"}},"required":["delivery_id","status"],"type":"object"}},"securitySchemes":{"AWSMarketplaceAuth":{"description":"AWS Marketplace registration token or shared secret for SNS webhook verification.","in":"header","name":"X-Amz-Marketplace-Token","type":"apiKey"},"ApiKeyAuth":{"bearerFormat":"APIKey","description":"API key issued via the dashboard. Pass it as `Authorization: Bearer <api-key>`.","scheme":"bearer","type":"http"},"BearerAuth":{"bearerFormat":"JWT","description":"JWT issued by Better Auth. Verified via JWKS.","scheme":"bearer","type":"http"},"InternalSecret":{"description":"Shared secret for dashboard-to-API service calls.","in":"header","name":"X-Internal-Secret","type":"apiKey"},"VercelOIDC":{"bearerFormat":"JWT","description":"Vercel Marketplace OIDC JWT. Verified via JWKS at marketplace.vercel.com.","scheme":"bearer","type":"http"}}},"info":{"contact":{"name":"PgBeam","url":"https://pgbeam.com"},"description":"REST API for the PgBeam multi-tenant PostgreSQL proxy platform.\nManages projects, database connections, cache/pool configuration, and regions.\n","license":{"name":"Proprietary","url":"https://pgbeam.com/terms"},"title":"PgBeam Control Plane API","version":"1.0.0"},"openapi":"3.0.0","paths":{"/v1/account/export":{"get":{"description":"Returns all personal data associated with the authenticated user in a structured JSON format. Supports GDPR data portability and CCPA right to know. Audit logs are limited to the most recent 1000 entries.","operationId":"ExportAccountData","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountExport"}}},"description":"Account data export."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Export account data","tags":["Account"]}},"/v1/aws-marketplace/claim":{},"/v1/aws-marketplace/customers/{customerIdentifier}":{"parameters":[{"in":"path","name":"customerIdentifier","required":true,"schema":{"type":"string"}}]},"/v1/aws-marketplace/resolve":{},"/v1/aws-marketplace/webhook":{},"/v1/databases/{database_id}/replicas":{"get":{"description":"Lists all read replicas for a database.","operationId":"ListReplicas","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListReplicasResponse"}}},"description":"List of replicas."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List replicas","tags":["Projects"]},"parameters":[{"$ref":"#/components/parameters/DatabaseId"}],"post":{"description":"Adds a read replica to a database.","operationId":"CreateReplica","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReplicaRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Replica"}}},"description":"Replica created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Add a replica","tags":["Projects"]}},"/v1/databases/{database_id}/replicas/{replica_id}":{"delete":{"description":"Removes a read replica from a database.","operationId":"DeleteReplica","responses":{"204":{"description":"Replica deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Delete a replica","tags":["Projects"]},"parameters":[{"$ref":"#/components/parameters/DatabaseId"},{"$ref":"#/components/parameters/ReplicaId"}]},"/v1/health":{"get":{"description":"Returns the health status of the API server.","operationId":"GetHealth","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}},"description":"Service is healthy."},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[],"summary":"Health check","tags":["Platform"]}},"/v1/installations/{installationId}":{"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string"}}]},"/v1/installations/{installationId}/plans":{"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string"}}]},"/v1/installations/{installationId}/resources":{"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string"}}]},"/v1/installations/{installationId}/resources/{resourceId}":{"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string"}},{"in":"path","name":"resourceId","required":true,"schema":{"type":"string"}}]},"/v1/installations/{installationId}/resources/{resourceId}/plans":{"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string"}},{"in":"path","name":"resourceId","required":true,"schema":{"type":"string"}}]},"/v1/internal/billing-health":{"get":{"description":"Returns aggregate billing metrics grouped by plan tier,\nbilling provider, and subscription status.\n","operationId":"GetBillingHealth","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingHealthSummary"}}},"description":"Billing health summary."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"InternalSecret":[]}],"summary":"Get billing health summary","tags":["Internal"],"x-internal":true}},"/v1/internal/consent":{"post":{"description":"Records that a user accepted a legal document (terms of service, privacy policy). Called by the dashboard at sign-up.","operationId":"RecordConsent","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordConsentRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentRecord"}}},"description":"Consent recorded."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"InternalSecret":[]}],"summary":"Record user consent","tags":["Internal"],"x-internal":true}},"/v1/internal/enterprise-plan":{"post":{"description":"Sets custom enterprise pricing for an organization. Bypasses\nthe standard Stripe subscription flow. Authenticated via internal secret.\n","operationId":"SetEnterprisePlan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterprisePlanRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationPlan"}}},"description":"Enterprise plan set."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"InternalSecret":[]}],"summary":"Set enterprise plan for an organization","tags":["Internal"],"x-internal":true}},"/v1/internal/organizations/{org_id}":{"delete":{"description":"Cleans up PgBeam resources for an organization being deleted.\nSoft-deletes projects, notifies data planes, removes Vercel installations,\nand deletes the organization plan row.\nAuthenticated via internal shared secret (not JWT/API key).\n","operationId":"DeleteOrganizationResources","parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"204":{"description":"Organization resources deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"InternalSecret":[]}],"summary":"Delete organization resources","tags":["Internal"],"x-internal":true}},"/v1/internal/reconcile":{"post":{"description":"Forces an immediate Stripe subscription reconciliation cycle.\nAuthenticated via internal shared secret.\n","operationId":"TriggerReconcile","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconcileResponse"}}},"description":"Reconciliation completed."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"InternalSecret":[]}],"summary":"Trigger on-demand Stripe reconciliation","tags":["Internal"],"x-internal":true}},"/v1/internal/support/slack-event":{"post":{"description":"Receives a forwarded Slack event from the dashboard webhook handler and creates a support message.","operationId":"HandleSlackSupportEvent","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackEventPayload"}}},"required":true},"responses":{"200":{"description":"Event processed."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"InternalSecret":[]}],"summary":"Handle a Slack support event","tags":["Internal"]}},"/v1/internal/sync-plan":{"post":{"description":"Called by the dashboard's durable workflow after subscription changes.\nAuthenticated via internal shared secret (not JWT/API key).\n","operationId":"SyncPlan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncPlanRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncPlanResponse"}}},"description":"Plan synced successfully."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"InternalSecret":[]}],"summary":"Sync subscription plan from dashboard","tags":["Internal"],"x-internal":true}},"/v1/mcp":{},"/v1/organizations":{"get":{"description":"Lists the organizations visible to the caller's credential. An organization-scoped API key (pbo_) returns exactly the organization it belongs to. A user credential (account-scoped API key or dashboard session token) returns the organizations the user is a member of, including the caller's role in each.","operationId":"ListOrganizations","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrganizationsResponse"}}},"description":"Organizations visible to the caller."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List organizations","tags":["Account"]}},"/v1/organizations/{org_id}/cancellation-feedback":{"post":{"description":"Records optional feedback when a user cancels their subscription.","operationId":"SubmitCancellationFeedback","parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancellationFeedbackRequest"}}},"required":true},"responses":{"204":{"description":"Feedback recorded."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Submit cancellation feedback","tags":["Analytics"]}},"/v1/organizations/{org_id}/crm/activities":{"get":{"description":"Lists the organization's most recent CRM activity, newest first.","operationId":"ListCrmActivities","parameters":[{"$ref":"#/components/parameters/PageSize"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListActivitiesResponse"}}},"description":"List of activities."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List activities","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}]},"/v1/organizations/{org_id}/crm/artifacts":{"get":{"description":"Lists agent-produced artifacts for the organization.","operationId":"ListCrmArtifacts","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListArtifactsResponse"}}},"description":"List of artifacts."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List artifacts","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}]},"/v1/organizations/{org_id}/crm/artifacts/{artifact_id}":{"get":{"description":"Returns a single artifact by ID.","operationId":"GetCrmArtifact","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Artifact"}}},"description":"The artifact."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get an artifact","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/CrmArtifactId"}]},"/v1/organizations/{org_id}/crm/companies":{"get":{"description":"List companies.","operationId":"ListCrmCompanies","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCompaniesResponse"}}},"description":"List of companies."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List companies","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"post":{"description":"Create a company.","operationId":"CreateCrmCompany","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}}},"description":"Company created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create a company","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/companies/{company_id}":{"delete":{"description":"Delete a company.","operationId":"DeleteCrmCompany","responses":{"204":{"description":"Company deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a company","tags":["Crm"],"x-internal":true},"get":{"description":"Get a company.","operationId":"GetCrmCompany","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}}},"description":"The company."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a company","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/CrmCompanyId"}],"put":{"description":"Update a company.","operationId":"UpdateCrmCompany","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}}},"description":"Updated company."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a company","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/contacts":{"get":{"description":"List contacts.","operationId":"ListCrmContacts","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListContactsResponse"}}},"description":"List of contacts."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List contacts","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"post":{"description":"Create a contact.","operationId":"CreateCrmContact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}},"description":"Contact created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create a contact","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/contacts/{contact_id}":{"delete":{"description":"Delete a contact.","operationId":"DeleteCrmContact","responses":{"204":{"description":"Contact deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a contact","tags":["Crm"],"x-internal":true},"get":{"description":"Get a contact.","operationId":"GetCrmContact","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}},"description":"The contact."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a contact","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/CrmContactId"}],"put":{"description":"Update a contact.","operationId":"UpdateCrmContact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}},"description":"Updated contact."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a contact","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/context":{"get":{"description":"Returns the shared CRM context document for the organization.","operationId":"GetCrmContext","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmContext"}}},"description":"The CRM context."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get the org CRM context","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"put":{"description":"Creates or updates the shared CRM context document.","operationId":"UpdateCrmContext","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmContextInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmContext"}}},"description":"The updated CRM context."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update the org CRM context","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/deals":{"get":{"description":"List deals.","operationId":"ListCrmDeals","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDealsResponse"}}},"description":"List of deals."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List deals","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"post":{"description":"Create a deal.","operationId":"CreateCrmDeal","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deal"}}},"description":"Deal created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create a deal","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/deals/{deal_id}":{"delete":{"description":"Delete a deal.","operationId":"DeleteCrmDeal","responses":{"204":{"description":"Deal deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a deal","tags":["Crm"],"x-internal":true},"get":{"description":"Get a deal.","operationId":"GetCrmDeal","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deal"}}},"description":"The deal."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a deal","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/CrmDealId"}],"put":{"description":"Update a deal.","operationId":"UpdateCrmDeal","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deal"}}},"description":"Updated deal."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a deal","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/pipeline":{"get":{"description":"Returns deal count and total value grouped by pipeline stage.","operationId":"GetCrmPipeline","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineSummaryResponse"}}},"description":"Pipeline summary."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Deal pipeline summary","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}]},"/v1/organizations/{org_id}/crm/research-tasks":{"get":{"description":"List research tasks.","operationId":"ListCrmResearchTasks","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListResearchTasksResponse"}}},"description":"List of research tasks."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List research tasks","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"post":{"description":"Adds a task to the CRM research queue. The autonomous research worker leases pending tasks, enriches the subject entity, and writes results back.\n","operationId":"CreateCrmResearchTask","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResearchTaskInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResearchTask"}}},"description":"Task enqueued."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Enqueue a research task","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/research-tasks/{task_id}":{"get":{"description":"Get a research task.","operationId":"GetCrmResearchTask","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResearchTask"}}},"description":"The research task."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a research task","tags":["Crm"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/CrmTaskId"}]},"/v1/organizations/{org_id}/crm/research-tasks/{task_id}/approve":{"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/CrmTaskId"}],"post":{"description":"Approves a task that is awaiting approval (an irreversible action). The task flips to pending and is then run by the worker.\n","operationId":"ApproveCrmResearchTask","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResearchTask"}}},"description":"The approved task."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Approve a research task","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/crm/research-tasks/{task_id}/cancel":{"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/CrmTaskId"}],"post":{"description":"Cancels a pending or leased task. Terminal tasks are unaffected.","operationId":"CancelCrmResearchTask","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResearchTask"}}},"description":"The canceled task."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Cancel a research task","tags":["Crm"],"x-internal":true}},"/v1/organizations/{org_id}/onboarding":{"get":{"description":"Returns the onboarding checklist progress for an organization.","operationId":"GetOnboardingProgress","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingProgress"}}},"description":"Onboarding progress."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Get onboarding progress","tags":["Account"]},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"patch":{"description":"Mark an onboarding step as complete or dismiss the checklist.","operationId":"UpdateOnboardingProgress","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOnboardingRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingProgress"}}},"description":"Updated onboarding progress."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Update onboarding progress","tags":["Account"]}},"/v1/organizations/{org_id}/plan":{"get":{"description":"Returns the current plan and limits for the organization.","operationId":"GetOrganizationPlan","parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationPlan"}}},"description":"Organization plan details."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get organization plan","tags":["Analytics"]}},"/v1/organizations/{org_id}/self-host-enrollments":{"get":{"description":"Lists an organization's self-host enrollments. Tokens are never returned.","operationId":"ListSelfHostEnrollments","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSelfHostEnrollmentsResponse"}}},"description":"List of enrollments."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"summary":"List self-host enrollments","tags":["Platform"]},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"post":{"description":"Issues an enrollment token a self-hosted (BYOC) proxy uses to authenticate to the control plane's config/audit gRPC stream. The token is returned once and cannot be retrieved again. Requires the Scale or enterprise plan.","operationId":"CreateSelfHostEnrollment","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSelfHostEnrollmentRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelfHostEnrollmentSecret"}}},"description":"Enrollment created. Token shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The organization's plan is not entitled to self-host."},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Issue a self-host enrollment token","tags":["Platform"]}},"/v1/organizations/{org_id}/self-host-enrollments/{enrollment_id}":{"delete":{"description":"Revokes an enrollment so its token can no longer authenticate a proxy. Connected proxies keep their last-known config until they reconnect.","operationId":"RevokeSelfHostEnrollment","responses":{"204":{"description":"Enrollment revoked."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Revoke a self-host enrollment","tags":["Platform"]},"parameters":[{"$ref":"#/components/parameters/OrgId"},{"description":"Unique enrollment identifier.","in":"path","name":"enrollment_id","required":true,"schema":{"example":"she_01h455vb4pex5vsknk084sn02q","pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}}]},"/v1/organizations/{org_id}/self-host-enrollments/{enrollment_id}/rotate":{"parameters":[{"$ref":"#/components/parameters/OrgId"},{"description":"Unique enrollment identifier.","in":"path","name":"enrollment_id","required":true,"schema":{"example":"she_01h455vb4pex5vsknk084sn02q","pattern":"^[a-zA-Z0-9_.-]+$","type":"string"}}],"post":{"description":"Mints a new enrollment token in place, keeping the same enrollment id, metadata, and expiry. The swap is atomic: the old token stops authenticating new proxy connections the moment this call returns. An already-connected proxy keeps its existing gRPC streams until it disconnects, then must present the new token to reconnect. The new token is returned once and cannot be retrieved again.","operationId":"RotateSelfHostEnrollment","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelfHostEnrollmentSecret"}}},"description":"Token rotated. New token shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The enrollment is revoked and cannot be rotated."}},"summary":"Rotate a self-host enrollment token","tags":["Platform"]}},"/v1/organizations/{org_id}/spend-limit":{"put":{"description":"Sets the monthly spend limit for an organization. Null removes the limit.","operationId":"UpdateSpendLimit","parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpendLimitRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationPlan"}}},"description":"Spend limit updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Update spend limit","tags":["Analytics"]}},"/v1/organizations/{org_id}/support/cases":{"get":{"description":"Lists support cases for the organization with optional status and search filters.","operationId":"ListSupportCases","parameters":[{"description":"Filter by case status.","in":"query","name":"status","schema":{"$ref":"#/components/schemas/SupportCaseStatus"}},{"description":"Search cases by title.","in":"query","name":"search","schema":{"type":"string"}},{"description":"Number of results per page (1-100, default 20).","in":"query","name":"page_size","schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Page number (1-based, default 1).","in":"query","name":"page","schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSupportCasesResponse"}}},"description":"List of support cases."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"summary":"List support cases","tags":["Support"]},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"post":{"description":"Creates a new support case with an initial message.","operationId":"CreateSupportCase","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSupportCaseRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportCase"}}},"description":"Support case created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"summary":"Create a support case","tags":["Support"]}},"/v1/organizations/{org_id}/support/cases/{case_id}":{"get":{"description":"Returns a support case with all its messages.","operationId":"GetSupportCase","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSupportCaseResponse"}}},"description":"Support case with messages."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a support case","tags":["Support"]},"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/SupportCaseId"}],"patch":{"description":"Updates the status of a support case (close or reopen).","operationId":"UpdateSupportCase","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSupportCaseRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportCase"}}},"description":"Updated support case."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a support case","tags":["Support"]}},"/v1/organizations/{org_id}/support/cases/{case_id}/messages":{"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/SupportCaseId"}],"post":{"description":"Adds a new message to an existing support case thread.","operationId":"CreateSupportMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSupportMessageRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportMessage"}}},"description":"Message created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Add a message to a support case","tags":["Support"]}},"/v1/organizations/{org_id}/usage":{"get":{"description":"Returns daily usage data aggregated across all projects in the organization.","operationId":"GetOrganizationUsage","parameters":[{"$ref":"#/components/parameters/OrgId"},{"description":"Start date (inclusive, YYYY-MM-DD).","in":"query","name":"start_date","required":true,"schema":{"example":"2024-01-01","format":"date","type":"string"}},{"description":"End date (inclusive, YYYY-MM-DD).","in":"query","name":"end_date","required":true,"schema":{"example":"2024-01-31","format":"date","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}},"description":"Daily usage data."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get organization usage","tags":["Analytics"]}},"/v1/organizations/{org_id}/vercel-installation":{"get":{"description":"Returns the Vercel Marketplace installation for the organization,\nincluding its provisioned resources and their current-period usage.\nReturns 404 when the organization was not provisioned through the\nVercel Marketplace. Powers the dashboard's Vercel integration page.\n","operationId":"GetVercelInstallation","parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VercelInstallationStatus"}}},"description":"Vercel installation status."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get Vercel Marketplace installation status","tags":["Analytics"]}},"/v1/plans":{"get":{"description":"Returns all available plan tiers with their limits and pricing.","operationId":"ListPlans","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPlansResponse"}}},"description":"List of available plans."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"List available plans","tags":["Analytics"]}},"/v1/products/{productSlug}/plans":{"parameters":[{"in":"path","name":"productSlug","required":true,"schema":{"type":"string"}}]},"/v1/projects":{"get":{"description":"Lists projects filtered by organization. Requires org_id query parameter.","operationId":"ListProjects","parameters":[{"description":"Organization ID to filter projects.","in":"query","name":"org_id","required":true,"schema":{"example":"org_abc123","pattern":"^[\\x20-\\x7E]+$","type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"},{"description":"Sort field for projects list.","in":"query","name":"sort_by","schema":{"default":"created_at","enum":["name","created_at","active_connections"],"example":"created_at","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListProjectsResponse"}}},"description":"List of projects."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List projects","tags":["Projects"]},"post":{"description":"Creates a new project within the specified organization.","operationId":"CreateProject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectResponse"}}},"description":"Project created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create a project","tags":["Projects"]}},"/v1/projects/{project_id}":{"delete":{"description":"Soft-deletes a project and all associated databases.","operationId":"DeleteProject","responses":{"204":{"description":"Project deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Delete a project","tags":["Projects"]},"get":{"description":"Returns a single project by ID.","operationId":"GetProject","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Project found."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Get a project","tags":["Projects"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"patch":{"description":"Partially updates a project. Only provided fields are modified.","operationId":"UpdateProject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Project updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Update a project","tags":["Projects"]}},"/v1/projects/{project_id}/agents":{"get":{"description":"Lists agent credentials for the project. Secrets are never returned.","operationId":"ListAgentCredentials","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentCredentialsResponse"}}},"description":"List of agent credentials."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List agent credentials","tags":["Agents"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Issues a scoped Postgres login and hosted MCP token for an AI agent. The connection string and MCP token are returned once and cannot be retrieved again.","operationId":"CreateAgentCredential","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentCredentialRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentCredentialSecrets"}}},"description":"Agent credential created. Secrets shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Agent credential quota reached for the organization plan."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create an agent credential","tags":["Agents"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/agents/{agent_id}":{"delete":{"description":"Permanently revokes the credential and drops any live connections.","operationId":"RevokeAgentCredential","responses":{"204":{"description":"Agent credential revoked."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Revoke an agent credential","tags":["Agents"],"x-feature-flag":"agent-gateway"},"get":{"description":"Returns a single agent credential. Secrets are never included.","operationId":"GetAgentCredential","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentCredential"}}},"description":"The agent credential (no secrets)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get an agent credential","tags":["Agents"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/AgentId"}],"patch":{"description":"Toggles the kill-switch. Disabling drops live connections within seconds.","operationId":"UpdateAgentCredentialStatus","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentCredentialStatusRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentCredential"}}},"description":"Updated agent credential."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Enable or disable an agent credential","tags":["Agents"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/agents/{agent_id}/policy-recommendation":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/AgentId"}],"post":{"description":"Derives the tightest policy that would still pass every statement this agent credential has legitimately run, using its recorded audit history over a lookback window (default 30 days). The candidate's table allowlist is the union of relations actually referenced, its statement-kind allow set is the observed set, it downgrades to read-only when no writes were seen, and its max_rows ceiling comes from an observed high-percentile row count. The candidate is proven safe by replaying it through the data plane's own policy engine against the same history: a good recommendation has replay.summary.newly_blocked == 0. This endpoint is advisory only. It reads the audit log, never connects to the upstream database, and never creates, updates, or mutates any policy or credential; the operator loads the candidate into the editor and saves it themselves.","operationId":"RecommendAgentPolicy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyRecommendationInput"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyRecommendation"}}},"description":"The recommended candidate policy and its replay proof."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Recommend a least-privilege policy from recorded traffic","tags":["Policies"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/agents/{agent_id}/rotate":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/AgentId"}],"post":{"description":"Generates a new Postgres password and MCP token for the credential in place, keeping the same id, username, name, and policy. Live connections using the old password are dropped within seconds. The new secrets are returned once and cannot be retrieved again.","operationId":"RotateAgentCredential","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentCredentialSecrets"}}},"description":"Secrets rotated. New secrets shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The credential is revoked and cannot be rotated."}},"summary":"Rotate an agent credential's secrets","tags":["Agents"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/anomalies":{"get":{"description":"Lists anomaly alerts for the project, newest first, optionally filtered by status.","operationId":"ListAnomalyAlerts","parameters":[{"description":"Filter to a single status.","in":"query","name":"status","schema":{"enum":["open","acknowledged","resolved"],"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAnomalyAlertsResponse"}}},"description":"Page of anomaly alerts."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List anomaly alerts","tags":["Anomalies"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}]},"/v1/projects/{project_id}/anomalies/{anomaly_id}":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/AnomalyId"}],"patch":{"description":"Updates the triage status of an anomaly alert (acknowledge or resolve).","operationId":"UpdateAnomalyAlert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAnomalyAlertRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyAlert"}}},"description":"The updated anomaly alert."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Triage an anomaly alert","tags":["Anomalies"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/approvals":{"get":{"description":"Lists approval requests for the project, newest first, optionally filtered by status.","operationId":"ListApprovalRequests","parameters":[{"description":"Filter to a single status.","in":"query","name":"status","schema":{"enum":["pending","approved","rejected","expired","executed","failed"],"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListApprovalRequestsResponse"}}},"description":"Page of approval requests."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List approval requests","tags":["Approvals"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}]},"/v1/projects/{project_id}/approvals/{approval_id}/approve":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/ApprovalId"}],"post":{"description":"Approves a pending approval request, releasing the held statement.","operationId":"ApproveApprovalRequest","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalDecisionRequest"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalRequest"}}},"description":"The updated approval request."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"summary":"Approve a held statement","tags":["Approvals"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/approvals/{approval_id}/reject":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/ApprovalId"}],"post":{"description":"Rejects a pending approval request, denying the held statement.","operationId":"RejectApprovalRequest","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalDecisionRequest"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalRequest"}}},"description":"The updated approval request."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"summary":"Reject a held statement","tags":["Approvals"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/audit-logs":{"get":{"description":"Returns agent statement audit entries for the project, newest first, with optional credential, event, decision, source and date-range filters.","operationId":"ListAuditLogs","parameters":[{"$ref":"#/components/parameters/AuditCredentialId"},{"$ref":"#/components/parameters/AuditEvent"},{"$ref":"#/components/parameters/AuditDecision"},{"$ref":"#/components/parameters/AuditSource"},{"$ref":"#/components/parameters/AuditStart"},{"$ref":"#/components/parameters/AuditEnd"},{"description":"Return entries strictly older than this timestamp (keyset pagination cursor).","in":"query","name":"before","schema":{"format":"date-time","type":"string"}},{"$ref":"#/components/parameters/PageSize"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAuditLogsResponse"}}},"description":"Page of audit entries."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List agent audit logs","tags":["Agents"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}]},"/v1/projects/{project_id}/audit-logs/export":{"get":{"description":"Streams the project's agent audit entries as a CSV file, newest first, honoring the same credential, event, decision, source and date-range filters as the list endpoint. The full filtered set is streamed (no pagination); the result is suitable for spreadsheets, SIEM ingestion, and compliance archives.","operationId":"ExportAuditLogs","parameters":[{"$ref":"#/components/parameters/AuditCredentialId"},{"$ref":"#/components/parameters/AuditEvent"},{"$ref":"#/components/parameters/AuditDecision"},{"$ref":"#/components/parameters/AuditSource"},{"$ref":"#/components/parameters/AuditStart"},{"$ref":"#/components/parameters/AuditEnd"}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"CSV stream of filtered audit entries."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Export agent audit logs as CSV","tags":["Agents"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}]},"/v1/projects/{project_id}/audit-logs/sessions/{session_id}":{"get":{"description":"Groups a session's audit entries into one deterministic summary: the credentials and origins involved, the window it spans, how many statements were allowed, blocked, masked and truncated, the rows and bytes it moved, and the tables it read, wrote and was refused. No model is involved, so the same entries always summarize the same way. Returns metadata only (table names and counts), never row values, and requires the same audit:read permission the list and export endpoints do.","operationId":"GetAuditSessionSummary","parameters":[{"$ref":"#/components/parameters/AuditStart"},{"$ref":"#/components/parameters/AuditEnd"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditSessionSummary"}}},"description":"Session summary."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Summarize one agent session","tags":["Agents"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/AuditSessionId"}]},"/v1/projects/{project_id}/audit-logs/verify":{"get":{"description":"Recomputes the project's audit hash chain over an optional time range and reports whether it is intact. Each audit entry is linked to its predecessor with a SHA-256 hash, so editing or deleting any row breaks the chain. On a break, the response reports the first sequence number where a tampered or deleted entry was detected. Requires the same audit:read permission as the list and export endpoints.","operationId":"VerifyAuditChain","parameters":[{"$ref":"#/components/parameters/AuditStart"},{"$ref":"#/components/parameters/AuditEnd"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditChainVerification"}}},"description":"Chain verification result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Verify the tamper-evident audit chain","tags":["Agents"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}]},"/v1/projects/{project_id}/branches":{"get":{"description":"Lists ephemeral sandbox branches for the project's databases.","operationId":"ListDatabaseBranches","parameters":[{"description":"Filter to a single status.","in":"query","name":"status","schema":{"enum":["pending","ready","error","discarded"],"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDatabaseBranchesResponse"}}},"description":"Page of sandbox branches."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List sandbox branches","tags":["Branches"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}]},"/v1/projects/{project_id}/branches/{branch_id}":{"delete":{"description":"Marks an ephemeral sandbox branch as discarded for teardown.","operationId":"DiscardDatabaseBranch","responses":{"204":{"description":"Sandbox branch discarded."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Discard a sandbox branch","tags":["Branches"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/BranchId"}]},"/v1/projects/{project_id}/databases":{"get":{"description":"Lists all databases registered for the project.","operationId":"ListDatabases","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDatabasesResponse"}}},"description":"List of databases."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List databases","tags":["Databases"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Registers a new upstream PostgreSQL database for the project.","operationId":"CreateDatabase","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDatabaseRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Database"}}},"description":"Database created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Add a database","tags":["Databases"]}},"/v1/projects/{project_id}/databases/{database_id}":{"delete":{"description":"Removes a database registration from the project.","operationId":"DeleteDatabase","responses":{"204":{"description":"Database deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Delete a database","tags":["Databases"]},"get":{"description":"Returns a single database by ID.","operationId":"GetDatabase","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Database"}}},"description":"Database found."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Get a database","tags":["Databases"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DatabaseId"}],"patch":{"description":"Partially updates a database connection. Only provided fields are modified.","operationId":"UpdateDatabase","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDatabaseRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Database"}}},"description":"Database updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Update a database","tags":["Databases"]}},"/v1/projects/{project_id}/databases/{database_id}/cache-rules":{"get":{"description":"Returns the cache rules for a database, showing all observed query\nshapes with their stats and cache recommendations.\n","operationId":"ListCacheRules","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCacheRulesResponse"}}},"description":"Cache rule entries."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List cache rules","tags":["Projects"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DatabaseId"}]},"/v1/projects/{project_id}/databases/{database_id}/cache-rules/{query_hash}":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DatabaseId"},{"description":"xxhash64 hex of the normalized SQL.","in":"path","name":"query_hash","required":true,"schema":{"maxLength":16,"minLength":16,"pattern":"^[a-f0-9]+$","type":"string"}}],"put":{"description":"Enable or disable caching for a specific query shape, with optional\nTTL and SWR overrides. Requires the query to exist in the cache rules.\n","operationId":"UpdateCacheRule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCacheRuleRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCacheRuleResponse"}}},"description":"Cache rule updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Update cache rule","tags":["Projects"]}},"/v1/projects/{project_id}/databases/{database_id}/scan-pii":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DatabaseId"}],"post":{"description":"Connects to the upstream database read-only, inspects information_schema and samples column values against PII heuristics, and returns ranked masking suggestions. Suggestions are advisory — the operator reviews them and applies the ones they want into a policy profile's masking rules. Nothing is auto-applied.","operationId":"ScanDatabaseForPii","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanPiiResult"}}},"description":"PII scan result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Scan a database for likely-PII columns","tags":["Databases"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/databases/{database_id}/schema-catalog":{"get":{"description":"Connects to the upstream database read-only and returns its user relations (tables and views) and columns. Powers table/column autocomplete and view-aware warnings in the policy editor — relation kind distinguishes a view (whose masking/row-filters apply to the view itself, not its base tables) from a base table, and a per-column is_binary flag flags columns that mask to NULL. System schemas are excluded; nothing is persisted.","operationId":"GetSchemaCatalog","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaCatalog"}}},"description":"Schema catalog."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Read a database's schema catalog","tags":["Databases"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DatabaseId"}]},"/v1/projects/{project_id}/databases/{database_id}/test-connection":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DatabaseId"}],"post":{"description":"Attempts to connect to the upstream database using the stored credentials and returns the result.","operationId":"TestDatabaseConnection","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestConnectionResult"}}},"description":"Connection test result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Test database connection","tags":["Databases"]}},"/v1/projects/{project_id}/domains":{"get":{"description":"Lists all custom domains registered for the project.","operationId":"ListCustomDomains","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}},"description":"List of custom domains."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List custom domains","tags":["Projects"],"x-feature-flag":"custom-domains"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Registers a new custom domain for the project. Returns DNS verification instructions. Requires a Scale or Enterprise plan.","operationId":"CreateCustomDomain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomDomainRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomain"}}},"description":"Custom domain created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Custom domains require a Scale or Enterprise plan."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Add a custom domain","tags":["Projects"],"x-feature-flag":"custom-domains"}},"/v1/projects/{project_id}/domains/{domain_id}":{"delete":{"description":"Removes a custom domain from the project and revokes its TLS certificate.","operationId":"DeleteCustomDomain","responses":{"204":{"description":"Custom domain deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Delete a custom domain","tags":["Projects"],"x-feature-flag":"custom-domains"},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DomainId"}]},"/v1/projects/{project_id}/domains/{domain_id}/verify":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/DomainId"}],"post":{"description":"Checks DNS TXT record to verify domain ownership. Updates domain status on success. Requires a Scale or Enterprise plan.","operationId":"VerifyCustomDomain","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCustomDomainResponse"}}},"description":"Verification result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Custom domains require a Scale or Enterprise plan."},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Verify custom domain DNS","tags":["Projects"],"x-feature-flag":"custom-domains"}},"/v1/projects/{project_id}/honeytokens":{"get":{"description":"Lists the project's honeytokens.","operationId":"ListHoneytokens","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListHoneytokensResponse"}}},"description":"List of honeytokens."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List honeytokens","tags":["Honeytokens"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Registers a decoy (canary) relation for the project. Any agent statement\nthat references it is blocked and recorded as a canary_tripped audit event.\n","operationId":"CreateHoneytoken","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoneytokenInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Honeytoken"}}},"description":"Honeytoken registered."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Register a honeytoken","tags":["Honeytokens"]}},"/v1/projects/{project_id}/honeytokens/{honeytoken_id}":{"delete":{"description":"Removes a honeytoken from the project.","operationId":"DeleteHoneytoken","responses":{"204":{"description":"Honeytoken deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a honeytoken","tags":["Honeytokens"]},"get":{"description":"Returns a single honeytoken by ID.","operationId":"GetHoneytoken","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Honeytoken"}}},"description":"The honeytoken."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a honeytoken","tags":["Honeytokens"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/HoneytokenId"}],"put":{"description":"Updates a honeytoken's relation or action.","operationId":"UpdateHoneytoken","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoneytokenInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Honeytoken"}}},"description":"Updated honeytoken."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a honeytoken","tags":["Honeytokens"]}},"/v1/projects/{project_id}/insights":{"get":{"description":"Returns aggregated query-level analytics for a project including top queries\nby count, cache hit/miss summary, and latency statistics.\n","operationId":"GetProjectInsights","parameters":[{"$ref":"#/components/parameters/ProjectId"},{"description":"Time range to query. Defaults to 24h.","in":"query","name":"range","schema":{"default":"24h","enum":["1h","6h","24h","7d"],"example":"24h","type":"string"}},{"description":"Maximum number of top queries to return (1-100).","in":"query","name":"limit","schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectInsights"}}},"description":"Query insights for the project."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get query insights for a project","tags":["Analytics"]}},"/v1/projects/{project_id}/metrics":{"get":{"description":"Returns recent project metrics snapshots, optionally filtered by region.","operationId":"GetProjectMetrics","parameters":[{"$ref":"#/components/parameters/ProjectId"},{"description":"Maximum number of recent snapshots to return.","in":"query","name":"limit","schema":{"default":60,"maximum":1000,"minimum":1,"type":"integer"}},{"description":"Filter metrics by region code.","in":"query","name":"region","schema":{"example":"us-east-1","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectMetricsResponse"}}},"description":"Metrics snapshots"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get project metrics","tags":["Projects"]}},"/v1/projects/{project_id}/migrations:lint":{"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Analyzes a migration script for unsafe schema changes and returns findings.","operationId":"LintMigration","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationLintRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationLintResponse"}}},"description":"Lint results."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Lint a migration","tags":["Migrations"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/policies":{"get":{"description":"Lists all policy profiles for the project.","operationId":"ListPolicyProfiles","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPolicyProfilesResponse"}}},"description":"List of policy profiles."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List policy profiles","tags":["Policies"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Creates a policy profile that can be attached to agent credentials.","operationId":"CreatePolicyProfile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyProfileInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyProfile"}}},"description":"Policy profile created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create a policy profile","tags":["Policies"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/policies/{policy_id}":{"delete":{"description":"Deletes a policy profile. Fails if agent credentials still reference it.","operationId":"DeletePolicyProfile","responses":{"204":{"description":"Policy profile deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Policy profile is still referenced by agent credentials."}},"summary":"Delete a policy profile","tags":["Policies"],"x-feature-flag":"agent-gateway"},"get":{"description":"Returns a single policy profile by ID.","operationId":"GetPolicyProfile","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyProfile"}}},"description":"The policy profile."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a policy profile","tags":["Policies"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/PolicyId"}],"put":{"description":"Updates a policy profile. Changes hot-reload to active agent sessions.","operationId":"UpdatePolicyProfile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyProfileInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyProfile"}}},"description":"Updated policy profile."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Update a policy profile","tags":["Policies"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/policy-evaluations":{"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Evaluates a single SQL statement against a policy (either a draft policy supplied inline or an existing policy referenced by id) and returns the decision the proxy would make: allow, block, mask, or row-filter. The evaluation reuses the data plane's own policy engine (the same parser, allow/block rules, row-filter rewriter, and masking analysis enforced on live agent sessions), so a what-if verdict matches real enforcement. Stateful checks a single-statement preview cannot model (per-region query and egress budgets, human approvals, and rollback/sandbox write routing) are reported as informational notes, not verdicts. This is a pure compute endpoint; it does not connect to the upstream database and persists nothing.","operationId":"DryEvalPolicy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DryEvalInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DryEvalResult"}}},"description":"The dry-eval decision."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Dry-eval a policy against a SQL statement","tags":["Policies"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/policy-replays":{"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Replays the project's recorded agent audit traffic against a candidate policy (either a draft supplied inline or an existing policy referenced by id) and reports what would change: which queries that ran would now be blocked, which blocked queries would now be permitted, and which results would be masked or row-filtered. Traffic is deduplicated by normalized query shape, newest first, and every statement is evaluated through the data plane's own policy engine, so the verdicts match real enforcement. Stateful checks (budgets, approvals, write-mode routing) are reported as informational notes on each result, not verdicts. This endpoint reads only the audit log; it never connects to the upstream database and persists nothing.","operationId":"ReplayPolicy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyReplayInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyReplayResult"}}},"description":"The replay summary and per-query decisions."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Replay recorded agent traffic against a policy","tags":["Policies"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/schema-annotations":{"delete":{"description":"Removes a single annotation identified by its natural key. Omit column_name to delete a table-level annotation, and omit schema_name to match the unqualified form.\n","operationId":"DeleteSchemaAnnotation","parameters":[{"description":"Relation (table or view) the annotation describes.","in":"query","name":"table_name","required":true,"schema":{"maxLength":255,"minLength":1,"type":"string"}},{"description":"Optional schema. Omit to match the unqualified form.","in":"query","name":"schema_name","schema":{"maxLength":255,"type":"string"}},{"description":"Optional column. Omit to delete a table-level annotation.","in":"query","name":"column_name","schema":{"maxLength":255,"type":"string"}}],"responses":{"204":{"description":"Annotation deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a schema annotation","tags":["SchemaAnnotations"]},"get":{"description":"Lists the project's human-written table and column descriptions. These are surfaced to connected agents through the MCP schema catalog.\n","operationId":"ListSchemaAnnotations","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSchemaAnnotationsResponse"}}},"description":"List of schema annotations."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List schema annotations","tags":["SchemaAnnotations"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"put":{"description":"Attaches an operator-written description to a table (omit column_name) or a column. Keyed by (schema_name, table_name, column_name); an existing annotation with the same key is replaced.\n","operationId":"PutSchemaAnnotation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaAnnotationInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaAnnotation"}}},"description":"The created or updated annotation."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create or replace a schema annotation","tags":["SchemaAnnotations"]}},"/v1/projects/{project_id}/usage":{"get":{"description":"Returns daily usage data for a specific project, broken down by region.","operationId":"GetProjectUsage","parameters":[{"$ref":"#/components/parameters/ProjectId"},{"description":"Start date (inclusive, YYYY-MM-DD).","in":"query","name":"start_date","required":true,"schema":{"example":"2024-01-01","format":"date","type":"string"}},{"description":"End date (inclusive, YYYY-MM-DD).","in":"query","name":"end_date","required":true,"schema":{"example":"2024-01-31","format":"date","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUsageResponse"}}},"description":"Daily usage data by region."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get project usage","tags":["Analytics"]}},"/v1/projects/{project_id}/usage/agents":{"get":{"description":"Aggregates the audit trail into per-agent usage for a window: statements by decision, rows and bytes returned, the cache outcome breakdown, and latency percentiles. Read-only, derived entirely from entries the gateway already records.\n\nGrouped by credential, not by session. `session_id` is 32 bits of randomness minted per connection, so it identifies a connection rather than an agent or a run, and at scale it collides; the credential is the only stable identity in the trail.\n\nThis endpoint reports usage and deliberately attributes no dollar figure to an agent. Overage is computed on the organization's total against a plan limit, so no single agent causes it independently of the others, and any per-agent split of that bill is a policy choice rather than a measurement. The organization's limits and marginal rates are returned alongside the usage so a caller can apply its own policy, with both meanings of a zero limit already resolved.\n\nThree things are reported rather than assumed. Usage recorded against no credential is its own line, so agents plus unattributed equals totals exactly. Latency covers only entries that ran and carried a finite value: every refusal writes a literal zero because there was nothing to time, and counting those would drag an agent's percentiles toward zero in proportion to how often it was refused, so the heavily blocked agent would report the fastest queries. And gap markers left by undelivered entries set `complete` to false, since a total over a trail with holes in it is a floor, not a measurement.\n\nBoth `start` and `end` are optional. Omitting `end` means now; omitting `start` means 30 days before the end. The window is half-open and is capped at 92 days, because this aggregate reads every row in the window on the request path and an unbounded one would sort a year of latencies per group. `requested_start` and `requested_end` echo the window that was actually used, so a caller that pinned neither still knows what the totals cover.","operationId":"GetAgentUsageBreakdown","parameters":[{"$ref":"#/components/parameters/AuditStart"},{"$ref":"#/components/parameters/AuditEnd"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentUsageReport"}}},"description":"Per-agent usage for the window."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Break down project usage by agent credential","tags":["Agents"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}]},"/v1/projects/{project_id}/webhooks":{"get":{"description":"Lists webhook endpoints for the project.","operationId":"ListWebhookEndpoints","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookEndpointsResponse"}}},"description":"List of webhook endpoints."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List webhook endpoints","tags":["Webhooks"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Creates a webhook endpoint that receives project event deliveries.","operationId":"CreateWebhookEndpoint","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"description":"Webhook endpoint created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Create a webhook endpoint","tags":["Webhooks"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/webhooks/{webhook_id}":{"delete":{"description":"Deletes a webhook endpoint and its pending deliveries.","operationId":"DeleteWebhookEndpoint","responses":{"204":{"description":"Webhook endpoint deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a webhook endpoint","tags":["Webhooks"],"x-feature-flag":"agent-gateway"},"get":{"description":"Returns a single webhook endpoint by ID.","operationId":"GetWebhookEndpoint","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"description":"The webhook endpoint."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a webhook endpoint","tags":["Webhooks"],"x-feature-flag":"agent-gateway"},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WebhookId"}],"put":{"description":"Updates a webhook endpoint.","operationId":"UpdateWebhookEndpoint","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"description":"Updated webhook endpoint."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a webhook endpoint","tags":["Webhooks"],"x-feature-flag":"agent-gateway"}},"/v1/projects/{project_id}/webhooks/{webhook_id}/test":{"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WebhookId"}],"post":{"description":"Enqueues a test event delivery to the webhook endpoint.","operationId":"TestWebhookEndpoint","responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResponse"}}},"description":"Test delivery enqueued."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Send a test event","tags":["Webhooks"],"x-feature-flag":"agent-gateway"}},"/v1/regions":{"get":{"description":"Returns all active data plane regions.","operationId":"ListRegions","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRegionsResponse"}}},"description":"List of regions."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List available regions","tags":["Platform"]}},"/v1/vercel/webhook":{}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"servers":[{"description":"Production","url":"https://api.pgbeam.com"}],"tags":[{"description":"Project lifecycle, custom domains, read replicas, and cache rules","name":"Projects","x-icon":"FolderKanban"},{"description":"Database connection management per project","name":"Databases","x-icon":"Database"},{"description":"Policy profiles enforced on agent credentials","name":"Policies","x-icon":"ShieldCheck"},{"description":"Scoped agent credentials for AI agent database access","name":"Agents","x-icon":"Bot"},{"description":"Human approval workflow for held agent statements","name":"Approvals","x-icon":"CircleCheck"},{"description":"Event delivery endpoints for project audit and anomaly events","name":"Webhooks","x-icon":"Webhook"},{"description":"Decoy (canary) relations that trip on agent access","name":"Honeytokens","x-icon":"Fingerprint"},{"description":"Human-written table and column descriptions for the schema catalog","name":"SchemaAnnotations","x-icon":"BookText"},{"description":"Customer relationship management: companies, contacts, deals, and an autonomous research task queue that enriches them.","name":"Crm","x-icon":"Contact"},{"description":"Anomalous-behavior alerts surfaced by the gateway","name":"Anomalies","x-icon":"TriangleAlert"},{"description":"Ephemeral sandbox branches for write isolation","name":"Branches","x-icon":"GitBranch"},{"description":"Migration safety linting for schema changes","name":"Migrations","x-icon":"FileCog"},{"description":"Usage metrics, billing data, and query insights","name":"Analytics","x-icon":"ChartLine"},{"description":"Regions and health checks","name":"Platform","x-icon":"Globe"},{"description":"Account data, privacy controls, and onboarding","name":"Account","x-icon":"CircleUser"},{"description":"Support case management","name":"Support","x-icon":"LifeBuoy"},{"description":"Internal service-to-service endpoints","name":"Internal"},{"description":"Vercel Marketplace Partner API endpoints","name":"Marketplace"},{"description":"Vercel Marketplace inbound webhook (invoice lifecycle). Authenticated by HMAC-SHA1 signature, not OIDC, so it is registered manually rather than through the generated Marketplace server interface.","name":"MarketplaceWebhook"},{"description":"AWS Marketplace integration endpoints","name":"AWSMarketplace"},{"description":"Model Context Protocol (MCP) remote server endpoint","name":"MCP","x-sdk-exclude":["go","ts"]}],"x-iac-resources":{"AgentCredential":{"adoption":{"list-query-params":{"page_size":100},"match-fields":["name"]},"description":"Manages a scoped agent credential (a PgBeam-issued Postgres login plus a hosted MCP token) for an AI agent. The connection string and MCP token are one-time secrets returned only at creation and exposed as sensitive computed outputs; they cannot be retrieved again. To rotate the secrets, taint/replace the resource (or use the rotate endpoint out of band).","extra-outputs":{"connection_string":{"description":"One-time guarded Postgres connection string for this agent credential (shown once).","path":"connection_string","sensitive":true},"mcp_token":{"description":"One-time bearer token for the hosted MCP endpoint (shown once).","path":"mcp_token","sensitive":true},"mcp_url":{"description":"Hosted agent-database MCP endpoint for this project. Use with the mcp_token as a bearer token.","path":"mcp_url"}},"operations":{"create":"createAgentCredential","delete":"revokeAgentCredential","list":"listAgentCredentials","read":"getAgentCredential","update":"updateAgentCredentialStatus"}},"CacheRule":{"description":"Manages a per-query cache rule. Deletion disables caching (soft-delete).","id-field":"query_hash","operations":{"list":"listCacheRules","upsert":"updateCacheRule"},"soft-delete":{"cache_enabled":false}},"CustomDomain":{"connection-details":["dns_verification_token"],"description":"Manages a custom domain for a PgBeam project.","operations":{"create":"createCustomDomain","delete":"deleteCustomDomain","list":"listCustomDomains","verify":"verifyCustomDomain"}},"Database":{"connection-details":["connection_string"],"description":"Manages an upstream database connection within a PgBeam project.","operations":{"create":"createDatabase","delete":"deleteDatabase","list":"listDatabases","read":"getDatabase","update":"updateDatabase"}},"Honeytoken":{"description":"Manages a honeytoken: a decoy (canary) relation that no legitimate query should ever touch. Any agent statement referencing it is blocked and recorded as a canary_tripped audit event; the kill action additionally disables the tripping credential via the kill-switch. The relation does not have to exist in the upstream database: enforcement is by name, in the wire protocol, before the statement reaches Postgres.","operations":{"create":"createHoneytoken","delete":"deleteHoneytoken","list":"listHoneytokens","read":"getHoneytoken","update":"updateHoneytoken"}},"PolicyProfile":{"adoption":{"list-query-params":{"page_size":100},"match-fields":["name"]},"description":"Manages a policy profile: a named bundle of agent-gateway enforcement rules (access mode, table allow/deny lists, statement-kind rules, PII masking rules, per-relation row filters, query/egress budgets, write mode, approvals, and migration safety) attached to agent credentials and enforced in the PG wire protocol. Nested-list fields (masking_rules, row_filters) and the nested statement_rules object are expressed as structured config.","operations":{"create":"createPolicyProfile","delete":"deletePolicyProfile","list":"listPolicyProfiles","read":"getPolicyProfile","update":"updatePolicyProfile"}},"Project":{"adoption":{"list-query-params":{"org_id":"org_id","page_size":100},"match-fields":["name"]},"connection-details":["proxy_host"],"description":"Manages a PgBeam project with a primary database.","extra-outputs":{"primary_database_id":{"description":"ID of the primary database created with this project.","path":"database.id"}},"operations":{"create":"createProject","delete":"deleteProject","list":"listProjects","read":"getProject","update":"updateProject"}},"Replica":{"description":"Manages a read replica for a PgBeam database.","operations":{"create":"createReplica","delete":"deleteReplica","list":"listReplicas"}},"SelfHostEnrollment":{"description":"Manages a self-host (BYOC) enrollment: a token a self-hosted proxy uses to authenticate to the control plane's config/audit stream. The token is a one-time secret returned only at creation and exposed as a sensitive computed output; it cannot be retrieved again. To rotate the token, replace the resource. Deletion revokes the enrollment.","extra-outputs":{"token":{"description":"One-time enrollment token (pbh_...) for the self-hosted proxy's GRPC_AUTH_TOKEN (shown once).","path":"token","sensitive":true}},"operations":{"create":"createSelfHostEnrollment","delete":"revokeSelfHostEnrollment","list":"listSelfHostEnrollments"}},"SpendLimit":{"description":"Manages the monthly spend limit for an organization.","id-field":"org_id","operations":{"read":"getOrganizationPlan","upsert":"updateSpendLimit"},"soft-delete":{"spend_limit":null}},"WebhookEndpoint":{"adoption":{"list-query-params":{"page_size":100},"match-fields":["url"]},"description":"Manages a webhook endpoint that receives project audit and anomaly event deliveries. The signing secret is write-only and never returned by the API.","operations":{"create":"createWebhookEndpoint","delete":"deleteWebhookEndpoint","list":"listWebhookEndpoints","read":"getWebhookEndpoint","update":"updateWebhookEndpoint"}}}}