1113 lines
47 KiB
YAML
1113 lines
47 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: InvestMoz API
|
|
version: 1.0.0
|
|
summary: Contrato consolidado da API do InvestMoz
|
|
description: |
|
|
Contrato consolidado para catálogos, oportunidades, manifestações de interesse,
|
|
simulações, legislação, jobs, relatórios e administração. Valores de taxas,
|
|
reduções e parâmetros de simulação são fornecidos pelo utilizador; não são
|
|
taxas oficiais nem decisões de elegibilidade.
|
|
contact:
|
|
name: Equipa InvestMoz
|
|
license:
|
|
name: MIT
|
|
identifier: MIT
|
|
servers:
|
|
- url: /
|
|
description: Mesmo host da aplicação
|
|
security:
|
|
- sessionCookie: []
|
|
tags:
|
|
- name: Catálogos
|
|
description: Referências versionadas, estáveis e localizadas em pt-MZ.
|
|
- name: Oportunidades
|
|
description: Consulta pública de oportunidades de investimento.
|
|
- name: Manifestações
|
|
description: Submissão de interesse em oportunidades.
|
|
- name: Simulações
|
|
description: Execuções indicativas com snapshots e controlo de concorrência.
|
|
- name: Jobs
|
|
description: Estado dos trabalhos assíncronos associados a uma simulação.
|
|
- name: Relatórios
|
|
description: Leitura de snapshots imutáveis de relatórios.
|
|
- name: Legislação
|
|
description: Fontes legais publicadas e versionadas.
|
|
- name: Administração
|
|
description: Operações administrativas protegidas por sessão e autorização.
|
|
paths:
|
|
/api/v1/catalogs/{catalog}:
|
|
get:
|
|
tags: [Catálogos]
|
|
operationId: listReferenceCatalog
|
|
summary: Consultar catálogo versionado
|
|
security: []
|
|
parameters:
|
|
- $ref: '#/components/parameters/CatalogName'
|
|
- $ref: '#/components/parameters/Version'
|
|
- $ref: '#/components/parameters/CatalogType'
|
|
- $ref: '#/components/parameters/ParentId'
|
|
- $ref: '#/components/parameters/JurisdictionId'
|
|
- $ref: '#/components/parameters/Page'
|
|
- $ref: '#/components/parameters/PerPage'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Página do catálogo na versão solicitada
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/CatalogPage' }
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'422': { $ref: '#/components/responses/ValidationError' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/questionnaires/{code}:
|
|
get:
|
|
tags: [Simulações]
|
|
operationId: getPublishedQuestionnaire
|
|
summary: Consultar questionário publicado e versão imutável
|
|
security: []
|
|
parameters:
|
|
- $ref: '#/components/parameters/QuestionnaireCode'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Questionário publicado em pt-MZ
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/QuestionnaireResponse',
|
|
}
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/simulations:
|
|
post:
|
|
tags: [Simulações]
|
|
operationId: createSimulation
|
|
summary: Criar simulação rastreável
|
|
description: Requer Idempotency-Key. Acesso anónimo requer token opaco gerado pelo cliente.
|
|
x-implementation-status: implemented
|
|
security:
|
|
- sessionCookie: []
|
|
- {}
|
|
parameters:
|
|
- $ref: '#/components/parameters/IdempotencyKey'
|
|
- $ref: '#/components/parameters/SimulationToken'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/SimulationInput' }
|
|
examples:
|
|
BoundaryValues:
|
|
summary: Exemplo técnico nos limites mínimos
|
|
description: Valores mínimos para demonstrar a forma do payload; não são valores fiscais recomendados.
|
|
value: { base: 0, rate: 0, reduction: 0 }
|
|
responses:
|
|
'202':
|
|
description: Simulação aceite para processamento
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
Location: { $ref: '#/components/headers/Location' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/SimulationAccepted',
|
|
}
|
|
'200':
|
|
description: Repetição idempotente da resposta original
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/SimulationAccepted',
|
|
}
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'409': { $ref: '#/components/responses/Conflict' }
|
|
'422': { $ref: '#/components/responses/ValidationError' }
|
|
'428': { $ref: '#/components/responses/PreconditionRequired' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/simulations/{id}:
|
|
get:
|
|
tags: [Simulações]
|
|
operationId: getSimulation
|
|
summary: Consultar simulação, cenários e estado de execução
|
|
x-implementation-status: implemented
|
|
security:
|
|
- sessionCookie: []
|
|
- {}
|
|
parameters:
|
|
- $ref: '#/components/parameters/SimulationId'
|
|
- $ref: '#/components/parameters/SimulationToken'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Simulação dentro do âmbito autorizado
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/SimulationResponse',
|
|
}
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/simulations/{id}/scenarios/{scenarioId}:
|
|
patch:
|
|
tags: [Simulações]
|
|
operationId: updateSimulationScenario
|
|
summary: Actualizar cenário com controlo optimista de concorrência
|
|
x-implementation-status: implemented
|
|
security:
|
|
- sessionCookie: []
|
|
- {}
|
|
parameters:
|
|
- $ref: '#/components/parameters/SimulationId'
|
|
- $ref: '#/components/parameters/ScenarioId'
|
|
- $ref: '#/components/parameters/IfMatch'
|
|
- $ref: '#/components/parameters/SimulationToken'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{ $ref: '#/components/schemas/UpdateScenarioInput' }
|
|
responses:
|
|
'202':
|
|
description: Alteração aceite e reexecução colocada em fila
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/Scenario' }
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'412': { $ref: '#/components/responses/PreconditionFailed' }
|
|
'422': { $ref: '#/components/responses/ValidationError' }
|
|
'428': { $ref: '#/components/responses/PreconditionRequired' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/simulations/{id}/jobs:
|
|
get:
|
|
tags: [Jobs]
|
|
operationId: listSimulationJobs
|
|
summary: Consultar jobs de execução e geração de relatórios
|
|
description: Contrato reservado para consulta dos jobs associados à simulação.
|
|
x-implementation-status: contract-only
|
|
security:
|
|
- sessionCookie: []
|
|
- {}
|
|
parameters:
|
|
- $ref: '#/components/parameters/SimulationId'
|
|
- $ref: '#/components/parameters/SimulationToken'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Jobs visíveis no âmbito autorizado
|
|
headers:
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{ $ref: '#/components/schemas/JobCollection' }
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/simulations/{id}/reports/{reportId}:
|
|
get:
|
|
tags: [Relatórios]
|
|
operationId: getSimulationReport
|
|
summary: Obter snapshot imutável de relatório
|
|
x-implementation-status: implemented
|
|
security:
|
|
- sessionCookie: []
|
|
- {}
|
|
parameters:
|
|
- $ref: '#/components/parameters/SimulationId'
|
|
- $ref: '#/components/parameters/ReportId'
|
|
- $ref: '#/components/parameters/SimulationToken'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Snapshot e hash do relatório
|
|
headers:
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{ $ref: '#/components/schemas/ReportResponse' }
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/legislation/sources:
|
|
get:
|
|
tags: [Legislação]
|
|
operationId: listLegislationSources
|
|
summary: Consultar fontes legais publicadas e versionadas
|
|
description: Contrato reservado para catálogo público de fontes; administração usa a API v2 existente.
|
|
x-implementation-status: contract-only
|
|
security: []
|
|
parameters:
|
|
- $ref: '#/components/parameters/Page'
|
|
- $ref: '#/components/parameters/PerPage'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Fontes legais publicadas
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{ $ref: '#/components/schemas/LegislationPage' }
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'422': { $ref: '#/components/responses/ValidationError' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v2/investment/admin/legal-sources:
|
|
get:
|
|
tags: [Administração, Legislação]
|
|
operationId: adminListLegalSources
|
|
summary: Listar fontes legais para administração
|
|
x-implementation-status: implemented
|
|
security: [{ sessionCookie: [] }]
|
|
parameters:
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Lista de fontes legais
|
|
headers:
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/AdminLegalSourcePage',
|
|
}
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
post:
|
|
tags: [Administração, Legislação]
|
|
operationId: adminCreateLegalSource
|
|
summary: Registar fonte legal para validação
|
|
x-implementation-status: implemented
|
|
security: [{ sessionCookie: [] }]
|
|
parameters:
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{ $ref: '#/components/schemas/LegalSourceInput' }
|
|
responses:
|
|
'201':
|
|
description: Fonte legal registada
|
|
headers:
|
|
Location: { $ref: '#/components/headers/Location' }
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/LegalSource' }
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'409': { $ref: '#/components/responses/Conflict' }
|
|
'422': { $ref: '#/components/responses/ValidationError' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v2/investment/admin/legal-sources/{id}/{action}:
|
|
post:
|
|
tags: [Administração, Legislação]
|
|
operationId: adminTransitionLegalSource
|
|
summary: Validar ou revogar uma fonte legal
|
|
x-implementation-status: implemented
|
|
security: [{ sessionCookie: [] }]
|
|
parameters:
|
|
- $ref: '#/components/parameters/SourceId'
|
|
- name: action
|
|
in: path
|
|
required: true
|
|
schema: { type: string, enum: [validate, revoke] }
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/LegalSourceTransitionInput',
|
|
}
|
|
responses:
|
|
'200':
|
|
description: Estado actualizado
|
|
headers:
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/LegalSource' }
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'409': { $ref: '#/components/responses/Conflict' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/interest-requests:
|
|
post:
|
|
tags: [Manifestações]
|
|
operationId: submitInterestRequest
|
|
summary: Submeter manifestação de interesse
|
|
x-implementation-status: implemented
|
|
security: []
|
|
parameters:
|
|
- $ref: '#/components/parameters/IdempotencyKeyOptional'
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/InterestRequestInput',
|
|
}
|
|
responses:
|
|
'201':
|
|
description: Manifestação submetida
|
|
headers:
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/InterestRequestResponse',
|
|
}
|
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
'403': { $ref: '#/components/responses/Forbidden' }
|
|
'409': { $ref: '#/components/responses/Conflict' }
|
|
'422': { $ref: '#/components/responses/ValidationError' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
/api/v1/opportunities/{slug}:
|
|
get:
|
|
tags: [Oportunidades]
|
|
operationId: getOpportunity
|
|
summary: Consultar oportunidade publicada
|
|
x-implementation-status: implemented
|
|
security: []
|
|
parameters:
|
|
- name: slug
|
|
in: path
|
|
required: true
|
|
schema: { type: string, minLength: 1, maxLength: 180 }
|
|
- $ref: '#/components/parameters/CorrelationId'
|
|
responses:
|
|
'200':
|
|
description: Oportunidade publicada
|
|
headers:
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/OpportunityResponse',
|
|
}
|
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
'500': { $ref: '#/components/responses/ServerError' }
|
|
components:
|
|
securitySchemes:
|
|
sessionCookie:
|
|
type: apiKey
|
|
in: cookie
|
|
name: laravel-session
|
|
description: Sessão Laravel; o nome pode ser substituído por SESSION_COOKIE. Rotas públicas e simulações anónimas substituem explicitamente este requisito.
|
|
parameters:
|
|
CatalogName:
|
|
name: catalog
|
|
in: path
|
|
required: true
|
|
schema:
|
|
{
|
|
type: string,
|
|
enum: [authorities, jurisdictions, economic-activities],
|
|
}
|
|
Version:
|
|
name: version
|
|
in: query
|
|
required: false
|
|
description: Versão estável publicada do catálogo
|
|
schema: { type: integer, minimum: 1 }
|
|
CatalogType:
|
|
name: type
|
|
in: query
|
|
required: false
|
|
description: Obrigatório para jurisdictions.
|
|
schema:
|
|
{
|
|
type: string,
|
|
enum: [country, province, district, admin_post, locality],
|
|
}
|
|
ParentId:
|
|
name: parent_id
|
|
in: query
|
|
schema: { type: string, format: uuid }
|
|
JurisdictionId:
|
|
name: jurisdiction_id
|
|
in: query
|
|
schema: { type: string, format: uuid }
|
|
Page:
|
|
name: page
|
|
in: query
|
|
schema: { type: integer, minimum: 1, default: 1 }
|
|
PerPage:
|
|
name: per_page
|
|
in: query
|
|
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
|
|
Search:
|
|
name: q
|
|
in: query
|
|
schema: { type: string, maxLength: 100 }
|
|
QuestionnaireCode:
|
|
name: code
|
|
in: path
|
|
required: true
|
|
schema: { type: string, pattern: '^[a-z0-9][a-z0-9-]{0,79}$' }
|
|
SimulationId:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
ScenarioId:
|
|
name: scenarioId
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
ReportId:
|
|
name: reportId
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
SourceId:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
IdempotencyKey:
|
|
name: Idempotency-Key
|
|
in: header
|
|
required: true
|
|
description: Repetições com a mesma chave e payload devolvem a resposta original; payload diferente produz conflito.
|
|
schema: { type: string, minLength: 16, maxLength: 128 }
|
|
IdempotencyKeyOptional:
|
|
name: Idempotency-Key
|
|
in: header
|
|
required: false
|
|
description: Se fornecida, deve ser UUID; uma chave repetida com outro payload produz conflito.
|
|
schema: { type: string, format: uuid }
|
|
SimulationToken:
|
|
name: X-Simulation-Token
|
|
in: header
|
|
required: false
|
|
description: Obrigatório para acesso anónimo; token opaco do cliente, guardado apenas como hash.
|
|
schema: { type: string, minLength: 32, maxLength: 256 }
|
|
IfMatch:
|
|
name: If-Match
|
|
in: header
|
|
required: true
|
|
description: ETag forte da representação lida previamente.
|
|
schema: { type: string, minLength: 1, maxLength: 128 }
|
|
CorrelationId:
|
|
name: X-Correlation-ID
|
|
in: header
|
|
required: false
|
|
description: UUID opcional propagado pela aplicação; quando ausente, a aplicação cria um identificador.
|
|
schema: { type: string, format: uuid }
|
|
headers:
|
|
ETag:
|
|
description: Validador da representação; usado com If-Match em alterações concorrentes.
|
|
schema: { type: string }
|
|
Location:
|
|
description: URI relativa do recurso criado ou aceite.
|
|
schema: { type: string, format: uri-reference }
|
|
RetryAfter:
|
|
description: Segundos até à próxima tentativa.
|
|
schema: { type: integer, minimum: 0 }
|
|
CorrelationId:
|
|
description: Identificador de correlação da operação.
|
|
schema: { type: string, format: uuid }
|
|
responses:
|
|
Unauthorized:
|
|
description: Autenticação necessária ou sessão inválida
|
|
headers:
|
|
{
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' },
|
|
}
|
|
content:
|
|
{
|
|
application/json:
|
|
{ schema: { $ref: '#/components/schemas/Problem' } },
|
|
}
|
|
Forbidden:
|
|
description: Actor autenticado sem autorização para a operação
|
|
headers:
|
|
{
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' },
|
|
}
|
|
content:
|
|
{
|
|
application/json:
|
|
{ schema: { $ref: '#/components/schemas/Problem' } },
|
|
}
|
|
NotFound:
|
|
description: Recurso inexistente ou fora do âmbito visível
|
|
headers:
|
|
{
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' },
|
|
}
|
|
content:
|
|
{
|
|
application/json:
|
|
{ schema: { $ref: '#/components/schemas/Problem' } },
|
|
}
|
|
Conflict:
|
|
description: Conflito de estado, versão ou chave idempotente
|
|
headers:
|
|
{
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' },
|
|
}
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/Problem' }
|
|
example:
|
|
{
|
|
message: A chave foi reutilizada com conteúdo diferente.,
|
|
code: idempotency_conflict,
|
|
}
|
|
PreconditionFailed:
|
|
description: If-Match não corresponde ao ETag actual
|
|
headers:
|
|
ETag: { $ref: '#/components/headers/ETag' }
|
|
X-Correlation-ID: { $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/Problem' }
|
|
example:
|
|
{
|
|
message: A representação mudou; volte a consultar o recurso.,
|
|
code: stale_etag,
|
|
}
|
|
ValidationError:
|
|
description: Dados inválidos
|
|
headers:
|
|
{
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' },
|
|
}
|
|
content:
|
|
{
|
|
application/json:
|
|
{
|
|
schema:
|
|
{
|
|
$ref: '#/components/schemas/ValidationProblem',
|
|
},
|
|
},
|
|
}
|
|
RateLimited:
|
|
description: Limite de pedidos excedido
|
|
headers:
|
|
Retry-After: { $ref: '#/components/headers/RetryAfter' }
|
|
X-Correlation-ID: { $ref: '#/components/headers/CorrelationId' }
|
|
content:
|
|
{
|
|
application/json:
|
|
{ schema: { $ref: '#/components/schemas/Problem' } },
|
|
}
|
|
ServerError:
|
|
description: Erro interno; resposta não contém detalhes sensíveis
|
|
headers:
|
|
{
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' },
|
|
}
|
|
content:
|
|
{
|
|
application/json:
|
|
{ schema: { $ref: '#/components/schemas/Problem' } },
|
|
}
|
|
PreconditionRequired:
|
|
description: Header obrigatório em falta, como If-Match ou Idempotency-Key
|
|
headers:
|
|
{
|
|
X-Correlation-ID:
|
|
{ $ref: '#/components/headers/CorrelationId' },
|
|
}
|
|
content:
|
|
{
|
|
application/json:
|
|
{ schema: { $ref: '#/components/schemas/Problem' } },
|
|
}
|
|
schemas:
|
|
Problem:
|
|
type: object
|
|
required: [message]
|
|
properties:
|
|
message: { type: string }
|
|
code: { type: string }
|
|
correlation_id: { type: string, format: uuid }
|
|
additionalProperties: true
|
|
ValidationProblem:
|
|
allOf:
|
|
- $ref: '#/components/schemas/Problem'
|
|
- type: object
|
|
properties:
|
|
errors:
|
|
type: object
|
|
additionalProperties:
|
|
type: array
|
|
items: { type: string }
|
|
CatalogItem:
|
|
type: object
|
|
required: [id, value, code, name, label, locale, version_no]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
value: { type: string }
|
|
code: { type: string }
|
|
name:
|
|
{
|
|
type: string,
|
|
description: Rótulo apresentado em português de Moçambique.,
|
|
}
|
|
label: { type: string }
|
|
locale: { type: string, const: pt-MZ }
|
|
parent_id: { type: [string, 'null'] }
|
|
type:
|
|
{
|
|
type: [string, 'null'],
|
|
enum:
|
|
[
|
|
country,
|
|
province,
|
|
district,
|
|
admin_post,
|
|
locality,
|
|
'null',
|
|
],
|
|
}
|
|
authority_type: { type: [string, 'null'] }
|
|
organization_id: { type: [string, 'null'], format: uuid }
|
|
jurisdiction_id: { type: [string, 'null'], format: uuid }
|
|
jurisdiction_name: { type: [string, 'null'] }
|
|
source_code: { type: [string, 'null'] }
|
|
sector_id: { type: [string, 'null'] }
|
|
version_no: { type: integer }
|
|
CatalogPage:
|
|
type: object
|
|
required: [data, meta]
|
|
properties:
|
|
data:
|
|
{
|
|
type: array,
|
|
items: { $ref: '#/components/schemas/CatalogItem' },
|
|
}
|
|
links:
|
|
type: object
|
|
properties:
|
|
next: { type: [string, 'null'], format: uri-reference }
|
|
previous:
|
|
{ type: [string, 'null'], format: uri-reference }
|
|
next_page_url: { type: [string, 'null'], format: uri-reference }
|
|
prev_page_url: { type: [string, 'null'], format: uri-reference }
|
|
current_page: { type: integer }
|
|
per_page: { type: integer }
|
|
total: { type: integer }
|
|
last_page: { type: integer }
|
|
meta:
|
|
allOf:
|
|
- $ref: '#/components/schemas/Pagination'
|
|
- type: object
|
|
properties:
|
|
catalog: { type: string }
|
|
version: { type: [integer, 'null'] }
|
|
locale: { type: string, const: pt-MZ }
|
|
source_version: { type: [string, 'null'] }
|
|
status:
|
|
{
|
|
type: string,
|
|
enum: [published, not_published],
|
|
}
|
|
Pagination:
|
|
type: object
|
|
required: [current_page, per_page, total]
|
|
properties:
|
|
current_page: { type: integer, minimum: 1 }
|
|
per_page: { type: integer, minimum: 1 }
|
|
total: { type: integer, minimum: 0 }
|
|
version: { type: string }
|
|
QuestionnaireResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
required:
|
|
[id, code, version_no, locale, schema_snapshot, status]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
code: { type: string }
|
|
version_no: { type: integer, minimum: 1 }
|
|
locale: { type: string, const: pt-MZ }
|
|
schema_snapshot:
|
|
{ type: object, additionalProperties: true }
|
|
status: { type: string, const: published }
|
|
valid_from: { type: [string, 'null'], format: date }
|
|
valid_to: { type: [string, 'null'], format: date }
|
|
SimulationInput:
|
|
type: object
|
|
required: [base, rate]
|
|
properties:
|
|
base:
|
|
{
|
|
type: number,
|
|
minimum: 0,
|
|
description: Valor de entrada sem moeda inferida.,
|
|
}
|
|
rate:
|
|
{
|
|
type: number,
|
|
minimum: 0,
|
|
maximum: 100,
|
|
description: Parâmetro fornecido pelo utilizador; não representa taxa oficial.,
|
|
}
|
|
reduction:
|
|
{ type: number, minimum: 0, maximum: 100, default: 0 }
|
|
organization_id: { type: [string, 'null'], format: uuid }
|
|
additionalProperties: false
|
|
UpdateScenarioInput:
|
|
type: object
|
|
required: [label, base, rate]
|
|
properties:
|
|
label: { type: string, minLength: 1, maxLength: 100 }
|
|
base: { type: number, minimum: 0 }
|
|
rate: { type: number, minimum: 0, maximum: 100 }
|
|
reduction:
|
|
{ type: number, minimum: 0, maximum: 100, default: 0 }
|
|
additionalProperties: false
|
|
SimulationAccepted:
|
|
type: object
|
|
required: [data, replayed]
|
|
properties:
|
|
data: { $ref: '#/components/schemas/Simulation' }
|
|
replayed: { type: boolean }
|
|
access_token:
|
|
{
|
|
type: string,
|
|
minLength: 32,
|
|
maxLength: 256,
|
|
description: Devolvido apenas para execução anónima.,
|
|
}
|
|
SimulationResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data: { $ref: '#/components/schemas/Simulation' }
|
|
Simulation:
|
|
type: object
|
|
required: [id, status, version_no, created_at, updated_at]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
questionnaire_version_id:
|
|
{ type: [string, 'null'], format: uuid }
|
|
organization_id: { type: [string, 'null'], format: uuid }
|
|
version_no: { type: integer, minimum: 1 }
|
|
status:
|
|
{
|
|
type: string,
|
|
enum: [queued, running, completed, failed, cancelled],
|
|
}
|
|
input_snapshot: { type: object, additionalProperties: true }
|
|
result_snapshot:
|
|
{ type: [object, 'null'], additionalProperties: true }
|
|
calculation_snapshot:
|
|
{ type: [object, 'null'], additionalProperties: true }
|
|
scenarios:
|
|
{
|
|
type: array,
|
|
items: { $ref: '#/components/schemas/Scenario' },
|
|
}
|
|
created_at: { type: string, format: date-time }
|
|
updated_at: { type: string, format: date-time }
|
|
Scenario:
|
|
type: object
|
|
required: [id, code, label, version_no, parameters]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
code: { type: string }
|
|
label: { type: string }
|
|
version_no: { type: integer, minimum: 1 }
|
|
parameters: { type: object, additionalProperties: true }
|
|
JobCollection:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
{
|
|
type: array,
|
|
items: { $ref: '#/components/schemas/SimulationJob' },
|
|
}
|
|
SimulationJob:
|
|
type: object
|
|
required:
|
|
[id, simulation_id, job_type, status, attempts, available_at]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
simulation_id: { type: string, format: uuid }
|
|
job_type: { type: string, enum: [execute, report] }
|
|
status:
|
|
{
|
|
type: string,
|
|
enum: [pending, running, succeeded, failed],
|
|
}
|
|
attempts: { type: integer, minimum: 0, maximum: 3 }
|
|
available_at: { type: string, format: date-time }
|
|
started_at: { type: [string, 'null'], format: date-time }
|
|
finished_at: { type: [string, 'null'], format: date-time }
|
|
error_code: { type: [string, 'null'] }
|
|
ReportResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data: { $ref: '#/components/schemas/SimulationReport' }
|
|
SimulationReport:
|
|
type: object
|
|
required: [id, simulation_id, version_no, status]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
simulation_id: { type: string, format: uuid }
|
|
version_no: { type: integer, minimum: 1 }
|
|
status: { type: string, enum: [queued, ready, failed] }
|
|
report_snapshot:
|
|
{ type: [object, 'null'], additionalProperties: true }
|
|
report_sha256:
|
|
{ type: [string, 'null'], pattern: '^[0-9a-f]{64}$' }
|
|
LegislationPage:
|
|
type: object
|
|
required: [data, meta]
|
|
properties:
|
|
data:
|
|
{
|
|
type: array,
|
|
items: { $ref: '#/components/schemas/LegalSource' },
|
|
}
|
|
meta: { $ref: '#/components/schemas/Pagination' }
|
|
AdminLegalSourcePage:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
{
|
|
type: array,
|
|
items: { $ref: '#/components/schemas/LegalSource' },
|
|
}
|
|
current_page: { type: integer }
|
|
per_page: { type: integer }
|
|
total: { type: integer }
|
|
last_page: { type: integer }
|
|
first_page_url:
|
|
{ type: [string, 'null'], format: uri-reference }
|
|
last_page_url: { type: [string, 'null'], format: uri-reference }
|
|
next_page_url: { type: [string, 'null'], format: uri-reference }
|
|
prev_page_url: { type: [string, 'null'], format: uri-reference }
|
|
LegalSourceInput:
|
|
type: object
|
|
required:
|
|
[title, url, diploma, article, competent_entity, valid_from]
|
|
properties:
|
|
title: { type: string, minLength: 1, maxLength: 255 }
|
|
url:
|
|
{
|
|
type: string,
|
|
format: uri,
|
|
pattern: '^https://',
|
|
maxLength: 2000,
|
|
}
|
|
diploma: { type: string, maxLength: 255 }
|
|
article: { type: string, maxLength: 255 }
|
|
competent_entity: { type: string, maxLength: 255 }
|
|
valid_from: { type: string, format: date }
|
|
valid_until: { type: [string, 'null'], format: date }
|
|
additionalProperties: false
|
|
LegalSourceTransitionInput:
|
|
type: object
|
|
required: [version_no]
|
|
properties:
|
|
version_no: { type: integer, minimum: 1 }
|
|
additionalProperties: false
|
|
LegalSource:
|
|
type: object
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
title: { type: string }
|
|
url: { type: string, format: uri }
|
|
diploma: { type: string }
|
|
article: { type: string }
|
|
competent_entity: { type: string }
|
|
validation_status:
|
|
{ type: string, enum: [pending, validated, revoked] }
|
|
version_no: { type: integer }
|
|
valid_until: { type: [string, 'null'], format: date }
|
|
validator_id: { type: [integer, 'null'] }
|
|
validated_at: { type: [string, 'null'], format: date-time }
|
|
valid_from: { type: [string, 'null'], format: date }
|
|
InterestRequestInput:
|
|
type: object
|
|
required:
|
|
[
|
|
fullName,
|
|
email,
|
|
investorType,
|
|
country,
|
|
sectorInterest,
|
|
message,
|
|
privacyConsent,
|
|
]
|
|
properties:
|
|
fullName:
|
|
{
|
|
type: string,
|
|
minLength: 3,
|
|
maxLength: 150,
|
|
writeOnly: true,
|
|
}
|
|
email:
|
|
{
|
|
type: string,
|
|
format: email,
|
|
maxLength: 150,
|
|
writeOnly: true,
|
|
}
|
|
phone:
|
|
{ type: [string, 'null'], maxLength: 30, writeOnly: true }
|
|
investorType:
|
|
{
|
|
type: string,
|
|
enum:
|
|
[
|
|
individual,
|
|
empresa,
|
|
fundo,
|
|
entidade_publica,
|
|
outro,
|
|
],
|
|
}
|
|
country: { type: string, maxLength: 100 }
|
|
sectorInterest: { type: string, maxLength: 150 }
|
|
opportunityReference: { type: [string, 'null'], maxLength: 80 }
|
|
existingBusinessId: { type: [string, 'null'], format: uuid }
|
|
modality: { type: [string, 'null'], maxLength: 50 }
|
|
investmentRange: { type: [string, 'null'], maxLength: 80 }
|
|
message:
|
|
{
|
|
type: string,
|
|
minLength: 20,
|
|
maxLength: 2000,
|
|
writeOnly: true,
|
|
}
|
|
privacyConsent: { type: boolean, const: true }
|
|
shareWithProponent: { type: boolean, default: false }
|
|
additionalProperties: false
|
|
not:
|
|
allOf:
|
|
- required: [opportunityReference]
|
|
properties:
|
|
opportunityReference: { type: string, minLength: 1 }
|
|
- required: [existingBusinessId]
|
|
properties:
|
|
existingBusinessId: { type: string, format: uuid }
|
|
allOf:
|
|
- if:
|
|
required: [existingBusinessId]
|
|
properties:
|
|
existingBusinessId: { type: string }
|
|
then:
|
|
required: [modality]
|
|
properties:
|
|
modality:
|
|
{ type: string, minLength: 1, maxLength: 50 }
|
|
InterestRequestResponse:
|
|
type: object
|
|
required: [success, message, data]
|
|
properties:
|
|
success: { type: boolean, const: true }
|
|
message: { type: string }
|
|
data:
|
|
type: object
|
|
required: [reference, status]
|
|
properties:
|
|
reference: { type: string }
|
|
status: { type: string, const: received }
|
|
OpportunityResponse:
|
|
type: object
|
|
required: [success, data]
|
|
properties:
|
|
success: { type: boolean, const: true }
|
|
data:
|
|
type: object
|
|
required: [id, slug, title]
|
|
properties:
|
|
id: { type: [string, integer] }
|
|
slug: { type: string }
|
|
title: { type: string }
|
|
summary: { type: [string, 'null'] }
|
|
status: { type: string }
|