1374 lines
38 KiB
YAML
1374 lines
38 KiB
YAML
openapi: 3.1.0
|
||
|
||
info:
|
||
title: Veylant IA Proxy API
|
||
version: 1.0.0
|
||
description: |
|
||
Enterprise AI governance gateway — OpenAI-compatible proxy with PII anonymization,
|
||
RBAC, audit logging, dynamic routing, GDPR/EU AI Act compliance, and cost tracking.
|
||
|
||
All `/v1/*` endpoints require a Bearer JWT token issued by Keycloak.
|
||
The token must contain `tenant_id`, `user_id`, and `roles` claims.
|
||
|
||
contact:
|
||
name: Veylant IA Support
|
||
url: https://veylant.ai
|
||
|
||
servers:
|
||
- url: http://localhost:8090
|
||
description: Local development
|
||
- url: https://api.veylant.ai
|
||
description: Production
|
||
|
||
security:
|
||
- BearerAuth: []
|
||
|
||
components:
|
||
securitySchemes:
|
||
BearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
bearerFormat: JWT
|
||
description: Keycloak-issued JWT. Claims must include `tenant_id`, `user_id`, `roles`.
|
||
|
||
schemas:
|
||
# ─── Chat ────────────────────────────────────────────────────────────────
|
||
Message:
|
||
type: object
|
||
required: [role, content]
|
||
properties:
|
||
role:
|
||
type: string
|
||
enum: [system, user, assistant]
|
||
content:
|
||
type: string
|
||
|
||
ChatRequest:
|
||
type: object
|
||
required: [model, messages]
|
||
properties:
|
||
model:
|
||
type: string
|
||
example: gpt-4o
|
||
messages:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Message'
|
||
minItems: 1
|
||
stream:
|
||
type: boolean
|
||
default: false
|
||
temperature:
|
||
type: number
|
||
minimum: 0
|
||
maximum: 2
|
||
max_tokens:
|
||
type: integer
|
||
minimum: 1
|
||
|
||
Choice:
|
||
type: object
|
||
properties:
|
||
index:
|
||
type: integer
|
||
message:
|
||
$ref: '#/components/schemas/Message'
|
||
finish_reason:
|
||
type: string
|
||
enum: [stop, length, tool_calls, content_filter]
|
||
|
||
Usage:
|
||
type: object
|
||
properties:
|
||
prompt_tokens:
|
||
type: integer
|
||
completion_tokens:
|
||
type: integer
|
||
total_tokens:
|
||
type: integer
|
||
|
||
ChatResponse:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
object:
|
||
type: string
|
||
example: chat.completion
|
||
created:
|
||
type: integer
|
||
model:
|
||
type: string
|
||
choices:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Choice'
|
||
usage:
|
||
$ref: '#/components/schemas/Usage'
|
||
|
||
# ─── PII ─────────────────────────────────────────────────────────────────
|
||
PIIEntity:
|
||
type: object
|
||
properties:
|
||
type:
|
||
type: string
|
||
example: EMAIL_ADDRESS
|
||
text:
|
||
type: string
|
||
score:
|
||
type: number
|
||
start:
|
||
type: integer
|
||
end:
|
||
type: integer
|
||
|
||
PIIAnalyzeRequest:
|
||
type: object
|
||
required: [text]
|
||
properties:
|
||
text:
|
||
type: string
|
||
language:
|
||
type: string
|
||
default: fr
|
||
|
||
PIIAnalyzeResponse:
|
||
type: object
|
||
properties:
|
||
original_text:
|
||
type: string
|
||
anonymized_text:
|
||
type: string
|
||
entities:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/PIIEntity'
|
||
processing_time_ms:
|
||
type: integer
|
||
|
||
# ─── Routing Policies ────────────────────────────────────────────────────
|
||
Condition:
|
||
type: object
|
||
required: [field, operator, value]
|
||
properties:
|
||
field:
|
||
type: string
|
||
example: department
|
||
description: Field to evaluate (department, role, model, sensitivity, user_id)
|
||
operator:
|
||
type: string
|
||
enum: [eq, neq, in, not_in, gte, lte, contains, regex]
|
||
value:
|
||
description: Comparison value (string or array for in/not_in operators)
|
||
|
||
Action:
|
||
type: object
|
||
required: [provider]
|
||
properties:
|
||
provider:
|
||
type: string
|
||
example: openai
|
||
model:
|
||
type: string
|
||
description: Override the model sent upstream (optional)
|
||
example: gpt-4o-mini
|
||
|
||
RoutingRule:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
tenant_id:
|
||
type: string
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
priority:
|
||
type: integer
|
||
description: Lower value = evaluated first
|
||
is_enabled:
|
||
type: boolean
|
||
conditions:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Condition'
|
||
action:
|
||
$ref: '#/components/schemas/Action'
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
CreatePolicyRequest:
|
||
type: object
|
||
required: [name, action]
|
||
properties:
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
priority:
|
||
type: integer
|
||
default: 100
|
||
is_enabled:
|
||
type: boolean
|
||
default: true
|
||
conditions:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Condition'
|
||
action:
|
||
$ref: '#/components/schemas/Action'
|
||
|
||
# ─── Audit Logs ──────────────────────────────────────────────────────────
|
||
AuditEntry:
|
||
type: object
|
||
properties:
|
||
request_id:
|
||
type: string
|
||
tenant_id:
|
||
type: string
|
||
user_id:
|
||
type: string
|
||
timestamp:
|
||
type: string
|
||
format: date-time
|
||
model_requested:
|
||
type: string
|
||
model_used:
|
||
type: string
|
||
provider:
|
||
type: string
|
||
department:
|
||
type: string
|
||
user_role:
|
||
type: string
|
||
prompt_hash:
|
||
type: string
|
||
sensitivity_level:
|
||
type: string
|
||
enum: [low, medium, high, critical]
|
||
latency_ms:
|
||
type: integer
|
||
pii_entity_count:
|
||
type: integer
|
||
token_input:
|
||
type: integer
|
||
token_output:
|
||
type: integer
|
||
token_total:
|
||
type: integer
|
||
cost_usd:
|
||
type: number
|
||
stream:
|
||
type: boolean
|
||
status:
|
||
type: string
|
||
enum: [ok, error]
|
||
error_type:
|
||
type: string
|
||
|
||
AuditResult:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/AuditEntry'
|
||
total:
|
||
type: integer
|
||
|
||
# ─── Costs ───────────────────────────────────────────────────────────────
|
||
CostSummary:
|
||
type: object
|
||
properties:
|
||
key:
|
||
type: string
|
||
description: Grouping key (provider name, model name, or department)
|
||
total_tokens:
|
||
type: integer
|
||
total_cost_usd:
|
||
type: number
|
||
request_count:
|
||
type: integer
|
||
|
||
CostResult:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CostSummary'
|
||
|
||
# ─── Users ───────────────────────────────────────────────────────────────
|
||
User:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
tenant_id:
|
||
type: string
|
||
email:
|
||
type: string
|
||
format: email
|
||
first_name:
|
||
type: string
|
||
last_name:
|
||
type: string
|
||
department:
|
||
type: string
|
||
role:
|
||
type: string
|
||
enum: [admin, manager, user, auditor]
|
||
is_active:
|
||
type: boolean
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
CreateUserRequest:
|
||
type: object
|
||
required: [email, role]
|
||
properties:
|
||
email:
|
||
type: string
|
||
format: email
|
||
first_name:
|
||
type: string
|
||
last_name:
|
||
type: string
|
||
department:
|
||
type: string
|
||
role:
|
||
type: string
|
||
enum: [admin, manager, user, auditor]
|
||
|
||
# ─── Feature Flags ───────────────────────────────────────────────────────
|
||
FeatureFlag:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
tenant_id:
|
||
type: string
|
||
description: Empty string means global flag
|
||
name:
|
||
type: string
|
||
example: pii_enabled
|
||
is_enabled:
|
||
type: boolean
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
UpsertFlagRequest:
|
||
type: object
|
||
required: [enabled]
|
||
properties:
|
||
enabled:
|
||
type: boolean
|
||
|
||
# ─── Rate Limits ─────────────────────────────────────────────────────────
|
||
RateLimitConfig:
|
||
type: object
|
||
properties:
|
||
tenant_id:
|
||
type: string
|
||
requests_per_min:
|
||
type: integer
|
||
burst_size:
|
||
type: integer
|
||
user_rpm:
|
||
type: integer
|
||
user_burst:
|
||
type: integer
|
||
is_enabled:
|
||
type: boolean
|
||
|
||
# ─── Compliance ──────────────────────────────────────────────────────────
|
||
ProcessingEntry:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
tenant_id:
|
||
type: string
|
||
use_case_name:
|
||
type: string
|
||
legal_basis:
|
||
type: string
|
||
enum: [consent, contract, legal_obligation, vital_interests, public_task, legitimate_interest]
|
||
purpose:
|
||
type: string
|
||
data_categories:
|
||
type: array
|
||
items:
|
||
type: string
|
||
recipients:
|
||
type: array
|
||
items:
|
||
type: string
|
||
processors:
|
||
type: array
|
||
items:
|
||
type: string
|
||
retention_period:
|
||
type: string
|
||
example: 12 months
|
||
security_measures:
|
||
type: string
|
||
controller_name:
|
||
type: string
|
||
risk_level:
|
||
type: string
|
||
enum: [minimal, limited, high, forbidden, ""]
|
||
ai_act_answers:
|
||
type: object
|
||
additionalProperties:
|
||
type: boolean
|
||
is_active:
|
||
type: boolean
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
CreateProcessingEntryRequest:
|
||
type: object
|
||
required: [use_case_name, legal_basis, purpose, retention_period]
|
||
properties:
|
||
use_case_name:
|
||
type: string
|
||
legal_basis:
|
||
type: string
|
||
purpose:
|
||
type: string
|
||
data_categories:
|
||
type: array
|
||
items:
|
||
type: string
|
||
recipients:
|
||
type: array
|
||
items:
|
||
type: string
|
||
processors:
|
||
type: array
|
||
items:
|
||
type: string
|
||
retention_period:
|
||
type: string
|
||
security_measures:
|
||
type: string
|
||
controller_name:
|
||
type: string
|
||
|
||
ErasureRecord:
|
||
type: object
|
||
properties:
|
||
erasure_id:
|
||
type: string
|
||
tenant_id:
|
||
type: string
|
||
user_id:
|
||
type: string
|
||
requested_by:
|
||
type: string
|
||
reason:
|
||
type: string
|
||
records_deleted:
|
||
type: integer
|
||
status:
|
||
type: string
|
||
enum: [completed]
|
||
timestamp:
|
||
type: string
|
||
format: date-time
|
||
|
||
# ─── Provider Status ─────────────────────────────────────────────────────
|
||
ProviderStatus:
|
||
type: object
|
||
properties:
|
||
provider:
|
||
type: string
|
||
state:
|
||
type: string
|
||
enum: [closed, open, half-open]
|
||
failures:
|
||
type: integer
|
||
last_failure:
|
||
type: string
|
||
format: date-time
|
||
|
||
# ─── Errors ──────────────────────────────────────────────────────────────
|
||
APIError:
|
||
type: object
|
||
properties:
|
||
error:
|
||
type: object
|
||
properties:
|
||
type:
|
||
type: string
|
||
message:
|
||
type: string
|
||
code:
|
||
type: string
|
||
|
||
paths:
|
||
# ─── Health ──────────────────────────────────────────────────────────────────
|
||
/healthz:
|
||
get:
|
||
operationId: healthCheck
|
||
summary: Health check
|
||
description: Returns service health status. No authentication required.
|
||
security: []
|
||
tags: [health]
|
||
responses:
|
||
'200':
|
||
description: Service is healthy
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
status:
|
||
type: string
|
||
example: ok
|
||
|
||
# ─── Chat Completions ─────────────────────────────────────────────────────────
|
||
/v1/chat/completions:
|
||
post:
|
||
operationId: chatCompletions
|
||
summary: Chat completions (OpenAI-compatible)
|
||
description: |
|
||
Drop-in replacement for the OpenAI Chat Completions API. Requests are
|
||
processed through the PII anonymization pipeline, routed to the
|
||
appropriate provider, and logged to the immutable audit trail.
|
||
|
||
Set `stream: true` to receive Server-Sent Events (SSE).
|
||
tags: [proxy]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ChatRequest'
|
||
examples:
|
||
basic:
|
||
summary: Basic chat request
|
||
value:
|
||
model: gpt-4o
|
||
messages:
|
||
- role: user
|
||
content: Summarize the Q3 report.
|
||
streaming:
|
||
summary: Streaming request
|
||
value:
|
||
model: gpt-4o
|
||
messages:
|
||
- role: user
|
||
content: Explain GDPR Article 30.
|
||
stream: true
|
||
responses:
|
||
'200':
|
||
description: |
|
||
Non-streaming: JSON ChatResponse.
|
||
Streaming: `Content-Type: text/event-stream` with SSE chunks.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ChatResponse'
|
||
text/event-stream:
|
||
schema:
|
||
type: string
|
||
description: SSE stream of delta chunks
|
||
'400':
|
||
description: Invalid request body
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
'401':
|
||
description: Missing or invalid JWT
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
'403':
|
||
description: Model not allowed for this role (RBAC)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
'429':
|
||
description: Rate limit exceeded
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
'502':
|
||
description: Upstream provider error
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
# ─── PII Analysis ─────────────────────────────────────────────────────────────
|
||
/v1/pii/analyze:
|
||
post:
|
||
operationId: piiAnalyze
|
||
summary: Analyze text for PII entities
|
||
description: |
|
||
Detects and anonymizes PII in the provided text using regex, NER, and
|
||
optional LLM validation (three-layer pipeline). Useful for the Playground.
|
||
tags: [pii]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PIIAnalyzeRequest'
|
||
example:
|
||
text: "Bonjour, je m'appelle Jean Dupont, mon email est jean.dupont@acme.fr"
|
||
responses:
|
||
'200':
|
||
description: PII analysis result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PIIAnalyzeResponse'
|
||
'400':
|
||
description: Invalid request
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
'502':
|
||
description: PII service unavailable
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
# ─── Admin: Routing Policies ──────────────────────────────────────────────────
|
||
/v1/admin/policies:
|
||
get:
|
||
operationId: listPolicies
|
||
summary: List routing policies
|
||
description: Returns all active routing rules for the authenticated tenant.
|
||
tags: [admin-policies]
|
||
responses:
|
||
'200':
|
||
description: List of routing rules
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/RoutingRule'
|
||
|
||
post:
|
||
operationId: createPolicy
|
||
summary: Create a routing policy
|
||
tags: [admin-policies]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CreatePolicyRequest'
|
||
responses:
|
||
'201':
|
||
description: Created routing rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RoutingRule'
|
||
'400':
|
||
description: Validation error
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
/v1/admin/policies/seed/{template}:
|
||
post:
|
||
operationId: seedPolicyTemplate
|
||
summary: Seed a routing policy from a template
|
||
description: |
|
||
Creates a pre-configured routing rule from one of the built-in templates.
|
||
Valid templates: `hr`, `finance`, `engineering`, `catchall`.
|
||
tags: [admin-policies]
|
||
parameters:
|
||
- name: template
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
enum: [hr, finance, engineering, catchall]
|
||
responses:
|
||
'201':
|
||
description: Seeded routing rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RoutingRule'
|
||
'400':
|
||
description: Unknown template
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
/v1/admin/policies/{id}:
|
||
get:
|
||
operationId: getPolicy
|
||
summary: Get a routing policy by ID
|
||
tags: [admin-policies]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Routing rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RoutingRule'
|
||
'404':
|
||
description: Policy not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
put:
|
||
operationId: updatePolicy
|
||
summary: Update a routing policy
|
||
tags: [admin-policies]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CreatePolicyRequest'
|
||
responses:
|
||
'200':
|
||
description: Updated routing rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RoutingRule'
|
||
'404':
|
||
description: Policy not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
delete:
|
||
operationId: deletePolicy
|
||
summary: Delete a routing policy
|
||
tags: [admin-policies]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'204':
|
||
description: Policy deleted
|
||
'404':
|
||
description: Policy not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
# ─── Admin: Audit Logs ────────────────────────────────────────────────────────
|
||
/v1/admin/logs:
|
||
get:
|
||
operationId: getLogs
|
||
summary: Query audit logs
|
||
description: Returns paginated audit log entries for the authenticated tenant.
|
||
tags: [admin-logs]
|
||
parameters:
|
||
- name: provider
|
||
in: query
|
||
schema:
|
||
type: string
|
||
- name: min_sensitivity
|
||
in: query
|
||
schema:
|
||
type: string
|
||
enum: [low, medium, high, critical]
|
||
- name: start
|
||
in: query
|
||
description: RFC3339 timestamp
|
||
schema:
|
||
type: string
|
||
format: date-time
|
||
- name: end
|
||
in: query
|
||
description: RFC3339 timestamp
|
||
schema:
|
||
type: string
|
||
format: date-time
|
||
- name: limit
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
default: 50
|
||
- name: offset
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
default: 0
|
||
responses:
|
||
'200':
|
||
description: Audit log query result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AuditResult'
|
||
|
||
# ─── Admin: Costs ─────────────────────────────────────────────────────────────
|
||
/v1/admin/costs:
|
||
get:
|
||
operationId: getCosts
|
||
summary: Query cost aggregations
|
||
description: Returns token usage and cost grouped by provider, model, or department.
|
||
tags: [admin-logs]
|
||
parameters:
|
||
- name: group_by
|
||
in: query
|
||
schema:
|
||
type: string
|
||
enum: [provider, model, department]
|
||
- name: start
|
||
in: query
|
||
schema:
|
||
type: string
|
||
format: date-time
|
||
- name: end
|
||
in: query
|
||
schema:
|
||
type: string
|
||
format: date-time
|
||
responses:
|
||
'200':
|
||
description: Cost aggregation result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CostResult'
|
||
|
||
# ─── Admin: Users ─────────────────────────────────────────────────────────────
|
||
/v1/admin/users:
|
||
get:
|
||
operationId: listUsers
|
||
summary: List users
|
||
tags: [admin-users]
|
||
responses:
|
||
'200':
|
||
description: List of users
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/User'
|
||
|
||
post:
|
||
operationId: createUser
|
||
summary: Create a user
|
||
tags: [admin-users]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CreateUserRequest'
|
||
responses:
|
||
'201':
|
||
description: Created user
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
|
||
/v1/admin/users/{id}:
|
||
get:
|
||
operationId: getUser
|
||
summary: Get user by ID
|
||
tags: [admin-users]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: User
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
'404':
|
||
description: User not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
put:
|
||
operationId: updateUser
|
||
summary: Update a user
|
||
tags: [admin-users]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CreateUserRequest'
|
||
responses:
|
||
'200':
|
||
description: Updated user
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
|
||
delete:
|
||
operationId: deleteUser
|
||
summary: Delete (soft-delete) a user
|
||
tags: [admin-users]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'204':
|
||
description: User deleted
|
||
|
||
# ─── Admin: Feature Flags ─────────────────────────────────────────────────────
|
||
/v1/admin/flags:
|
||
get:
|
||
operationId: listFlags
|
||
summary: List feature flags
|
||
description: Returns all flags for the authenticated tenant plus global defaults.
|
||
tags: [admin-flags]
|
||
responses:
|
||
'200':
|
||
description: Feature flags
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/FeatureFlag'
|
||
|
||
/v1/admin/flags/{name}:
|
||
put:
|
||
operationId: upsertFlag
|
||
summary: Set a feature flag
|
||
description: |
|
||
Creates or updates a feature flag for the authenticated tenant.
|
||
Built-in flags: `pii_enabled`, `routing_enabled`, `billing_enabled`, `zero_retention`.
|
||
tags: [admin-flags]
|
||
parameters:
|
||
- name: name
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
example: pii_enabled
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/UpsertFlagRequest'
|
||
responses:
|
||
'200':
|
||
description: Updated feature flag
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/FeatureFlag'
|
||
|
||
delete:
|
||
operationId: deleteFlag
|
||
summary: Delete a feature flag
|
||
description: Removes a tenant-specific flag, reverting to the global default.
|
||
tags: [admin-flags]
|
||
parameters:
|
||
- name: name
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'204':
|
||
description: Flag deleted
|
||
'404':
|
||
description: Flag not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
# ─── Admin: Providers Status ──────────────────────────────────────────────────
|
||
/v1/admin/providers/status:
|
||
get:
|
||
operationId: getProviderStatus
|
||
summary: Get provider circuit breaker status
|
||
description: Returns the circuit breaker state for each configured provider.
|
||
tags: [admin-providers]
|
||
responses:
|
||
'200':
|
||
description: Provider statuses
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/ProviderStatus'
|
||
|
||
# ─── Admin: Rate Limits ───────────────────────────────────────────────────────
|
||
/v1/admin/rate-limits:
|
||
get:
|
||
operationId: listRateLimits
|
||
summary: List rate limit configurations
|
||
tags: [admin-rate-limits]
|
||
responses:
|
||
'200':
|
||
description: Rate limit configurations
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/RateLimitConfig'
|
||
|
||
/v1/admin/rate-limits/{tenant_id}:
|
||
get:
|
||
operationId: getRateLimit
|
||
summary: Get rate limit config for a tenant
|
||
tags: [admin-rate-limits]
|
||
parameters:
|
||
- name: tenant_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Rate limit config
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RateLimitConfig'
|
||
|
||
put:
|
||
operationId: upsertRateLimit
|
||
summary: Set rate limit config for a tenant
|
||
tags: [admin-rate-limits]
|
||
parameters:
|
||
- name: tenant_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RateLimitConfig'
|
||
responses:
|
||
'200':
|
||
description: Updated rate limit config
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RateLimitConfig'
|
||
|
||
delete:
|
||
operationId: deleteRateLimit
|
||
summary: Delete rate limit config for a tenant
|
||
tags: [admin-rate-limits]
|
||
parameters:
|
||
- name: tenant_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'204':
|
||
description: Rate limit config deleted
|
||
|
||
# ─── Admin: Compliance ────────────────────────────────────────────────────────
|
||
/v1/admin/compliance/entries:
|
||
get:
|
||
operationId: listComplianceEntries
|
||
summary: List GDPR Article 30 processing entries
|
||
tags: [admin-compliance]
|
||
responses:
|
||
'200':
|
||
description: Processing entries
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/ProcessingEntry'
|
||
|
||
post:
|
||
operationId: createComplianceEntry
|
||
summary: Create a processing entry
|
||
tags: [admin-compliance]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CreateProcessingEntryRequest'
|
||
responses:
|
||
'201':
|
||
description: Created processing entry
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ProcessingEntry'
|
||
|
||
/v1/admin/compliance/entries/{id}:
|
||
get:
|
||
operationId: getComplianceEntry
|
||
summary: Get a processing entry by ID
|
||
tags: [admin-compliance]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Processing entry
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ProcessingEntry'
|
||
'404':
|
||
description: Entry not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/APIError'
|
||
|
||
put:
|
||
operationId: updateComplianceEntry
|
||
summary: Update a processing entry
|
||
tags: [admin-compliance]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CreateProcessingEntryRequest'
|
||
responses:
|
||
'200':
|
||
description: Updated processing entry
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ProcessingEntry'
|
||
|
||
delete:
|
||
operationId: deleteComplianceEntry
|
||
summary: Delete a processing entry
|
||
tags: [admin-compliance]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'204':
|
||
description: Entry deleted
|
||
|
||
/v1/admin/compliance/entries/{id}/classify:
|
||
post:
|
||
operationId: classifyComplianceEntry
|
||
summary: Run EU AI Act risk classification
|
||
description: |
|
||
Scores the entry using the five-question questionnaire and sets `risk_level`:
|
||
0 yes → minimal, 1–2 → limited, 3–4 → high, 5 → forbidden.
|
||
tags: [admin-compliance]
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
ai_act_answers:
|
||
type: object
|
||
description: Answers to q1..q5 (true/false)
|
||
additionalProperties:
|
||
type: boolean
|
||
example:
|
||
q1: true
|
||
q2: false
|
||
q3: true
|
||
q4: false
|
||
q5: true
|
||
responses:
|
||
'200':
|
||
description: Classified entry with updated risk_level
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ProcessingEntry'
|
||
|
||
/v1/admin/compliance/gdpr/access/{user_id}:
|
||
get:
|
||
operationId: gdprAccess
|
||
summary: GDPR Art. 15 — right of access
|
||
description: Returns all audit log entries for the given user (data subject access request).
|
||
tags: [admin-compliance]
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: GDPR access report
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
user_id:
|
||
type: string
|
||
generated_at:
|
||
type: string
|
||
format: date-time
|
||
total:
|
||
type: integer
|
||
records:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/AuditEntry'
|
||
|
||
/v1/admin/compliance/gdpr/erase/{user_id}:
|
||
delete:
|
||
operationId: gdprErase
|
||
summary: GDPR Art. 17 — right to erasure
|
||
description: |
|
||
Soft-deletes the user and creates an immutable erasure log entry.
|
||
An erasure log record is always created even if `db` is nil (graceful degradation).
|
||
tags: [admin-compliance]
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
- name: reason
|
||
in: query
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Erasure confirmation
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErasureRecord'
|
||
|
||
tags:
|
||
- name: health
|
||
description: Service health
|
||
- name: proxy
|
||
description: AI proxy (OpenAI-compatible)
|
||
- name: pii
|
||
description: PII detection and anonymization
|
||
- name: admin-policies
|
||
description: Routing policy management
|
||
- name: admin-logs
|
||
description: Audit logs and cost reporting
|
||
- name: admin-users
|
||
description: User management
|
||
- name: admin-flags
|
||
description: Feature flag management
|
||
- name: admin-providers
|
||
description: Provider circuit breaker status
|
||
- name: admin-rate-limits
|
||
description: Rate limit configuration
|
||
- name: admin-compliance
|
||
description: GDPR / EU AI Act compliance registry
|