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 }