{ "openapi": "3.0.3", "info": { "title": "InvestMoz — descoberta e manifestações", "version": "1.1.0-QA-classification", "description": "Contrato local 27/09/2026. Sessão web Laravel, email verificado e CSRF; não usa bearer independente. Accept: application/json. Respostas privadas no-store. Estados de atendimento: received,in_review,contacted,closed. API pública usa throttle api da aplicação; limites específicos indicados por operação. O middleware Laravel 13 aceita origem same-origin comprovada ou token CSRF válido; clientes devem enviar o token. Pedidos cross-site sem token são recusados. Pesquisa, referências, sugestão, mapa, comparação, exportação e favoritos partilham 60 pedidos/minuto por IP. Delta 15/10/2026: classificação multidimensional preparada apenas em QA; as novas operações e parâmetros abaixo identificados por x-qa-only NÃO estão ativos por esta documentação." }, "servers": [ { "url": "/api/v1/investment" } ], "security": [], "paths": { "/search": { "get": { "summary": "Pesquisar oportunidades publicadas com filtros em intersecção.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 120 } }, { "name": "sector", "in": "query", "schema": { "type": "string" } }, { "name": "province", "in": "query", "schema": { "type": "string" } }, { "name": "district", "in": "query", "schema": { "type": "string" } }, { "name": "cluster_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "corridor_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "project_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "geo_location_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "education", "in": "query", "schema": { "type": "boolean" } }, { "name": "maturity_level", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 6 } }, { "name": "facets", "in": "query", "schema": { "type": "array", "items": { "type": "integer" }, "maxItems": 20 } }, { "name": "min_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "max_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "currency", "in": "query", "schema": { "type": "string", "enum": [ "MZN", "USD", "EUR", "ZAR" ] } }, { "name": "before", "in": "query", "schema": { "type": "string", "format": "date" } }, { "name": "sort", "in": "query", "schema": { "type": "string", "enum": [ "recent", "title", "amount_asc", "amount_desc" ] } }, { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 12 } }, { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1 } }, { "name": "zee_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "zfi_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "park_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "dimension", "in": "query", "schema": { "type": "string", "enum": [ "cluster", "corridor", "zee", "zfi" ] }, "description": "Require a visible association in the selected dimension, preserving other filters." }, { "name": "view", "in": "query", "schema": { "type": "string", "enum": [ "grid", "list", "map", "combined" ] }, "description": "Presentation state retained in URL; does not alter permission checks." }, { "in": "query", "name": "association_type", "required": false, "schema": { "type": "string", "enum": [ "corridor", "location", "cluster", "project", "chain", "park", "zone", "sector", "activity" ] }, "x-qa-only": true }, { "in": "query", "name": "association_target", "required": false, "schema": { "type": "string", "maxLength": 80 }, "x-qa-only": true }, { "in": "query", "name": "association_state", "required": false, "schema": { "type": "string", "enum": [ "draft", "preliminary", "in_validation", "confirmed", "rejected", "archived", "revoked" ] }, "x-qa-only": true }, { "in": "query", "name": "association_purpose", "required": false, "schema": { "type": "string" }, "x-qa-only": true }, { "in": "query", "name": "authority_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "chain_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "subsector_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "category", "required": false, "schema": { "type": "string", "enum": [ "investment_project", "real_estate", "land_rights", "business_sale", "business_partnership", "franchise", "concession", "financing", "supply", "other" ] }, "x-qa-only": true }, { "in": "query", "name": "publication_state", "required": false, "schema": { "type": "string", "enum": [ "published" ] }, "x-qa-only": true } ], "description": "Min/max exigem currency; max >= min. Sem câmbio. Facetas: facets[]=1&facets[]=2. Ordenação monetária agrupada por moeda. Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática." } }, "/references": { "get": { "summary": "Opções activas e territórios públicos.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/References" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/opportunities/{slug}": { "get": { "summary": "Ficha publicada e contexto.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Detail" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/suggest": { "get": { "summary": "Sugestões a partir de dois caracteres; até cinco de cada tipo.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "opportunities": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "title": { "type": "string" }, "slug": { "type": "string" } } } }, "territorial": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "title": { "type": "string" } } } } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 120 } }, { "name": "sector", "in": "query", "schema": { "type": "string" } }, { "name": "province", "in": "query", "schema": { "type": "string" } }, { "name": "district", "in": "query", "schema": { "type": "string" } }, { "name": "cluster_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "corridor_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "project_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "geo_location_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "education", "in": "query", "schema": { "type": "boolean" } }, { "name": "maturity_level", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 6 } }, { "name": "facets", "in": "query", "schema": { "type": "array", "items": { "type": "integer" }, "maxItems": 20 } }, { "name": "min_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "max_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "currency", "in": "query", "schema": { "type": "string", "enum": [ "MZN", "USD", "EUR", "ZAR" ] } }, { "name": "before", "in": "query", "schema": { "type": "string", "format": "date" } }, { "name": "sort", "in": "query", "schema": { "type": "string", "enum": [ "recent", "title", "amount_asc", "amount_desc" ] } }, { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 12 } }, { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1 } }, { "name": "zee_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "zfi_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "park_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "dimension", "in": "query", "schema": { "type": "string", "enum": [ "cluster", "corridor", "zee", "zfi" ] }, "description": "Require a visible association in the selected dimension, preserving other filters." }, { "name": "view", "in": "query", "schema": { "type": "string", "enum": [ "grid", "list", "map", "combined" ] }, "description": "Presentation state retained in URL; does not alter permission checks." }, { "in": "query", "name": "association_type", "required": false, "schema": { "type": "string", "enum": [ "corridor", "location", "cluster", "project", "chain", "park", "zone", "sector", "activity" ] }, "x-qa-only": true }, { "in": "query", "name": "association_target", "required": false, "schema": { "type": "string", "maxLength": 80 }, "x-qa-only": true }, { "in": "query", "name": "association_state", "required": false, "schema": { "type": "string", "enum": [ "draft", "preliminary", "in_validation", "confirmed", "rejected", "archived", "revoked" ] }, "x-qa-only": true }, { "in": "query", "name": "association_purpose", "required": false, "schema": { "type": "string" }, "x-qa-only": true }, { "in": "query", "name": "authority_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "chain_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "subsector_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "category", "required": false, "schema": { "type": "string", "enum": [ "investment_project", "real_estate", "land_rights", "business_sale", "business_partnership", "franchise", "concession", "financing", "supply", "other" ] }, "x-qa-only": true }, { "in": "query", "name": "publication_state", "required": false, "schema": { "type": "string", "enum": [ "published" ] }, "x-qa-only": true } ], "description": " Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática." } }, "/map": { "get": { "summary": "Até mil pontos públicos WGS84, com filtros.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Map" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 120 } }, { "name": "sector", "in": "query", "schema": { "type": "string" } }, { "name": "province", "in": "query", "schema": { "type": "string" } }, { "name": "district", "in": "query", "schema": { "type": "string" } }, { "name": "cluster_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "corridor_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "project_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "geo_location_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "education", "in": "query", "schema": { "type": "boolean" } }, { "name": "maturity_level", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 6 } }, { "name": "facets", "in": "query", "schema": { "type": "array", "items": { "type": "integer" }, "maxItems": 20 } }, { "name": "min_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "max_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "currency", "in": "query", "schema": { "type": "string", "enum": [ "MZN", "USD", "EUR", "ZAR" ] } }, { "name": "before", "in": "query", "schema": { "type": "string", "format": "date" } }, { "name": "sort", "in": "query", "schema": { "type": "string", "enum": [ "recent", "title", "amount_asc", "amount_desc" ] } }, { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 12 } }, { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1 } }, { "name": "zee_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "zfi_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "park_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "dimension", "in": "query", "schema": { "type": "string", "enum": [ "cluster", "corridor", "zee", "zfi" ] }, "description": "Require a visible association in the selected dimension, preserving other filters." }, { "name": "view", "in": "query", "schema": { "type": "string", "enum": [ "grid", "list", "map", "combined" ] }, "description": "Presentation state retained in URL; does not alter permission checks." }, { "in": "query", "name": "association_type", "required": false, "schema": { "type": "string", "enum": [ "corridor", "location", "cluster", "project", "chain", "park", "zone", "sector", "activity" ] }, "x-qa-only": true }, { "in": "query", "name": "association_target", "required": false, "schema": { "type": "string", "maxLength": 80 }, "x-qa-only": true }, { "in": "query", "name": "association_state", "required": false, "schema": { "type": "string", "enum": [ "draft", "preliminary", "in_validation", "confirmed", "rejected", "archived", "revoked" ] }, "x-qa-only": true }, { "in": "query", "name": "association_purpose", "required": false, "schema": { "type": "string" }, "x-qa-only": true }, { "in": "query", "name": "authority_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "chain_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "subsector_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "category", "required": false, "schema": { "type": "string", "enum": [ "investment_project", "real_estate", "land_rights", "business_sale", "business_partnership", "franchise", "concession", "financing", "supply", "other" ] }, "x-qa-only": true }, { "in": "query", "name": "publication_state", "required": false, "schema": { "type": "string", "enum": [ "published" ] }, "x-qa-only": true } ], "description": " Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática." } }, "/compare": { "get": { "summary": "Comparar até quatro oportunidades publicadas.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "records": { "type": "array", "items": { "$ref": "#/components/schemas/Detail" } } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "ids", "in": "query", "required": true, "description": "Enviar ids[]=1&ids[]=2", "schema": { "type": "array", "items": { "type": "integer" }, "minItems": 1, "maxItems": 4, "uniqueItems": true } } ] } }, "/export": { "get": { "summary": "CSV UTF-8 com BOM; até mil resultados; fórmulas neutralizadas.", "responses": { "200": { "description": "CSV separado por ponto e vírgula", "content": { "text/csv": { "schema": { "type": "string" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 120 } }, { "name": "sector", "in": "query", "schema": { "type": "string" } }, { "name": "province", "in": "query", "schema": { "type": "string" } }, { "name": "district", "in": "query", "schema": { "type": "string" } }, { "name": "cluster_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "corridor_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "project_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "geo_location_id", "in": "query", "schema": { "type": "string", "format": "uuid" } }, { "name": "education", "in": "query", "schema": { "type": "boolean" } }, { "name": "maturity_level", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 6 } }, { "name": "facets", "in": "query", "schema": { "type": "array", "items": { "type": "integer" }, "maxItems": 20 } }, { "name": "min_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "max_amount", "in": "query", "schema": { "type": "number", "minimum": 0 } }, { "name": "currency", "in": "query", "schema": { "type": "string", "enum": [ "MZN", "USD", "EUR", "ZAR" ] } }, { "name": "before", "in": "query", "schema": { "type": "string", "format": "date" } }, { "name": "sort", "in": "query", "schema": { "type": "string", "enum": [ "recent", "title", "amount_asc", "amount_desc" ] } }, { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 12 } }, { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1 } }, { "name": "zee_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "zfi_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "park_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Current validated public association. AND with other filters." }, { "name": "dimension", "in": "query", "schema": { "type": "string", "enum": [ "cluster", "corridor", "zee", "zfi" ] }, "description": "Require a visible association in the selected dimension, preserving other filters." }, { "name": "view", "in": "query", "schema": { "type": "string", "enum": [ "grid", "list", "map", "combined" ] }, "description": "Presentation state retained in URL; does not alter permission checks." }, { "in": "query", "name": "association_type", "required": false, "schema": { "type": "string", "enum": [ "corridor", "location", "cluster", "project", "chain", "park", "zone", "sector", "activity" ] }, "x-qa-only": true }, { "in": "query", "name": "association_target", "required": false, "schema": { "type": "string", "maxLength": 80 }, "x-qa-only": true }, { "in": "query", "name": "association_state", "required": false, "schema": { "type": "string", "enum": [ "draft", "preliminary", "in_validation", "confirmed", "rejected", "archived", "revoked" ] }, "x-qa-only": true }, { "in": "query", "name": "association_purpose", "required": false, "schema": { "type": "string" }, "x-qa-only": true }, { "in": "query", "name": "authority_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "chain_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "subsector_id", "required": false, "schema": { "type": "string", "format": "uuid" }, "x-qa-only": true }, { "in": "query", "name": "category", "required": false, "schema": { "type": "string", "enum": [ "investment_project", "real_estate", "land_rights", "business_sale", "business_partnership", "franchise", "concession", "financing", "supply", "other" ] }, "x-qa-only": true }, { "in": "query", "name": "publication_state", "required": false, "schema": { "type": "string", "enum": [ "published" ] }, "x-qa-only": true } ], "description": " Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática." } }, "/favourites/{id}": { "post": { "summary": "Guardar/retirar favorito próprio.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "saved": { "type": "boolean" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "saved": { "type": "boolean" } }, "required": [ "saved" ] } } } } } }, "/submissions": { "get": { "summary": "Manifestações próprias (20/página) e favoritos publicados.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "submissions": { "type": "object", "properties": {}, "description": "Paginator Laravel: data, total, current_page, next_page_url, prev_page_url; linhas com id,status,version,created_at,reference,request_status." }, "favourites": { "type": "array", "items": { "$ref": "#/components/schemas/Opportunity" } } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [] } ], "parameters": [ { "name": "page", "in": "query", "schema": { "type": "integer" } } ] }, "post": { "summary": "Criar rascunho próprio; no máximo um destino publicado; 10/min.", "responses": { "201": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "version": { "type": "integer" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "type": "object", "properties": { "opportunity_id": { "type": "integer", "nullable": true }, "dossier_id": { "type": "string", "format": "uuid", "nullable": true }, "company_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Declaração de empresa do próprio utilizador, usada para pré-preenchimento." }, "zone_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Published zone origin; may combine with a publicly associated opportunity, not with dossier_id or company_id." }, "intent": { "type": "string", "enum": [ "interest", "dossier", "meeting" ], "description": "Required with zone_id. Reuses the existing draft for this user, zone version, opportunity and intent." } } } } } } } }, "/submissions/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "get": { "summary": "Consultar pedido próprio ou, com manage-portal, pedido em atendimento.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "submission": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "version": { "type": "integer" }, "status": { "type": "string" }, "payload": { "$ref": "#/components/schemas/Payload" } } }, "needs": { "type": "array", "items": { "$ref": "#/components/schemas/Need" } }, "references": { "$ref": "#/components/schemas/References" }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "file_name": { "type": "string" } } } }, "events": { "type": "array", "items": { "type": "object", "properties": { "action": { "type": "string" }, "version": { "type": "integer" }, "created_at": { "type": "string", "format": "date-time" } } } }, "receipt": { "type": "object", "properties": { "reference": { "type": "string" }, "status": { "type": "string" } }, "nullable": true }, "messages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "sender_role": { "type": "string", "enum": [ "investor", "support" ] }, "body": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" } } } }, "revisions": { "type": "array", "items": { "type": "object", "properties": { "version": { "type": "integer" }, "created_at": { "type": "string", "format": "date-time" } } } } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [] } ] }, "put": { "summary": "Guardar rascunho próprio com versão optimista; 30/min.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Version" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Draft" } } } } } }, "/submissions/{id}/submit": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "post": { "summary": "Submeter atomicamente; reenvio devolve protocolo e estado existentes; 10/min.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "reference": { "type": "string" }, "status": { "type": "string" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Draft" } } } }, "description": "Somente titular. Exige campos finais e consentimento. Um recibo e uma outbox de CRM; sem activação de conector externo." } }, "/submissions/{id}/attachments": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "post": { "summary": "Carregar anexo privado em rascunho; 10/min.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Version" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "version": { "type": "integer" }, "file": { "type": "string", "format": "binary", "description": "PDF/TXT até 10 MiB; máximo dez anexos." } }, "required": [ "version", "file" ] } } } } } }, "/submissions/{id}/attachments/{attachment}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "attachment", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "get": { "summary": "Download privado após validar titular/gestor, caminho, estado e checksum.", "responses": { "200": { "description": "Attachment; no-store, nosniff", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [] } ] } }, "/admin/opportunities/{id}/context": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "put": { "summary": "Gestor altera contexto; devolve oportunidade a rascunho.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Version" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContextInput" } } } }, "description": "manage-portal obrigatório. version=0 antes da criação do perfil. Opções activas, entidades não eliminadas. Não publica." } }, "/admin/references": { "post": { "summary": "Gestor cria/actualiza opção; grupo e código estáveis.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Option" } } } }, "description": "manage-portal obrigatório. Grupo existente; Outro mantém actividade e requires_description. Sem eliminação histórica." } }, "/admin/references/{id}": { "post": { "summary": "Gestor cria/actualiza opção; grupo e código estáveis.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Option" } } } }, "description": "manage-portal obrigatório. Grupo existente; Outro mantém actividade e requires_description. Sem eliminação histórica." }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ] }, "/profile": { "get": { "summary": "Perfil privado e empresas declaradas do titular.", "security": [ { "session": [] } ], "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "account": { "$ref": "#/components/schemas/InvestorAccount" }, "companies": { "type": "array", "items": { "$ref": "#/components/schemas/CompanyDeclaration" } } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "summary": "Guardar perfil privado com versão; 20/min.", "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InvestorAccount" } } } }, "description": "version=0 inicialmente. Campos desconhecidos recusados; não altera nome/email nem concede representação de empresa.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Version" } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/companies": { "post": { "summary": "Guardar declaração privada de empresa; 20/min.", "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompanyDeclaration" } } } }, "description": "Titular apenas. Máximo vinte declarações; versão zero para criar. Não cria memberships nem altera organizações canónicas.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "version": { "type": "integer" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/companies/{id}": { "post": { "summary": "Guardar declaração privada de empresa; 20/min.", "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompanyDeclaration" } } } }, "description": "Titular apenas. Máximo vinte declarações; versão zero para criar. Não cria memberships nem altera organizações canónicas.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "version": { "type": "integer" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ] }, "/notifications": { "get": { "summary": "Notificações próprias, vinte por página, e contagem não lida.", "security": [ { "session": [] } ], "parameters": [ { "name": "page", "in": "query", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "unread": { "type": "integer" }, "notifications": { "type": "object", "properties": {}, "description": "Paginator Laravel com data: id,submission_id,kind,payload,read_at,created_at. Tipos received,status,message. Sem email externo." } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/notifications/{id}/read": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "post": { "summary": "Marcar notificação própria como lida; idempotente.", "security": [ { "session": [], "csrf": [] } ], "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "read": { "type": "boolean" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/submissions/{id}/messages": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "post": { "summary": "Mensagem privada em pedido submetido; 10/min.", "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "client_key": { "type": "string", "format": "uuid" }, "body": { "type": "string", "minLength": 3, "maxLength": 5000 } }, "required": [ "client_key", "body" ] } } } }, "description": "Titular ou gestor. Mesma chave e texto devolvem a mensagem existente. Chave reutilizada com texto diferente:409. Texto encriptado; auditoria sem corpo. Cria notificações internas para a outra parte.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/submissions/{id}/revisions/{version}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "version", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1 } } ], "get": { "summary": "Consultar versão histórica encriptada do pedido.", "security": [ { "session": [] } ], "description": "Titular ou gestor actual. Só versões gravadas após esta extensão. Não altera nem restaura automaticamente o pedido; no-store.", "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "version": { "type": "integer" }, "snapshot": { "type": "object", "properties": { "payload": { "$ref": "#/components/schemas/Payload" }, "status": { "type": "string" }, "needs": { "type": "array", "items": { "$ref": "#/components/schemas/Need" } }, "attachment_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } } } } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/admin/interests/{interest}/status": { "parameters": [ { "name": "interest", "in": "path", "required": true, "schema": { "type": "integer" } } ], "patch": { "summary": "Gestor actualiza estado de atendimento e notifica o titular quando muda.", "security": [ { "session": [], "csrf": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "status" ], "properties": { "status": { "type": "string", "enum": [ "received", "in_review", "contacted", "closed" ] } } } } } }, "responses": { "200": { "description": "Sucesso", "content": { "application/json": { "schema": { "type": "object", "properties": { "reference": { "type": "string" }, "status": { "type": "string" } } } } } }, "401": { "description": "Sem sessão", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Email não verificado / sem manage-portal", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Registo ausente ou invisível", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Versão desactualizada / pedido submetido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "419": { "description": "Sessão / CSRF expirado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Validação", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Limite de pedidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "description": "Exige manage-portal. Alteração transaccional com auditoria. Repetir o mesmo estado não cria outra notificação." } }, "/minhas-oportunidades/{id}/classification": { "servers": [ { "url": "/" } ], "get": { "x-qa-only": true, "summary": "Recuperar associações, metadados e versões anteriores autorizadas", "description": "Sessão web Laravel verificada; autorização view do mesmo cadastro. Resposta Cache-Control private,no-store. Sem novo papel. Candidatos a duplicação limitados ao âmbito já autorizado e a título exato; nenhuma fusão.", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1 } } ], "responses": { "200": { "description": "Sucesso" }, "401": { "description": "Sessão necessária" }, "403": { "description": "Âmbito, responsabilidade, MFA ou independência insuficientes" }, "404": { "description": "Registo inexistente" }, "409": { "description": "Versão ou associação mudou" }, "422": { "description": "Campos ou fundamento insuficientes" } } } }, "/minhas-oportunidades/{id}/classification/review": { "servers": [ { "url": "/" } ], "post": { "x-qa-only": true, "summary": "Decidir confirmação de uma associação, sem transição editorial", "description": "Validador no âmbito da oportunidade; technical_reviewer ou legal_reviewer para dimensão regulatória, MFA efetiva e independência já aprovados. CSRF. Um 200 não publica a relação nem concede ato externo. Hash da relação e versão documental vinculam a decisão. Versão anterior publicada pode ser revogada após correção privada.", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "etag", "hash", "state", "reason" ], "properties": { "etag": { "type": "string", "minLength": 64, "maxLength": 64 }, "hash": { "type": "string", "minLength": 64, "maxLength": 64 }, "state": { "type": "string", "enum": [ "in_validation", "confirmed", "rejected", "archived", "revoked" ] }, "reason": { "type": "string", "minLength": 20, "maxLength": 1000 } } } } } }, "responses": { "200": { "description": "Sucesso" }, "401": { "description": "Sessão necessária" }, "403": { "description": "Âmbito, responsabilidade, MFA ou independência insuficientes" }, "404": { "description": "Registo inexistente" }, "409": { "description": "Versão ou associação mudou" }, "422": { "description": "Campos ou fundamento insuficientes" } } } } }, "components": { "securitySchemes": { "session": { "type": "apiKey", "in": "cookie", "name": "laravel_session", "description": "Nome configurável SESSION_COOKIE; autenticar pelo fluxo web." }, "csrf": { "type": "apiKey", "in": "header", "name": "X-XSRF-TOKEN", "description": "Valor descodificado do cookie XSRF-TOKEN." } }, "schemas": { "Error": { "type": "object", "properties": { "message": { "type": "string" }, "errors": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } } } } }, "Version": { "type": "object", "properties": { "version": { "type": "integer" } } }, "Entity": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" } } }, "Option": { "type": "object", "required": [ "group", "code", "label", "active", "requires_description", "sort_order" ], "properties": { "id": { "type": "integer" }, "group": { "type": "string" }, "code": { "type": "string", "maxLength": 80, "pattern": "^[a-zA-Z0-9_-]+$" }, "label": { "type": "string", "maxLength": 200 }, "active": { "type": "boolean" }, "requires_description": { "type": "boolean" }, "sort_order": { "type": "integer", "minimum": 0, "maximum": 10000 } } }, "Payload": { "type": "object", "additionalProperties": false, "properties": { "full_name": { "type": "string", "nullable": true, "maxLength": 150 }, "email": { "type": "string", "nullable": true, "maxLength": 150 }, "phone": { "type": "string", "nullable": true }, "country": { "type": "string", "nullable": true }, "organisation": { "type": "string", "nullable": true }, "representative_role": { "type": "string", "nullable": true }, "experience": { "type": "string", "nullable": true }, "investment_capacity": { "type": "string", "nullable": true }, "sector": { "type": "string", "nullable": true }, "objective": { "type": "string", "maxLength": 5000, "nullable": true }, "currency": { "type": "string", "nullable": true }, "horizon": { "type": "string", "nullable": true }, "location": { "type": "string", "nullable": true }, "other_details": { "type": "string", "nullable": true }, "contact_consent": { "type": "boolean" }, "estimated_amount": { "type": "number", "minimum": 0, "nullable": true }, "profile_id": { "type": "integer", "nullable": true }, "participation_id": { "type": "integer", "nullable": true }, "partnership_id": { "type": "integer", "nullable": true }, "cluster_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 20, "uniqueItems": true }, "corridor_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 20, "uniqueItems": true }, "project_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 30, "uniqueItems": true } }, "description": "Para submeter: full_name, email, country, profile_id, sector, objective, participation_id e horizon obrigatórios; contact_consent=true. Moeda obrigatória com montante. Outro exige other_details. Opções activas do grupo correcto. Drafts permit incomplete name, email and objective. Submission requires a name of at least 3 characters, RFC email and objective of at least 20 characters." }, "Draft": { "type": "object", "required": [ "version", "payload" ], "properties": { "version": { "type": "integer", "minimum": 1 }, "payload": { "$ref": "#/components/schemas/Payload" }, "needs": { "type": "array", "maxItems": 40, "items": { "$ref": "#/components/schemas/Need" } } } }, "Need": { "type": "object", "additionalProperties": false, "required": [ "category_id", "option_id", "details" ], "properties": { "category_id": { "type": "integer" }, "option_id": { "type": "integer" }, "unit_id": { "type": "integer", "nullable": true }, "priority_id": { "type": "integer", "nullable": true }, "quantity": { "type": "number", "nullable": true, "minimum": 0, "maximum": 999999999999 }, "deadline": { "type": "string", "format": "date", "nullable": true }, "details": { "type": "object", "additionalProperties": false, "required": [ "description" ], "properties": { "description": { "type": "string", "nullable": false, "maxLength": 2000, "minLength": 3 }, "location": { "type": "string", "nullable": true, "maxLength": 2000 }, "observations": { "type": "string", "nullable": true, "maxLength": 2000 }, "qualification": { "type": "string", "nullable": true, "maxLength": 2000 }, "specialty": { "type": "string", "nullable": true, "maxLength": 2000 }, "experience": { "type": "string", "nullable": true, "maxLength": 2000 }, "certifications": { "type": "string", "nullable": true, "maxLength": 2000 }, "availability": { "type": "string", "nullable": true, "maxLength": 2000 }, "institution": { "type": "string", "nullable": true, "maxLength": 2000 }, "training_mode": { "type": "string", "nullable": true, "maxLength": 2000 }, "duration": { "type": "string", "nullable": true, "maxLength": 2000 }, "status": { "type": "string", "nullable": true, "maxLength": 2000 } } } } }, "Opportunity": { "type": "object", "properties": { "id": { "type": "integer" }, "title": { "type": "string" }, "slug": { "type": "string" }, "reference": { "type": "string" }, "summary": { "type": "string", "nullable": true }, "province": { "type": "string", "nullable": true }, "district": { "type": "string", "nullable": true }, "estimated_investment_amount": { "type": "string", "nullable": true, "example": "1500000.00" }, "estimated_investment_currency": { "type": "string" }, "maturity_label": { "type": "string", "nullable": true }, "status": { "type": "string" }, "sector": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "slug": { "type": "string" } } } } }, "Page": { "type": "object", "properties": { "current_page": { "type": "integer" }, "per_page": { "type": "integer" }, "total": { "type": "integer" }, "last_page": { "type": "integer" }, "next_page_url": { "type": "string", "nullable": true }, "prev_page_url": { "type": "string", "nullable": true }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/Opportunity" } } } }, "ContextInput": { "type": "object", "required": [ "version", "is_education", "source_reference" ], "properties": { "version": { "type": "integer", "minimum": 0 }, "is_education": { "type": "boolean" }, "source_reference": { "type": "string", "minLength": 10, "maxLength": 2000 }, "business_model": { "type": "string", "maxLength": 5000, "nullable": true }, "requirements": { "type": "string", "maxLength": 10000, "nullable": true }, "risks": { "type": "string", "maxLength": 5000, "nullable": true }, "target_date": { "type": "string", "format": "date", "nullable": true }, "facets": { "type": "array", "maxItems": 100, "items": { "type": "integer" }, "uniqueItems": true }, "clusters": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true }, "corridors": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true }, "projects": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true }, "locations": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true } } }, "Context": { "type": "object", "properties": { "profile": { "type": "object", "nullable": true, "properties": { "version": { "type": "integer", "minimum": 0 }, "is_education": { "type": "boolean" }, "source_reference": { "type": "string", "minLength": 10, "maxLength": 2000 }, "business_model": { "type": "string", "maxLength": 5000, "nullable": true }, "requirements": { "type": "string", "maxLength": 10000, "nullable": true }, "risks": { "type": "string", "maxLength": 5000, "nullable": true }, "target_date": { "type": "string", "format": "date", "nullable": true }, "facets": { "type": "array", "maxItems": 100, "items": { "type": "integer" }, "uniqueItems": true }, "clusters": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true }, "corridors": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true }, "projects": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true }, "locations": { "type": "array", "maxItems": 100, "items": { "type": "string", "format": "uuid" }, "uniqueItems": true } } }, "facets": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "group": { "type": "string" }, "label": { "type": "string" } } } }, "clusters": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } }, "corridors": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } }, "projects": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } }, "locations": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } } } }, "References": { "type": "object", "properties": { "options": { "type": "array", "items": { "$ref": "#/components/schemas/Option" } }, "sectors": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "slug": { "type": "string" } } } }, "clusters": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } }, "corridors": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } }, "projects": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } }, "locations": { "type": "array", "items": { "$ref": "#/components/schemas/Entity" } } } }, "Detail": { "type": "object", "properties": { "record": { "$ref": "#/components/schemas/Opportunity" }, "context": { "$ref": "#/components/schemas/Context" } } }, "Map": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "FeatureCollection" ] }, "limit": { "type": "integer", "enum": [ 1000 ] }, "features": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "Feature" ] }, "geometry": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "Point" ] }, "coordinates": { "type": "array", "minItems": 2, "maxItems": 2, "items": { "type": "number" } } } }, "properties": { "type": "object", "properties": { "id": { "type": "integer" }, "title": { "type": "string" }, "location": { "type": "string" }, "url": { "type": "string" } } } } } } } }, "InvestorAccount": { "type": "object", "properties": { "version": { "type": "integer" }, "payload": { "type": "object", "properties": { "phone": { "type": "string", "nullable": true }, "country": { "type": "string", "nullable": true }, "sector": { "type": "string", "nullable": true }, "experience": { "type": "string", "nullable": true }, "investment_capacity": { "type": "string", "nullable": true } } } }, "required": [ "version", "payload" ] }, "CompanyDeclaration": { "type": "object", "properties": { "version": { "type": "integer" }, "payload": { "type": "object", "properties": { "name": { "type": "string" }, "country": { "type": "string" }, "registration": { "type": "string" }, "sector": { "type": "string" }, "role": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "country", "role" ], "additionalProperties": false } }, "required": [ "version", "payload" ] } } } }