Capítulo 71 — Contratos REST e OpenAPI
Este capítulo documenta os contratos REST da Plataforma de Relacionamento Digital com o Cidadão, apresentando a estrutura OpenAPI de cada grupo funcional, as convenções de contrato adotadas na plataforma, e os padrões qu…
71.1 Objetivo do Capítulo
Este capítulo documenta os contratos REST da Plataforma de Relacionamento Digital com o Cidadão, apresentando a estrutura OpenAPI de cada grupo funcional, as convenções de contrato adotadas na plataforma, e os padrões que garantem consistência, evolução controlada e interoperabilidade entre canais, serviços de domínio e sistemas externos.
O Capítulo 14 estabeleceu as diretrizes arquiteturais de APIs: classificação, padrões REST, paginação, idempotência, versionamento e ciclo de vida. Este capítulo é a materialização dessas diretrizes em contratos concretos — paths, métodos, headers, parâmetros, schemas de request/response e códigos de erro documentados por domínio.
Os contratos aqui descritos cobrem os 24 serviços de domínio definidos no Capítulo 12, organizados em grupos funcionais. Para cada grupo, são apresentados: estrutura do contrato OpenAPI, endpoints representativos com schemas detalhados, headers obrigatórios e opcionais, modelos de resposta padrão e mapeamento de erros. O catálogo completo de endpoints está registrado no repositório de contratos versionado da plataforma, referenciado no Capítulo 58.
71.2 Estrutura dos Contratos OpenAPI
71.2.1 Versão e Metadados
Todos os contratos adotam OpenAPI Specification 3.1.0. A estrutura raiz de cada arquivo de contrato segue o padrão:
openapi: "3.1.0"
info:
title: "Request Service API"
description: |
API de gerenciamento do ciclo de vida das solicitações de serviços públicos.
Classificação: Pública / Canal / Interna.
Tenant-scoped: sim.
version: "1.3.0"
contact:
name: "Plataforma de Relacionamento Digital com o Cidadão"
license:
name: "Uso restrito — PRODEMGE"
servers:
- url: "https://api.{tenant}.plataforma.mg.gov.br/v1"
description: "Produção — por tenant"
variables:
tenant:
default: "default"
description: "Identificador do tenant (slug do órgão)"
- url: "https://api.staging.plataforma.mg.gov.br/v1"
description: "Homologação"
tags:
- name: "Solicitações"
description: "Ciclo de vida das solicitações de serviços públicos"
- name: "Protocolos"
description: "Consulta pública por número de protocolo"
security:
- BearerAuth: []
71.2.2 Componentes Reutilizáveis
Os contratos de todos os serviços referenciam um arquivo de componentes compartilhados (components.yaml) que define schemas, headers, responses e security schemes reutilizáveis. Isso elimina a duplicação de definições de erro, paginação, tenant context e schemas comuns entre os contratos dos 24 serviços.
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
Token JWT emitido pelo IAM da plataforma após autenticação.
Para cidadãos autenticados via GOV.BR, o token é emitido
pela plataforma após vinculação da identidade federada.
headers:
X-Tenant-Id:
description: "Identificador do tenant derivado da identidade autenticada. Não aceito como único fator de tenant."
schema:
type: string
format: uuid
required: true
X-Correlation-Id:
description: "Identificador de correlação para rastreamento distribuído."
schema:
type: string
required: false
Idempotency-Key:
description: "UUID gerado pelo cliente para operações de criação idempotentes."
schema:
type: string
format: uuid
required: false
schemas:
ProblemDetails:
type: object
required: [type, title, status, code, correlationId]
properties:
type:
type: string
format: uri
example: "https://platform.domain/problems/validation-error"
title:
type: string
example: "Validation failed"
status:
type: integer
example: 422
code:
type: string
example: "VALIDATION_ERROR"
correlationId:
type: string
example: "corr-a7f2-4b81-9c3d"
errors:
type: array
items:
type: object
properties:
field:
type: string
code:
type: string
message:
type: string
PagedResponse:
type: object
required: [items, page, size, totalElements, totalPages]
properties:
items:
type: array
items: {}
page:
type: integer
minimum: 0
size:
type: integer
minimum: 1
maximum: 100
totalElements:
type: integer
totalPages:
type: integer
CursorPagedResponse:
type: object
required: [items, hasMore]
properties:
items:
type: array
items: {}
nextCursor:
type: string
description: "Opaco. O consumidor não interpreta ou constrói este valor."
hasMore:
type: boolean
responses:
400BadRequest:
description: "Requisição malformada ou parâmetros inválidos."
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
401Unauthorized:
description: "Token ausente, expirado ou inválido."
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
403Forbidden:
description: "Autenticado mas sem permissão para esta operação."
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
404NotFound:
description: "Recurso não encontrado ou não acessível pelo tenant corrente."
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
422UnprocessableContent:
description: "Dados válidos sintaticamente mas inválidos semanticamente (regra de negócio)."
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
429TooManyRequests:
description: "Rate limit ou quota excedidos."
headers:
Retry-After:
schema:
type: integer
description: "Segundos até que novas requisições sejam aceitas."
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
500InternalServerError:
description: "Erro interno não esperado. Registrado com correlationId."
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
71.2.3 Convenção de Content-Type
Requisições com body usam Content-Type: application/json. Respostas de sucesso retornam Content-Type: application/json. Respostas de erro retornam Content-Type: application/problem+json, conforme RFC 9457. Upload de documentos binários usa multipart/form-data com campo file tipado. APIs de streaming de IA retornam text/event-stream via Server-Sent Events.
71.3 Grupo Funcional: Identidade e Acesso
71.3.1 Identity Service — Autenticação e Usuários
paths:
/auth/login:
post:
summary: "Autenticação local (usuários internos e cidadãos com cadastro local)"
tags: [Autenticação]
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [credential, password]
properties:
credential:
type: string
description: "CPF, e-mail ou login do usuário"
password:
type: string
format: password
writeOnly: true
tenantSlug:
type: string
description: "Slug do tenant para contexto de autenticação"
responses:
'200':
description: "Autenticação bem-sucedida"
content:
application/json:
schema:
type: object
properties:
accessToken:
type: string
description: "JWT de acesso"
tokenType:
type: string
enum: [Bearer]
expiresIn:
type: integer
description: "Segundos até expiração"
refreshToken:
type: string
description: "Token de renovação"
'401':
$ref: '#/components/responses/401Unauthorized'
'429':
$ref: '#/components/responses/429TooManyRequests'
/auth/refresh:
post:
summary: "Renovação de token de acesso via refresh token"
tags: [Autenticação]
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [refreshToken]
properties:
refreshToken:
type: string
responses:
'200':
description: "Tokens renovados"
'401':
$ref: '#/components/responses/401Unauthorized'
/auth/logout:
post:
summary: "Encerramento de sessão e revogação de tokens"
tags: [Autenticação]
responses:
'204':
description: "Sessão encerrada"
/auth/govbr/authorize:
get:
summary: "Início do fluxo OAuth 2.0 / OIDC com GOV.BR"
tags: [Autenticação Federada]
security: []
parameters:
- name: tenantSlug
in: query
required: true
schema:
type: string
- name: redirectUri
in: query
required: true
schema:
type: string
format: uri
responses:
'302':
description: "Redirecionamento para GOV.BR"
/auth/govbr/callback:
get:
summary: "Callback após autenticação no GOV.BR"
tags: [Autenticação Federada]
security: []
parameters:
- name: code
in: query
required: true
schema:
type: string
- name: state
in: query
required: true
schema:
type: string
responses:
'302':
description: "Redirecionamento para o canal com token da plataforma"
/me:
get:
summary: "Perfil do usuário autenticado e permissões da sessão"
tags: [Usuário]
responses:
'200':
description: "Dados do usuário autenticado"
content:
application/json:
schema:
type: object
properties:
userId:
type: string
format: uuid
name:
type: string
email:
type: string
tenantId:
type: string
format: uuid
roles:
type: array
items:
type: string
govbrLinked:
type: boolean
description: "Indica se a identidade GOV.BR está vinculada"
/users:
post:
summary: "Criação de usuário interno (atendente, gestor, administrador)"
tags: [Usuários]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserCreateRequest'
responses:
'201':
description: "Usuário criado"
headers:
Location:
schema:
type: string
format: uri
'400':
$ref: '#/components/responses/400BadRequest'
'409':
description: "Credencial já registrada"
/users/{userId}:
get:
summary: "Consulta de usuário por ID"
tags: [Usuários]
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Dados do usuário"
'404':
$ref: '#/components/responses/404NotFound'
patch:
summary: "Atualização parcial de usuário"
tags: [Usuários]
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
email:
type: string
format: email
active:
type: boolean
responses:
'200':
description: "Usuário atualizado"
'404':
$ref: '#/components/responses/404NotFound'
71.4 Grupo Funcional: Tenant e Configuração
71.4.1 Tenant Service
paths:
/tenants:
get:
summary: "Listagem de tenants (acesso administrativo global)"
tags: [Tenants]
parameters:
- name: status
in: query
schema:
type: string
enum: [ACTIVE, SUSPENDED, INACTIVE]
- name: page
in: query
schema:
type: integer
default: 0
- name: size
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: "Lista paginada de tenants"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/PagedResponse'
- type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/TenantSummary'
post:
summary: "Criação de novo tenant"
tags: [Tenants]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, slug, contactEmail]
properties:
name:
type: string
description: "Nome institucional do órgão"
slug:
type: string
pattern: "^[a-z0-9-]+$"
description: "Identificador URL-friendly único"
contactEmail:
type: string
format: email
plan:
type: string
enum: [STARTER, STANDARD, ENTERPRISE]
responses:
'201':
description: "Tenant criado"
headers:
Location:
schema:
type: string
format: uri
'409':
description: "Slug já registrado"
/tenants/{tenantId}:
get:
summary: "Detalhe do tenant"
tags: [Tenants]
parameters:
- name: tenantId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Dados completos do tenant"
patch:
summary: "Atualização de configurações do tenant"
tags: [Tenants]
parameters:
- name: tenantId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Tenant atualizado"
/tenants/{tenantId}/activate:
post:
summary: "Ativação de tenant"
tags: [Tenants]
parameters:
- name: tenantId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Tenant ativado"
'409':
description: "Tenant já ativo"
/tenants/{tenantId}/suspend:
post:
summary: "Suspensão temporária de tenant"
tags: [Tenants]
parameters:
- name: tenantId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
properties:
reason:
type: string
responses:
'200':
description: "Tenant suspenso"
/tenants/{tenantId}/modules:
get:
summary: "Módulos habilitados para o tenant"
tags: [Tenants]
parameters:
- name: tenantId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Lista de módulos e status de habilitação"
content:
application/json:
schema:
type: object
properties:
modules:
type: array
items:
type: object
properties:
moduleId:
type: string
enabled:
type: boolean
enabledAt:
type: string
format: date-time
put:
summary: "Atualização dos módulos habilitados"
tags: [Tenants]
parameters:
- name: tenantId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
modules:
type: array
items:
type: object
properties:
moduleId:
type: string
enabled:
type: boolean
responses:
'200':
description: "Módulos atualizados"
71.5 Grupo Funcional: Cidadão e Catálogo
71.5.1 Citizen Service
paths:
/citizens:
post:
summary: "Registro de cidadão com cadastro local"
tags: [Cidadão]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [cpf, name, email]
properties:
cpf:
type: string
pattern: "^\\d{11}$"
description: "CPF sem formatação"
name:
type: string
email:
type: string
format: email
birthDate:
type: string
format: date
phone:
type: string
responses:
'201':
description: "Cidadão registrado"
headers:
Location:
schema:
type: string
format: uri
'409':
description: "CPF já registrado neste tenant"
/citizens/{citizenId}:
get:
summary: "Dados do cidadão"
tags: [Cidadão]
parameters:
- name: citizenId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Dados básicos do cidadão"
content:
application/json:
schema:
$ref: '#/components/schemas/Citizen'
'404':
$ref: '#/components/responses/404NotFound'
patch:
summary: "Atualização parcial do cadastro do cidadão"
tags: [Cidadão]
parameters:
- name: citizenId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
email:
type: string
format: email
phone:
type: string
responses:
'200':
description: "Cadastro atualizado"
/citizens/{citizenId}/contacts:
get:
summary: "Contatos do cidadão (e-mails, telefones, canais de preferência)"
tags: [Cidadão]
parameters:
- name: citizenId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Lista de contatos"
post:
summary: "Adição de novo contato"
tags: [Cidadão]
parameters:
- name: citizenId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [type, value]
properties:
type:
type: string
enum: [EMAIL, PHONE, WHATSAPP]
value:
type: string
verified:
type: boolean
default: false
responses:
'201':
description: "Contato adicionado"
/citizens/{citizenId}/preferences:
get:
summary: "Preferências de comunicação e acessibilidade do cidadão"
tags: [Cidadão]
parameters:
- name: citizenId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Preferências do cidadão"
put:
summary: "Atualização completa das preferências"
tags: [Cidadão]
parameters:
- name: citizenId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
preferredChannel:
type: string
enum: [EMAIL, SMS, WHATSAPP, PUSH]
language:
type: string
default: "pt-BR"
accessibilityNeeds:
type: array
items:
type: string
enum: [VISUAL, AUDITORY, MOTOR, COGNITIVE]
responses:
'200':
description: "Preferências atualizadas"
/citizens/{citizenId}/360:
get:
summary: "Visão 360° do cidadão — composição por API, nunca por join de bancos"
tags: [Cidadão]
parameters:
- name: citizenId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Visão consolidada do cidadão"
content:
application/json:
schema:
type: object
properties:
citizen:
$ref: '#/components/schemas/Citizen'
recentRequests:
type: array
items:
$ref: '#/components/schemas/RequestSummary'
openInteractions:
type: array
items:
$ref: '#/components/schemas/InteractionSummary'
pendingAppointments:
type: array
items:
$ref: '#/components/schemas/AppointmentSummary'
71.5.2 Service Catalog Service
paths:
/services:
get:
summary: "Catálogo de serviços públicos do tenant"
tags: [Catálogo]
security: []
parameters:
- name: categoryId
in: query
schema:
type: string
- name: channel
in: query
schema:
type: string
enum: [WEB, MOBILE, PRESENTIAL]
- name: q
in: query
description: "Busca textual no nome e descrição"
schema:
type: string
- name: page
in: query
schema:
type: integer
default: 0
- name: size
in: query
schema:
type: integer
default: 20
maximum: 50
responses:
'200':
description: "Catálogo paginado de serviços"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/PagedResponse'
post:
summary: "Criação de serviço público"
tags: [Catálogo]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceCreateRequest'
responses:
'201':
description: "Serviço criado em rascunho"
headers:
Location:
schema:
type: string
format: uri
/services/{serviceId}:
get:
summary: "Detalhe de serviço público"
tags: [Catálogo]
security: []
parameters:
- name: serviceId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Dados completos do serviço"
patch:
summary: "Atualização de dados do serviço (sem publicar nova versão)"
tags: [Catálogo]
parameters:
- name: serviceId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Serviço atualizado"
/services/{serviceId}/publish:
post:
summary: "Publicação do serviço — torna-o disponível ao cidadão"
tags: [Catálogo]
parameters:
- name: serviceId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Serviço publicado"
'409':
description: "Serviço sem versão aprovada ou já publicado"
/services/{serviceId}/suspend:
post:
summary: "Suspensão temporária do serviço"
tags: [Catálogo]
parameters:
- name: serviceId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Serviço suspenso"
/service-categories:
get:
summary: "Categorias de serviços do tenant"
tags: [Catálogo]
security: []
responses:
'200':
description: "Árvore de categorias"
71.6 Grupo Funcional: Solicitações e Formulários
71.6.1 Request Service
O Request Service é o serviço central da plataforma. Seu contrato define o ciclo completo de uma solicitação de serviço público.
paths:
/requests:
get:
summary: "Listagem de solicitações do cidadão autenticado"
tags: [Solicitações]
parameters:
- name: status
in: query
schema:
type: string
enum: [DRAFT, SUBMITTED, IN_PROGRESS, PENDING_COMPLEMENT,
COMPLETED, REJECTED, CANCELLED]
- name: serviceId
in: query
schema:
type: string
format: uuid
- name: createdFrom
in: query
schema:
type: string
format: date-time
- name: createdTo
in: query
schema:
type: string
format: date-time
- name: page
in: query
schema:
type: integer
default: 0
- name: size
in: query
schema:
type: integer
default: 20
maximum: 50
responses:
'200':
description: "Solicitações paginadas"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/PagedResponse'
- type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/RequestSummary'
post:
summary: "Criação de rascunho de solicitação"
tags: [Solicitações]
parameters:
- name: Idempotency-Key
in: header
required: false
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [serviceId, serviceVersion, formId, formVersion]
properties:
serviceId:
type: string
format: uuid
serviceVersion:
type: string
description: "Versão do serviço no momento da criação"
formId:
type: string
format: uuid
formVersion:
type: string
description: "Versão do formulário — preservada para validação posterior"
channel:
type: string
enum: [WEB, MOBILE, PRESENTIAL, PHONE]
responses:
'201':
description: "Rascunho criado"
headers:
Location:
schema:
type: string
format: uri
content:
application/json:
schema:
$ref: '#/components/schemas/Request'
'400':
$ref: '#/components/responses/400BadRequest'
/requests/{requestId}:
get:
summary: "Detalhe da solicitação"
tags: [Solicitações]
parameters:
- name: requestId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Solicitação completa com histórico de status"
content:
application/json:
schema:
$ref: '#/components/schemas/Request'
'404':
$ref: '#/components/responses/404NotFound'
patch:
summary: "Atualização de dados do formulário (rascunho)"
tags: [Solicitações]
parameters:
- name: requestId
in: path
required: true
schema:
type: string
format: uuid
- name: If-Match
in: header
required: false
schema:
type: string
description: "ETag para controle de concorrência otimista"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
formData:
type: object
description: "Dados do formulário em estrutura livre definida pelo schema do formulário"
additionalProperties: true
responses:
'200':
description: "Dados atualizados"
headers:
ETag:
schema:
type: string
'412':
description: "ETag não corresponde — conflito de concorrência"
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
/requests/{requestId}/submit:
post:
summary: "Submissão da solicitação — transição de DRAFT para SUBMITTED"
tags: [Solicitações]
parameters:
- name: requestId
in: path
required: true
schema:
type: string
format: uuid
- name: Idempotency-Key
in: header
required: false
schema:
type: string
format: uuid
responses:
'200':
description: "Solicitação submetida — protocolo gerado"
content:
application/json:
schema:
type: object
properties:
requestId:
type: string
format: uuid
protocolNumber:
type: string
description: "Número de protocolo único"
status:
type: string
enum: [SUBMITTED]
submittedAt:
type: string
format: date-time
'409':
description: "Solicitação já submetida"
'422':
description: "Formulário incompleto ou documentos obrigatórios ausentes"
$ref: '#/components/responses/422UnprocessableContent'
/requests/{requestId}/cancel:
post:
summary: "Cancelamento de solicitação pelo cidadão"
tags: [Solicitações]
parameters:
- name: requestId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
properties:
reason:
type: string
responses:
'200':
description: "Solicitação cancelada"
'409':
description: "Status atual não permite cancelamento pelo cidadão"
/requests/{requestId}/complement:
post:
summary: "Envio de complementação solicitada pelo atendente"
tags: [Solicitações]
parameters:
- name: requestId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [complementData]
properties:
complementData:
type: object
additionalProperties: true
message:
type: string
responses:
'200':
description: "Complementação registrada"
'409':
description: "Solicitação não está aguardando complementação"
/protocols/{protocolNumber}:
get:
summary: "Consulta pública de solicitação por protocolo"
tags: [Protocolos]
security: []
parameters:
- name: protocolNumber
in: path
required: true
schema:
type: string
responses:
'200':
description: "Situação da solicitação acessível publicamente"
content:
application/json:
schema:
type: object
properties:
protocolNumber:
type: string
status:
type: string
serviceName:
type: string
submittedAt:
type: string
format: date-time
estimatedCompletionDate:
type: string
format: date
lastUpdate:
type: string
format: date-time
'404':
$ref: '#/components/responses/404NotFound'
71.6.2 Schemas Centrais do Request Service
components:
schemas:
Request:
type: object
properties:
requestId:
type: string
format: uuid
protocolNumber:
type: string
nullable: true
description: "Nulo até a submissão"
tenantId:
type: string
format: uuid
citizenId:
type: string
format: uuid
serviceId:
type: string
format: uuid
serviceVersion:
type: string
formId:
type: string
format: uuid
formVersion:
type: string
status:
type: string
enum: [DRAFT, SUBMITTED, IN_PROGRESS, PENDING_COMPLEMENT,
COMPLETED, REJECTED, CANCELLED]
channel:
type: string
enum: [WEB, MOBILE, PRESENTIAL, PHONE]
formData:
type: object
additionalProperties: true
documents:
type: array
items:
$ref: '#/components/schemas/RequestDocumentRef'
statusHistory:
type: array
items:
$ref: '#/components/schemas/StatusHistoryEntry'
createdAt:
type: string
format: date-time
submittedAt:
type: string
format: date-time
nullable: true
updatedAt:
type: string
format: date-time
RequestSummary:
type: object
properties:
requestId:
type: string
format: uuid
protocolNumber:
type: string
nullable: true
serviceName:
type: string
status:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
StatusHistoryEntry:
type: object
properties:
status:
type: string
transitionedAt:
type: string
format: date-time
actor:
type: string
description: "ID do usuário ou 'SYSTEM'"
note:
type: string
nullable: true
RequestDocumentRef:
type: object
properties:
documentId:
type: string
format: uuid
role:
type: string
description: "Papel do documento na solicitação (ex: RG_FRENTE, COMPROVANTE_RESIDENCIA)"
uploadedAt:
type: string
format: date-time
71.7 Grupo Funcional: Workflow e Tarefas
71.7.1 Workflow Service
paths:
/process-instances:
get:
summary: "Listagem de instâncias de processo"
tags: [Workflow]
parameters:
- name: status
in: query
schema:
type: string
enum: [ACTIVE, SUSPENDED, COMPLETED, CANCELLED]
- name: requestId
in: query
schema:
type: string
format: uuid
- name: page
in: query
schema:
type: integer
responses:
'200':
description: "Instâncias de processo paginadas"
post:
summary: "Criação de instância de processo (início de workflow)"
tags: [Workflow]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [processDefinitionKey, variables]
properties:
processDefinitionKey:
type: string
description: "Chave da definição de processo no BPM Engine"
requestId:
type: string
format: uuid
tenantId:
type: string
format: uuid
variables:
type: object
additionalProperties: true
responses:
'201':
description: "Instância de processo criada"
/process-instances/{instanceId}:
get:
summary: "Detalhe de instância de processo"
tags: [Workflow]
parameters:
- name: instanceId
in: path
required: true
schema:
type: string
responses:
'200':
description: "Estado atual da instância"
/process-instances/{instanceId}/cancel:
post:
summary: "Cancelamento de instância de processo"
tags: [Workflow]
parameters:
- name: instanceId
in: path
required: true
schema:
type: string
responses:
'200':
description: "Instância cancelada"
/process-definitions:
get:
summary: "Definições de processo disponíveis para o tenant"
tags: [Workflow]
responses:
'200':
description: "Lista de definições de processo"
/process-definitions/{key}/deploy:
post:
summary: "Deploy de nova versão de definição de processo (BPMN)"
tags: [Workflow]
parameters:
- name: key
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [bpmnFile]
properties:
bpmnFile:
type: string
format: binary
description: "Arquivo BPMN 2.0"
responses:
'201':
description: "Definição implantada"
71.7.2 Task Service
paths:
/tasks:
get:
summary: "Tarefas disponíveis para o usuário autenticado"
tags: [Tarefas]
parameters:
- name: status
in: query
schema:
type: string
enum: [CREATED, CLAIMED, IN_PROGRESS, COMPLETED, CANCELLED]
- name: assignee
in: query
schema:
type: string
description: "UUID do usuário ou 'me' para tarefas do usuário autenticado"
- name: priority
in: query
schema:
type: string
enum: [LOW, MEDIUM, HIGH, URGENT]
- name: dueBefore
in: query
schema:
type: string
format: date-time
- name: cursor
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 50
responses:
'200':
description: "Tarefas (paginação por cursor)"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/CursorPagedResponse'
/tasks/{taskId}:
get:
summary: "Detalhe de tarefa"
tags: [Tarefas]
parameters:
- name: taskId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Dados completos da tarefa"
/tasks/{taskId}/claim:
post:
summary: "Assumir tarefa"
tags: [Tarefas]
parameters:
- name: taskId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Tarefa assumida"
'409':
description: "Tarefa já assumida por outro usuário"
/tasks/{taskId}/unclaim:
post:
summary: "Devolver tarefa ao pool"
tags: [Tarefas]
parameters:
- name: taskId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Tarefa devolvida ao pool"
/tasks/{taskId}/complete:
post:
summary: "Conclusão de tarefa com variáveis de saída"
tags: [Tarefas]
parameters:
- name: taskId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
properties:
variables:
type: object
additionalProperties: true
description: "Variáveis de processo atualizadas pela tarefa"
comment:
type: string
responses:
'200':
description: "Tarefa concluída — workflow prossegue"
'409':
description: "Tarefa não está em estado concluível"
/tasks/{taskId}/delegate:
post:
summary: "Delegação de tarefa para outro usuário"
tags: [Tarefas]
parameters:
- name: taskId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [targetUserId]
properties:
targetUserId:
type: string
format: uuid
reason:
type: string
responses:
'200':
description: "Tarefa delegada"
71.8 Grupo Funcional: CRM e Comunicação
71.8.1 CRM Service
paths:
/interactions:
get:
summary: "Histórico de interações do tenant"
tags: [CRM]
parameters:
- name: citizenId
in: query
schema:
type: string
format: uuid
- name: channel
in: query
schema:
type: string
enum: [PORTAL, MOBILE, PHONE, EMAIL, WHATSAPP, PRESENTIAL]
- name: status
in: query
schema:
type: string
enum: [OPEN, PENDING, RESOLVED, CLOSED]
- name: cursor
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 100
responses:
'200':
description: "Interações (paginação por cursor)"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/CursorPagedResponse'
post:
summary: "Abertura de nova interação"
tags: [CRM]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [citizenId, channel, subject]
properties:
citizenId:
type: string
format: uuid
channel:
type: string
enum: [PORTAL, MOBILE, PHONE, EMAIL, WHATSAPP, PRESENTIAL]
subject:
type: string
requestId:
type: string
format: uuid
nullable: true
description: "Solicitação relacionada, se houver"
responses:
'201':
description: "Interação aberta"
headers:
Location:
schema:
type: string
format: uri
/interactions/{interactionId}:
get:
summary: "Detalhe da interação com histórico de mensagens"
tags: [CRM]
parameters:
- name: interactionId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Interação completa"
/interactions/{interactionId}/messages:
post:
summary: "Envio de mensagem na interação"
tags: [CRM]
parameters:
- name: interactionId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [content]
properties:
content:
type: string
maxLength: 5000
attachments:
type: array
items:
type: string
format: uuid
description: "IDs de documentos previamente enviados"
responses:
'201':
description: "Mensagem registrada"
/interactions/{interactionId}/close:
post:
summary: "Encerramento de interação"
tags: [CRM]
parameters:
- name: interactionId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
properties:
resolution:
type: string
closureReason:
type: string
enum: [RESOLVED, UNRESOLVED, CITIZEN_ABANDONED, DUPLICATE]
responses:
'200':
description: "Interação encerrada"
71.8.2 Communication Service
paths:
/communications:
post:
summary: "Envio de comunicação para cidadão (e-mail, SMS, WhatsApp, push)"
tags: [Comunicação]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [citizenId, templateId, channel]
properties:
citizenId:
type: string
format: uuid
templateId:
type: string
format: uuid
templateVersion:
type: string
channel:
type: string
enum: [EMAIL, SMS, WHATSAPP, PUSH]
variables:
type: object
additionalProperties: true
description: "Variáveis de substituição no template"
scheduledAt:
type: string
format: date-time
nullable: true
description: "Nulo para envio imediato"
responses:
'202':
description: "Comunicação aceita para envio"
content:
application/json:
schema:
type: object
properties:
communicationId:
type: string
format: uuid
status:
type: string
enum: [QUEUED, SCHEDULED]
/communications/{communicationId}:
get:
summary: "Situação de envio de comunicação"
tags: [Comunicação]
parameters:
- name: communicationId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Status de entrega"
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: [QUEUED, SCHEDULED, SENDING, DELIVERED, BOUNCED, FAILED]
sentAt:
type: string
format: date-time
nullable: true
deliveredAt:
type: string
format: date-time
nullable: true
failureReason:
type: string
nullable: true
/templates:
get:
summary: "Templates de comunicação do tenant"
tags: [Comunicação]
responses:
'200':
description: "Lista de templates"
post:
summary: "Criação de template de comunicação"
tags: [Comunicação]
responses:
'201':
description: "Template criado"
/templates/{templateId}/versions:
post:
summary: "Publicação de nova versão de template"
tags: [Comunicação]
parameters:
- name: templateId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [channel, subject, body]
properties:
channel:
type: string
enum: [EMAIL, SMS, WHATSAPP, PUSH]
subject:
type: string
nullable: true
description: "Obrigatório para e-mail"
body:
type: string
description: "Conteúdo com variáveis em sintaxe {{variavel}}"
variables:
type: array
items:
type: string
description: "Lista das variáveis esperadas no template"
responses:
'201':
description: "Versão de template publicada"
71.9 Grupo Funcional: Documentos e Agendamentos
71.9.1 Document Service
paths:
/documents:
post:
summary: "Upload de documento"
tags: [Documentos]
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [file, documentType]
properties:
file:
type: string
format: binary
description: "Arquivo binário (PDF, JPEG, PNG)"
documentType:
type: string
description: "Tipo de documento conforme catálogo do tenant"
requestId:
type: string
format: uuid
nullable: true
description: "Solicitação à qual o documento será associado"
citizenId:
type: string
format: uuid
description:
type: string
encoding:
file:
contentType: application/pdf, image/jpeg, image/png
responses:
'201':
description: "Documento armazenado"
content:
application/json:
schema:
type: object
properties:
documentId:
type: string
format: uuid
fileName:
type: string
mimeType:
type: string
sizeBytes:
type: integer
uploadedAt:
type: string
format: date-time
'413':
description: "Arquivo excede o tamanho máximo permitido"
/documents/{documentId}:
get:
summary: "Metadados do documento"
tags: [Documentos]
parameters:
- name: documentId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Metadados do documento"
'404':
$ref: '#/components/responses/404NotFound'
delete:
summary: "Exclusão de documento (restrita a rascunhos e documentos não submetidos)"
tags: [Documentos]
parameters:
- name: documentId
in: path
required: true
schema:
type: string
format: uuid
responses:
'204':
description: "Documento excluído"
'409':
description: "Documento vinculado a solicitação submetida — exclusão não permitida"
/documents/{documentId}/download:
get:
summary: "Download do arquivo do documento"
tags: [Documentos]
parameters:
- name: documentId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Arquivo binário do documento"
content:
application/octet-stream:
schema:
type: string
format: binary
headers:
Content-Disposition:
schema:
type: string
description: "attachment; filename=\"nome-do-arquivo.pdf\""
Content-Type:
schema:
type: string
/documents/{documentId}/classify:
post:
summary: "Classificação manual ou reclassificação de documento"
tags: [Documentos]
parameters:
- name: documentId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [documentType]
properties:
documentType:
type: string
classification:
type: string
enum: [PUBLIC, INTERNAL, CONFIDENTIAL, RESTRICTED]
responses:
'200':
description: "Documento classificado"
/documents/{documentId}/versions:
get:
summary: "Histórico de versões do documento"
tags: [Documentos]
parameters:
- name: documentId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Versões do documento"
71.9.2 Scheduling Service
paths:
/agendas:
get:
summary: "Agendas de atendimento disponíveis"
tags: [Agendamentos]
parameters:
- name: serviceId
in: query
schema:
type: string
format: uuid
- name: locationId
in: query
schema:
type: string
format: uuid
responses:
'200':
description: "Agendas disponíveis"
post:
summary: "Criação de agenda de atendimento"
tags: [Agendamentos]
responses:
'201':
description: "Agenda criada"
/agendas/{agendaId}/availability:
get:
summary: "Disponibilidade de horários em uma agenda"
tags: [Agendamentos]
parameters:
- name: agendaId
in: path
required: true
schema:
type: string
format: uuid
- name: date
in: query
required: true
schema:
type: string
format: date
description: "Data para consulta de disponibilidade"
responses:
'200':
description: "Horários disponíveis"
content:
application/json:
schema:
type: object
properties:
date:
type: string
format: date
slots:
type: array
items:
type: object
properties:
slotId:
type: string
format: uuid
startTime:
type: string
format: date-time
endTime:
type: string
format: date-time
available:
type: boolean
/appointments:
post:
summary: "Agendamento de horário"
tags: [Agendamentos]
parameters:
- name: Idempotency-Key
in: header
required: false
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [agendaId, slotId, citizenId]
properties:
agendaId:
type: string
format: uuid
slotId:
type: string
format: uuid
citizenId:
type: string
format: uuid
requestId:
type: string
format: uuid
nullable: true
notes:
type: string
responses:
'201':
description: "Agendamento confirmado"
content:
application/json:
schema:
$ref: '#/components/schemas/Appointment'
'409':
description: "Horário já ocupado — outro cidadão confirmou antes"
/appointments/{appointmentId}:
get:
summary: "Detalhe do agendamento"
tags: [Agendamentos]
parameters:
- name: appointmentId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Agendamento"
/appointments/{appointmentId}/reschedule:
post:
summary: "Reagendamento"
tags: [Agendamentos]
parameters:
- name: appointmentId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [newSlotId]
properties:
newSlotId:
type: string
format: uuid
reason:
type: string
responses:
'200':
description: "Reagendamento confirmado"
/appointments/{appointmentId}/cancel:
post:
summary: "Cancelamento de agendamento"
tags: [Agendamentos]
parameters:
- name: appointmentId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
type: object
properties:
reason:
type: string
responses:
'200':
description: "Agendamento cancelado"
71.10 Grupo Funcional: Ouvidoria e Satisfação
71.10.1 Ombudsman Service
paths:
/manifestations:
get:
summary: "Listagem de manifestações"
tags: [Ouvidoria]
parameters:
- name: type
in: query
schema:
type: string
enum: [RECLAMACAO, DENUNCIA, SUGESTAO, ELOGIO, SOLICITACAO, PEDIDO_INFORMACAO]
- name: status
in: query
schema:
type: string
enum: [REGISTERED, TRIAGED, FORWARDED, PENDING_COMPLEMENT, RESPONDED, CLOSED]
- name: page
in: query
schema:
type: integer
- name: size
in: query
schema:
type: integer
maximum: 50
responses:
'200':
description: "Manifestações paginadas"
post:
summary: "Registro de manifestação de ouvidoria"
tags: [Ouvidoria]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [type, subject, description]
properties:
type:
type: string
enum: [RECLAMACAO, DENUNCIA, SUGESTAO, ELOGIO, SOLICITACAO, PEDIDO_INFORMACAO]
subject:
type: string
description:
type: string
anonymous:
type: boolean
default: false
description: "Manifestação anônima — identidade não registrada"
documents:
type: array
items:
type: string
format: uuid
responses:
'201':
description: "Manifestação registrada"
/manifestations/{manifestationId}:
get:
summary: "Detalhe da manifestação"
tags: [Ouvidoria]
parameters:
- name: manifestationId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Manifestação completa"
/manifestations/{manifestationId}/forward:
post:
summary: "Encaminhamento para setor responsável"
tags: [Ouvidoria]
parameters:
- name: manifestationId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [targetSectorId]
properties:
targetSectorId:
type: string
format: uuid
forwardingNote:
type: string
responses:
'200':
description: "Manifestação encaminhada"
/manifestations/{manifestationId}/respond:
post:
summary: "Resposta à manifestação"
tags: [Ouvidoria]
parameters:
- name: manifestationId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [response]
properties:
response:
type: string
internalNote:
type: string
description: "Nota interna não visível ao cidadão"
responses:
'200':
description: "Resposta registrada"
/manifestations/{manifestationId}/close:
post:
summary: "Encerramento da manifestação"
tags: [Ouvidoria]
parameters:
- name: manifestationId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Manifestação encerrada"
71.10.2 Satisfaction Service
paths:
/feedback:
get:
summary: "Listagem de avaliações recebidas"
tags: [Satisfação]
parameters:
- name: serviceId
in: query
schema:
type: string
format: uuid
- name: channel
in: query
schema:
type: string
- name: ratingFrom
in: query
schema:
type: integer
minimum: 1
maximum: 5
- name: ratingTo
in: query
schema:
type: integer
minimum: 1
maximum: 5
- name: page
in: query
schema:
type: integer
responses:
'200':
description: "Avaliações paginadas"
post:
summary: "Submissão de avaliação pelo cidadão"
tags: [Satisfação]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [rating, context]
properties:
rating:
type: integer
minimum: 1
maximum: 5
comment:
type: string
maxLength: 1000
context:
type: object
required: [type]
properties:
type:
type: string
enum: [REQUEST, INTERACTION, APPOINTMENT, SERVICE]
referenceId:
type: string
format: uuid
channel:
type: string
responses:
'201':
description: "Avaliação registrada"
/feedback/summary:
get:
summary: "Consolidação de indicadores de satisfação"
tags: [Satisfação]
parameters:
- name: serviceId
in: query
schema:
type: string
format: uuid
- name: period
in: query
schema:
type: string
enum: [7D, 30D, 90D, 12M]
default: 30D
responses:
'200':
description: "Indicadores consolidados"
content:
application/json:
schema:
type: object
properties:
averageRating:
type: number
format: float
minimum: 1
maximum: 5
totalResponses:
type: integer
nps:
type: number
description: "Net Promoter Score calculado"
distribution:
type: object
properties:
rating1:
type: integer
rating2:
type: integer
rating3:
type: integer
rating4:
type: integer
rating5:
type: integer
period:
type: object
properties:
from:
type: string
format: date
to:
type: string
format: date
71.11 Grupo Funcional: Analytics e IA
71.11.1 Analytics Service
paths:
/dashboards:
get:
summary: "Dashboards disponíveis para o perfil do usuário"
tags: [Analytics]
responses:
'200':
description: "Lista de dashboards"
/dashboards/{dashboardId}/data:
get:
summary: "Dados do dashboard para renderização"
tags: [Analytics]
parameters:
- name: dashboardId
in: path
required: true
schema:
type: string
format: uuid
- name: period
in: query
schema:
type: string
enum: [TODAY, 7D, 30D, 90D, 12M, CUSTOM]
- name: from
in: query
schema:
type: string
format: date
- name: to
in: query
schema:
type: string
format: date
responses:
'200':
description: "Conjuntos de dados para os widgets do dashboard"
/metrics/{domain}:
get:
summary: "Métricas operacionais por domínio"
tags: [Analytics]
parameters:
- name: domain
in: path
required: true
schema:
type: string
enum: [requests, interactions, ombudsman, appointments, communications, satisfaction]
- name: period
in: query
schema:
type: string
enum: [7D, 30D, 90D, 12M]
default: 30D
responses:
'200':
description: "Métricas do domínio selecionado"
/reports:
get:
summary: "Relatórios disponíveis e agendados"
tags: [Analytics]
responses:
'200':
description: "Lista de relatórios"
/reports/export:
post:
summary: "Exportação de relatório"
tags: [Analytics]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [reportType, period, format]
properties:
reportType:
type: string
period:
type: object
properties:
from:
type: string
format: date
to:
type: string
format: date
format:
type: string
enum: [CSV, XLSX, PDF]
filters:
type: object
additionalProperties: true
responses:
'202':
description: "Exportação em processamento"
content:
application/json:
schema:
type: object
properties:
exportId:
type: string
format: uuid
estimatedReadyAt:
type: string
format: date-time
71.11.2 AI Gateway — Contratos de IA
paths:
/ai/chat:
post:
summary: "Envio de mensagem ao assistente de IA do tenant"
tags: [IA]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [message]
properties:
message:
type: string
maxLength: 4096
conversationId:
type: string
format: uuid
nullable: true
description: "Nulo para nova conversa"
stream:
type: boolean
default: false
description: "true para resposta via Server-Sent Events"
context:
type: object
properties:
requestId:
type: string
format: uuid
serviceId:
type: string
format: uuid
responses:
'200':
description: "Resposta da IA (modo síncrono)"
content:
application/json:
schema:
type: object
properties:
conversationId:
type: string
format: uuid
messageId:
type: string
format: uuid
content:
type: string
model:
type: string
description: "Modelo utilizado — abstraído pelo AI Gateway"
tokensUsed:
type: integer
text/event-stream:
schema:
type: string
description: |
Server-Sent Events para modo streaming.
Eventos: data: {delta}, data: [DONE]
/ai/search:
post:
summary: "Busca semântica na base de conhecimento do tenant"
tags: [IA]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [query]
properties:
query:
type: string
maxLength: 512
knowledgeBaseId:
type: string
format: uuid
nullable: true
topK:
type: integer
minimum: 1
maximum: 20
default: 5
responses:
'200':
description: "Resultados da busca semântica"
content:
application/json:
schema:
type: object
properties:
results:
type: array
items:
type: object
properties:
documentId:
type: string
chunk:
type: string
score:
type: number
format: float
metadata:
type: object
additionalProperties: true
/ai/classify:
post:
summary: "Classificação de texto por modelo de IA"
tags: [IA]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [text, classificationTask]
properties:
text:
type: string
classificationTask:
type: string
enum: [MANIFESTATION_TYPE, SENTIMENT, PRIORITY, SERVICE_CATEGORY]
responses:
'200':
description: "Resultado da classificação"
content:
application/json:
schema:
type: object
properties:
label:
type: string
confidence:
type: number
format: float
alternatives:
type: array
items:
type: object
properties:
label:
type: string
confidence:
type: number
/ai/knowledge-bases:
get:
summary: "Bases de conhecimento do tenant"
tags: [IA]
responses:
'200':
description: "Lista de bases de conhecimento"
post:
summary: "Criação de base de conhecimento"
tags: [IA]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
description:
type: string
responses:
'201':
description: "Base criada"
/ai/knowledge-bases/{knowledgeBaseId}/documents:
post:
summary: "Indexação de documento na base de conhecimento"
tags: [IA]
parameters:
- name: knowledgeBaseId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
title:
type: string
metadata:
type: string
description: "JSON com metadados do documento"
responses:
'202':
description: "Documento aceito para indexação"
71.12 Contratos de Webhooks
A plataforma expõe mecanismo de webhooks para notificação de eventos a sistemas externos autorizados. O contrato de webhook é simétrico ao catálogo de eventos do Capítulo 72.
paths:
/webhooks:
get:
summary: "Endpoints de webhook configurados pelo tenant"
tags: [Webhooks]
responses:
'200':
description: "Lista de webhooks"
post:
summary: "Registro de endpoint de webhook"
tags: [Webhooks]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [targetUrl, events, signingSecret]
properties:
targetUrl:
type: string
format: uri
description: "Endpoint HTTPS do sistema receptor"
events:
type: array
items:
type: string
description: "Eventos subscritos (ex: request.submitted.v1)"
signingSecret:
type: string
writeOnly: true
description: "Segredo para assinatura HMAC-SHA256 do payload"
active:
type: boolean
default: true
responses:
'201':
description: "Webhook registrado"
/webhooks/{webhookId}:
delete:
summary: "Remoção de webhook"
tags: [Webhooks]
parameters:
- name: webhookId
in: path
required: true
schema:
type: string
format: uuid
responses:
'204':
description: "Webhook removido"
/webhooks/{webhookId}/test:
post:
summary: "Disparo de evento de teste"
tags: [Webhooks]
parameters:
- name: webhookId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: "Payload de teste enviado"
content:
application/json:
schema:
type: object
properties:
httpStatus:
type: integer
responseTimeMs:
type: integer
success:
type: boolean
Payload padrão de webhook:
{
"webhookId": "uuid",
"eventType": "request.submitted.v1",
"occurredAt": "2026-07-17T14:30:00Z",
"tenantId": "uuid",
"payload": {
"requestId": "uuid",
"protocolNumber": "2026-00123456",
"serviceId": "uuid"
},
"signature": "sha256=hmac-assinatura-hex"
}
A assinatura usa HMAC-SHA256 sobre o corpo bruto do payload. O receptor deve validar a assinatura antes de processar o evento. Webhooks sem resposta 2xx em até 30 segundos são reenviados com backoff exponencial até 5 tentativas.
71.13 Convenções Transversais de Contrato
71.13.1 Headers Obrigatórios em Toda Requisição Autenticada
| Header | Tipo | Gerado por | Propósito |
|---|---|---|---|
Authorization: Bearer {token} | Autenticação | Cliente | Token JWT de sessão |
X-Tenant-Id | Contexto | Gateway | Derivado do token — não aceito do cliente como único fator |
X-Correlation-Id | Rastreamento | Gateway | Propagado ao longo de toda a cadeia |
X-Request-Id | Rastreamento | Gateway | Identificador único da requisição HTTP |
traceparent | Telemetria | Gateway | W3C Trace Context para rastreamento distribuído |
71.13.2 Headers de Resposta Padrão
| Header | Presente em | Propósito |
|---|---|---|
Location | POST 201 | URL do recurso criado |
ETag | GET com versionamento | Versão do recurso para controle de concorrência |
Sunset | APIs depreciadas | Data de remoção da versão |
Retry-After | 429 | Segundos até próxima tentativa |
X-Correlation-Id | Todas as respostas | Rastreabilidade na resposta |
71.13.3 Campos Proibidos em Respostas
Independentemente do que o consumidor solicita, os contratos garantem que as seguintes informações nunca aparecem em respostas de API:
- Stack trace Java ou qualquer outra linguagem
- Nome de classe interna, método, caminho de arquivo ou linha de código
- Query SQL ou nome de tabela
- URL interna de serviço
- Credencial, chave de API, segredo ou token
- Payload completo de outro tenant
- Dados pessoais sensíveis em endpoints que não os requerem explicitamente
71.13.4 Matriz de Paginação por Tipo de API
| Tipo de Listagem | Estratégia | Parâmetros | Resposta |
|---|---|---|---|
| Listagens administrativas com total | Offset | page, size (max 100) | PagedResponse com totalElements |
| Feeds, histórico, grandes volumes | Cursor | cursor, limit (max 100) | CursorPagedResponse com nextCursor |
| Busca com relevância | Cursor + score | cursor, limit, q | Itens com campo score |
| Exportações | Assíncrona | Job ID + polling | 202 Accepted + endpoint de status |
71.13.5 Tenant Isolation por Contrato
Nenhum endpoint retorna ou aceita dados de tenant diferente do tenant derivado da identidade autenticada. Essa garantia é aplicada em duas camadas: o API Gateway bloqueia requisições sem token válido e extrai o tenant do token; o serviço de domínio filtra todos os acessos ao banco de dados pelo tenantId extraído do Tenant Context — nunca pelo tenantId da query string ou body do cliente.
71.14 Catálogo de Contratos por Serviço
A tabela a seguir consolida todos os contratos OpenAPI da plataforma com localização, versão e classificação.
| Serviço | Arquivo de Contrato | Versão | Classificação | Estratégia |
|---|---|---|---|---|
| Identity Service | identity-service-api.yaml | 1.2.0 | Pública + Canal | Design First |
| Tenant Service | tenant-service-api.yaml | 1.1.0 | Administrativa | Design First |
| Citizen Service | citizen-service-api.yaml | 1.3.0 | Pública + Canal | Design First |
| Service Catalog Service | catalog-service-api.yaml | 1.2.0 | Pública + Canal | Design First |
| Forms Service | forms-service-api.yaml | 1.1.0 | Canal + Interna | Design First |
| Request Service | request-service-api.yaml | 2.0.0 | Pública + Canal | Design First |
| Workflow Service | workflow-service-api.yaml | 1.0.0 | Interna + Administrativa | Code First governado |
| Task Service | task-service-api.yaml | 1.1.0 | Canal + Interna | Design First |
| CRM Service | crm-service-api.yaml | 1.2.0 | Canal + Interna | Design First |
| Communication Service | communication-service-api.yaml | 1.1.0 | Canal + Interna | Code First governado |
| Document Service | document-service-api.yaml | 1.3.0 | Pública + Canal | Design First |
| Scheduling Service | scheduling-service-api.yaml | 1.1.0 | Pública + Canal | Design First |
| Ombudsman Service | ombudsman-service-api.yaml | 1.0.0 | Pública + Canal | Design First |
| Satisfaction Service | satisfaction-service-api.yaml | 1.0.0 | Pública + Canal | Design First |
| Segmentation Service | segmentation-service-api.yaml | 1.0.0 | Administrativa + Interna | Code First governado |
| Campaign Service | campaign-service-api.yaml | 1.0.0 | Administrativa | Code First governado |
| Analytics Service | analytics-service-api.yaml | 1.1.0 | Canal + Administrativa | Design First |
| Data Quality Service | data-quality-service-api.yaml | 1.0.0 | Administrativa | Code First governado |
| AI Gateway | ai-gateway-api.yaml | 1.2.0 | Canal + Interna | Design First |
| AI Specialized Service | ai-specialized-api.yaml | 1.0.0 | Interna | Code First governado |
| Integration Service | integration-service-api.yaml | 1.1.0 | Integração | Design First |
| Configuration Service | configuration-service-api.yaml | 1.0.0 | Administrativa | Code First governado |
| Audit Service | audit-service-api.yaml | 1.0.0 | Administrativa | Design First |
| Webhooks | webhooks-api.yaml | 1.0.0 | Administrativa | Design First |
Os arquivos de contrato são armazenados no repositório platform-api-contracts/ sob controle de versão Git, com pull request obrigatório para alterações em contratos classificados como Design First. O pipeline de CI valida a compatibilidade de cada pull request contra a versão anterior do contrato usando ferramentas de diff semântico de OpenAPI.
71.15 Governança de Evolução dos Contratos
71.15.1 Compatibilidade e Breaking Changes
A regra de compatibilidade segue o Capítulo 14: mudanças compatíveis não requerem nova versão de URI; mudanças incompatíveis exigem nova versão e período de convivência. O pipeline detecta automaticamente mudanças incompatíveis usando análise de diff de schema OpenAPI e bloqueia o merge quando identifica:
- remoção de campo presente em respostas anteriores
- mudança de tipo de campo existente
- adição de campo obrigatório em request body
- mudança de código HTTP de sucesso
- remoção de endpoint ou método HTTP
71.15.2 Período de Deprecação
Contratos depreciados publicam o header Sunset com a data de remoção planejada. O portal de APIs exibe avisos de deprecação para desenvolvedores. Tenants integrados diretamente às APIs recebem comunicação formal conforme a política de descontinuação definida no Capítulo 55.
Sunset: Tue, 31 Mar 2027 00:00:00 GMT
Deprecation: Sat, 01 Oct 2026 00:00:00 GMT
Link: <https://api.plataforma.mg.gov.br/v2/requests>; rel="successor-version"
71.15.3 Testes de Contrato no Pipeline
Cada serviço de domínio mantém testes de contrato automatizados que verificam se a implementação Java/Spring Boot está em conformidade com o arquivo OpenAPI correspondente. A abordagem é Pact-compatible para APIs de integração crítica: o consumidor define suas expectativas em um pact file; o produtor verifica sua implementação contra esse pact no pipeline de CI. Qualquer divergência entre contrato e implementação falha o pipeline antes do merge, garantindo que contratos e código nunca divirjam silenciosamente.
71.16 Riscos e Mitigações
| Risco | Consequência | Mitigação |
|---|---|---|
| Contrato desatualizado em relação à implementação | Consumidores codificam comportamento não documentado | Testes de contrato no pipeline; falha em caso de divergência |
| Breaking change sem versionamento de URI | Canais quebram após deploy | Análise automática de diff no pipeline; bloqueio de merge |
| Schema com campo obrigatório adicionado silenciosamente | Clientes antigos falham na serialização | Pipeline de compatibilidade; período de deprecação obrigatório |
| Tenant Context extraído do body | Acesso cruzado entre órgãos | Tenant Context extraído exclusivamente do token pelo Gateway |
| Dados pessoais em logs de API | Vazamento de informação pessoal (LGPD) | Mascaramento automático no middleware de logging; PII identificado no schema |
| Contrato de IA sem isolamento de quota | Tenant consome quota de outro | Quotas por tenant aplicadas no AI Gateway, não apenas no API Gateway externo |
| Versionamento inconsistente entre serviços | Dificuldade de coordenação de mudanças | Convenção única (/api/v{N}/) aplicada por linting no pipeline |
71.17 Decisões Arquiteturais
| ADR | Tema |
|---|---|
| ADR-086 | REST Guideline corporativo — verbos, URLs, JSON, datas |
| ADR-087 | Convenção JSON e padrão de datas (camelCase, ISO 8601 UTC) |
| ADR-088 | Estratégia de versionamento de APIs (URI, período de deprecação) |
| ADR-089 | Problem Details RFC 9457 — formato estendido com correlationId |
| ADR-090 | Estratégia de paginação por tipo de API (offset vs cursor) |
| ADR-091 | Idempotency-Key — implementação e retenção |
| ADR-092 | ETag e controle de concorrência otimista |
| ADR-093 | OpenAPI como contrato — Design First vs. Code First por categoria |
| ADR-094 | Tenant Context em HTTP — extração do token, não do header do cliente |
| ADR-106 | Webhooks — política, assinatura HMAC-SHA256 e reentrega |
| ADR-107 | Streaming de IA — SSE via text/event-stream por canal |
| ADR-108 | Contratos das capacidades de IA no AI Gateway |
71.18 Rastreabilidade com Requisitos
Bloco 5 — Integração e Interoperabilidade (Anexo III):
- Item 5.1 — Integração com sistemas internos e externos via APIs: todos os 24 serviços de domínio expõem contratos OpenAPI documentados neste capítulo; o padrão REST com versionamento por URI é aplicado uniformemente.
- Item 5.3 — Gestão de APIs (versionamento e monitoramento): ciclo de vida de contrato com estados Proposed → Retired documentados no catálogo; header
Sunsetpara deprecações; pipeline de compatibilidade como controle automatizado. - Item 5.6 — Uso de padrões de interoperabilidade: OpenAPI 3.1.0 como especificação de contrato; RFC 9457 para erros; W3C Trace Context para rastreamento; OAuth 2.0 / JWT para autenticação.
Bloco 6 — Infraestrutura, Segurança e Governança (Anexo III):
- Item 6.5 — Rastreabilidade e auditoria: correlationId em toda resposta; X-Request-Id e traceparent propagados; PII mascarado em logs de API.
Capacidades (Anexo IV):
- Item 1.2 — Integração de sistemas por APIs: catálogo de 24 contratos OpenAPI versionados; Design First para APIs de alto impacto; testes de contrato automatizados no pipeline.
- Item 2.1 — Arquitetura multi-tenant: Tenant Context extraído do token em todos os contratos; filtro de tenant obrigatório validado por contrato e por implementação.
71.19 Próximo Capítulo
O Capítulo 72 — Eventos e Tópicos de Mensageria — documenta os contratos assíncronos da plataforma: o catálogo completo de eventos por domínio, as definições AsyncAPI dos tópicos RabbitMQ, os schemas de payload de cada evento, as políticas de DLQ e reentrega, e a rastreabilidade entre eventos publicados e consumidos pelos 24 serviços de domínio.
71.20 Controle de Versão
| Campo | Valor |
|---|---|
| Documento | Documento Mestre — Plataforma de Relacionamento Digital com o Cidadão |
| Capítulo | 71 — Contratos REST e OpenAPI |
| Versão | 1.0 |
| Situação | Concluído |
| Última atualização | 17/07/2026 |
71.21 Rastreabilidade PRODEMGE
Edital CP 001/2026:
- Item 3.3 — Grupos de características técnicas: APIs REST documentadas em OpenAPI como padrão de interoperabilidade da plataforma.
Plano de Negócio (Anexo I):
- Seção 3.3 — Características Técnicas: plataforma interoperável com APIs documentadas e integrada ao ecossistema governamental.
- Seção 5 — Propriedade intelectual e custódia: contratos versionados em repositório sob custódia PRODEMGE conforme Capítulo 58.
Funcionalidades (Anexo III) — impacto na pontuação de 60%:
- Bloco 5, Item 5.1 — Integração com sistemas internos e externos via APIs: 24 contratos OpenAPI documentados neste capítulo.
- Bloco 5, Item 5.3 — Gestão de APIs (versionamento e monitoramento): ciclo de vida de contrato com análise automática de compatibilidade.
- Bloco 5, Item 5.6 — Uso de padrões de interoperabilidade: OpenAPI 3.1.0, RFC 9457, W3C Trace Context.
- Bloco 6, Item 6.5 — Rastreabilidade e auditoria: correlationId rastreável em toda resposta de API.
Capacidades (Anexo IV) — impacto na pontuação de 30%:
- Bloco 1, Item 1.2 — Integração de sistemas por APIs: catálogo de 24 contratos versionados com testes automatizados de conformidade.
- Bloco 2, Item 2.1 — Arquitetura multi-tenant: Tenant Context por contrato, validado em duas camadas.
Esclarecimentos pertinentes:
- Madrona Advogados, 08/07/2026 — Documentação funcional confirmada: especificações de API, contratos OpenAPI, schemas e exemplos são evidências aceitas para fins de qualificação técnica.
- WideLabs, 09/07/2026 — Evidências por links acessíveis publicamente são aceitas; os arquivos de contrato OpenAPI referenciados neste capítulo são acessíveis no repositório público da plataforma.
Erratas:
- Errata nº 002 — Não aplicável a este capítulo.
Capítulo 70 — Modelo de Dados
Este capítulo apresenta o modelo de dados da Plataforma de Relacionamento Digital com o Cidadão. O objetivo é documentar as principais entidades de cada domínio, seus atributos relevantes, chaves, relacionamentos e invar…
Capítulo 72 — Eventos e Tópicos de Mensageria
Este capítulo documenta de forma consolidada e de referência o catálogo completo de eventos de domínio, comandos assíncronos e trabalhos distribuídos da Plataforma de Relacionamento Digital com o Cidadão.