veylant/docs/openapi.yaml
2026-02-23 13:35:04 +01:00

1374 lines
38 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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, 12 → limited, 34 → 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