fraudshield/specs/001-fraud-detection-engine/contracts/api.yaml
Felipe Domingues 7f9832bf4b plan: add implementation plan for fraud detection engine
Stack: Python 3.12/FastAPI + React 19/TypeScript + PostgreSQL + Redis.
6 artifacts: plan.md, research.md, data-model.md, api.yaml (OpenAPI),
quickstart.md, updated AGENTS.md. Constitution check: 6/6 PASS.
2026-05-12 14:58:21 -03:00

803 lines
19 KiB
YAML

openapi: "3.0.3"
info:
title: FraudShield API
version: "1.0.0"
description: API do motor de detecção de fraudes bancárias.
servers:
- url: http://localhost:8000/api/v1
description: Local development
paths:
/transactions/ingest:
post:
summary: Ingest transaction for fraud evaluation
operationId: ingestTransaction
tags: [Transactions]
security:
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/TransactionIngestRequest"
responses:
"202":
description: Transaction accepted for processing
content:
application/json:
schema:
$ref: "#/components/schemas/TransactionAccepted"
"400":
$ref: "#/components/responses/ValidationError"
"429":
description: Rate limit exceeded
"503":
description: Service unavailable (backpressure)
/transactions/{transaction_id}:
get:
summary: Get transaction details with evaluation result
operationId: getTransaction
tags: [Transactions]
security:
- BearerAuth: []
parameters:
- name: transaction_id
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Transaction details
content:
application/json:
schema:
$ref: "#/components/schemas/TransactionDetail"
"404":
description: Transaction not found
/alerts:
get:
summary: List fraud alerts with filters
operationId: listAlerts
tags: [Alerts]
security:
- BearerAuth: []
parameters:
- name: status
in: query
schema:
type: string
enum: [pending, confirmed, false_positive, escalated]
- name: min_score
in: query
schema:
type: integer
minimum: 0
maximum: 100
- name: from_date
in: query
schema:
type: string
format: date-time
- name: to_date
in: query
schema:
type: string
format: date-time
- name: triggered_rule
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 200
- name: offset
in: query
schema:
type: integer
default: 0
responses:
"200":
description: Paginated alert list
content:
application/json:
schema:
$ref: "#/components/schemas/AlertListResponse"
/alerts/{alert_id}:
get:
summary: Get alert details
operationId: getAlert
tags: [Alerts]
security:
- BearerAuth: []
parameters:
- name: alert_id
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Alert details with full explanation
content:
application/json:
schema:
$ref: "#/components/schemas/AlertDetail"
"404":
description: Alert not found
/alerts/{alert_id}/decide:
post:
summary: Submit investigation decision
operationId: decideAlert
tags: [Alerts]
security:
- BearerAuth: []
parameters:
- name: alert_id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AlertDecisionRequest"
responses:
"200":
description: Decision recorded
content:
application/json:
schema:
$ref: "#/components/schemas/AlertDetail"
"400":
$ref: "#/components/responses/ValidationError"
"409":
description: Alert already decided
/rules:
get:
summary: List detection rules
operationId: listRules
tags: [Rules]
security:
- BearerAuth: []
- AdminAuth: []
parameters:
- name: is_active
in: query
schema:
type: boolean
responses:
"200":
description: Rule list
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/DetectionRule"
post:
summary: Create new detection rule
operationId: createRule
tags: [Rules]
security:
- BearerAuth: []
- AdminAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateRuleRequest"
responses:
"201":
description: Rule created (inactive by default)
content:
application/json:
schema:
$ref: "#/components/schemas/DetectionRule"
"400":
$ref: "#/components/responses/ValidationError"
/rules/{rule_id}:
get:
summary: Get rule details
operationId: getRule
tags: [Rules]
security:
- BearerAuth: []
- AdminAuth: []
parameters:
- name: rule_id
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Rule details
content:
application/json:
schema:
$ref: "#/components/schemas/DetectionRule"
put:
summary: Update detection rule
operationId: updateRule
tags: [Rules]
security:
- BearerAuth: []
- AdminAuth: []
parameters:
- name: rule_id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateRuleRequest"
responses:
"200":
description: Rule updated
content:
application/json:
schema:
$ref: "#/components/schemas/DetectionRule"
/rules/{rule_id}/activate:
post:
summary: Activate a rule
operationId: activateRule
tags: [Rules]
security:
- BearerAuth: []
- AdminAuth: []
parameters:
- name: rule_id
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Rule activated
"400":
description: Rule has no weight or threshold set
/rules/{rule_id}/deactivate:
post:
summary: Deactivate a rule
operationId: deactivateRule
tags: [Rules]
security:
- BearerAuth: []
- AdminAuth: []
parameters:
- name: rule_id
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Rule deactivated
/rules/{rule_id}/test:
post:
summary: Test rule against historical data
operationId: testRule
tags: [Rules]
security:
- BearerAuth: []
- AdminAuth: []
parameters:
- name: rule_id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/TestRuleRequest"
responses:
"200":
description: Test results
content:
application/json:
schema:
$ref: "#/components/schemas/TestRuleResponse"
/dashboard/metrics:
get:
summary: Get real-time dashboard metrics
operationId: getDashboardMetrics
tags: [Dashboard]
security:
- BearerAuth: []
parameters:
- name: period
in: query
schema:
type: string
enum: [24h, 7d, 30d, 90d]
default: 24h
responses:
"200":
description: Dashboard metrics
content:
application/json:
schema:
$ref: "#/components/schemas/DashboardMetrics"
/dashboard/report:
get:
summary: Export compliance report
operationId: exportReport
tags: [Dashboard]
security:
- BearerAuth: []
parameters:
- name: from_date
in: query
required: true
schema:
type: string
format: date
- name: to_date
in: query
required: true
schema:
type: string
format: date
- name: format
in: query
schema:
type: string
enum: [pdf, csv]
default: pdf
responses:
"200":
description: Report file
content:
application/pdf:
schema:
type: string
format: binary
text/csv:
schema:
type: string
format: binary
/health:
get:
summary: Health check
operationId: healthCheck
tags: [System]
responses:
"200":
description: Service healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: healthy
version:
type: string
example: "1.0.0"
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
AdminAuth: {}
schemas:
TransactionIngestRequest:
type: object
required: [external_id, amount, merchant_name, merchant_category, customer_id, channel, transaction_at]
properties:
external_id:
type: string
description: ID original do sistema bancário
amount:
type: number
format: decimal
minimum: 0.01
example: 5000.00
merchant_name:
type: string
example: "Loja Exemplo Ltda"
merchant_category:
type: string
example: "eletrônicos"
latitude:
type: number
format: float
nullable: true
longitude:
type: number
format: float
nullable: true
customer_id:
type: string
description: Token do cliente
example: "tok_abc123xyz"
channel:
type: string
enum: [web, mobile, pos]
transaction_at:
type: string
format: date-time
TransactionAccepted:
type: object
properties:
transaction_id:
type: string
format: uuid
status:
type: string
example: accepted
trace_id:
type: string
format: uuid
TransactionDetail:
type: object
properties:
id:
type: string
format: uuid
external_id:
type: string
amount:
type: number
merchant_name:
type: string
merchant_category:
type: string
latitude:
type: number
nullable: true
longitude:
type: number
nullable: true
customer_id:
type: string
channel:
type: string
transaction_at:
type: string
format: date-time
ingested_at:
type: string
format: date-time
alert:
$ref: "#/components/schemas/AlertDetail"
nullable: true
AlertListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/AlertSummary"
total:
type: integer
limit:
type: integer
offset:
type: integer
AlertSummary:
type: object
properties:
id:
type: string
format: uuid
score:
type: integer
status:
type: string
amount:
type: number
merchant_name:
type: string
top_rule:
type: string
created_at:
type: string
format: date-time
AlertDetail:
type: object
properties:
id:
type: string
format: uuid
transaction_id:
type: string
format: uuid
score:
type: integer
triggered_rules:
type: array
items:
type: object
properties:
rule_id:
type: string
format: uuid
rule_name:
type: string
score:
type: integer
explanation:
type: string
explanation:
type: string
description: Explicação composta em linguagem natural
status:
type: string
enum: [pending, confirmed, false_positive, escalated]
assigned_to:
type: string
nullable: true
decision:
type: string
nullable: true
decided_by:
type: string
nullable: true
decided_at:
type: string
format: date-time
nullable: true
justification:
type: string
nullable: true
created_at:
type: string
format: date-time
AlertDecisionRequest:
type: object
required: [decision]
properties:
decision:
type: string
enum: [confirmed, false_positive, escalated]
justification:
type: string
description: Required for false_positive and escalated
notes:
type: string
DetectionRule:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
description:
type: string
condition:
type: string
weight:
type: integer
minimum: 0
maximum: 100
threshold:
type: integer
minimum: 0
maximum: 100
is_active:
type: boolean
version:
type: integer
created_by:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
CreateRuleRequest:
type: object
required: [name, description, condition]
properties:
name:
type: string
example: "Valor atípico"
description:
type: string
example: "Detecta transações com valor muito acima da média do cliente"
condition:
type: string
example: "amount > customer.avg_amount_30d * 3"
weight:
type: integer
minimum: 0
maximum: 100
default: 0
threshold:
type: integer
minimum: 0
maximum: 100
default: 0
UpdateRuleRequest:
type: object
properties:
name:
type: string
description:
type: string
condition:
type: string
weight:
type: integer
minimum: 0
maximum: 100
threshold:
type: integer
minimum: 0
maximum: 100
TestRuleRequest:
type: object
properties:
days_back:
type: integer
default: 90
maximum: 90
TestRuleResponse:
type: object
properties:
rule_id:
type: string
format: uuid
total_transactions_evaluated:
type: integer
example: 50000
would_trigger_count:
type: integer
example: 1250
would_trigger_pct:
type: number
example: 2.5
score_distribution:
type: object
properties:
p50:
type: number
p90:
type: number
p95:
type: number
max:
type: number
estimated_false_positives:
type: integer
description: Based on analyst decisions on similar patterns
sample_alerts:
type: array
items:
$ref: "#/components/schemas/AlertSummary"
DashboardMetrics:
type: object
properties:
period:
type: string
total_transactions:
type: integer
total_alerts:
type: integer
fraud_rate_pct:
type: number
description: Alertas confirmados / total de transações
false_positive_rate_pct:
type: number
avg_decision_time_seconds:
type: number
alerts_by_status:
type: object
properties:
pending:
type: integer
confirmed:
type: integer
false_positive:
type: integer
escalated:
type: integer
alerts_by_hour:
type: array
items:
type: object
properties:
hour:
type: integer
count:
type: integer
top_triggering_rules:
type: array
items:
type: object
properties:
rule_name:
type: string
alert_count:
type: integer
score_distribution:
type: object
properties:
low:
type: integer
medium:
type: integer
high:
type: integer
critical:
type: integer
responses:
ValidationError:
description: Validation error
content:
application/json:
schema:
type: object
properties:
detail:
type: string
errors:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string