Guia do módulo SAT — Assistência Técnica
Microserviço: XDPeople.Soba.WebAPI (Core API) + Invoice API (emissão)
Autenticação: token Bearer (JWT) e contexto de tenant — ver Login Combinado
Os endpoints de gestão vivem em https://api.xdsoba.com/gateway/... e exigem o cabeçalho Authorization: Bearer {token}.
Introdução
O módulo SAT (Serviço de Assistência Técnica) cobre o ciclo completo de assistência no Soba: catálogos, contratos de assistência, equipamentos do cliente, ordens de serviço, intervenções técnicas, fecho, faturação e RMA (devoluções), mais relatórios próprios.
Visão geral do fluxo
| Passo | O quê | Onde no guia |
|---|---|---|
| 1 | Preparar catálogos (uma vez por tenant) | Catálogos |
| 1.5 | Configuração do módulo SAT | Configuração |
| 2 | Contratos de assistência (opcional) | Contratos |
| 3 | Registar equipamento do cliente | Equipamento |
| 4 | Abrir, fechar e reabrir a Ordem de Serviço | Ordem de serviço |
| 4.1 | Linhas facturáveis (details) | Ordem de serviço |
| 5 | Registar intervenções | Intervenções |
| 5.1 | Ligar intervenções à Ordem de Serviço | Ligações |
| 6 | Pré-visualizar e emitir fatura | Faturação |
| — | Devoluções (fluxo paralelo) | RMA |
| — | Ligar RMA à Ordem de Serviço | Ligações |
Mapa rápido de recursos
| Área | Prefixo típico |
|---|---|
| Equipamento | /gateway/equipment-type, equipment-brand, equipment-model, equipment |
| Ordem de Serviço | /gateway/service-order-catalog, service-order-state, service-order, sat-config |
| Intervenção | /gateway/intervention-config, intervention |
| Contrato | /gateway/entity-contract-group, entity-contract-type, entity-contract |
| Faturação | /gateway/service-order/invoice/preview, /gateway/intervention/invoice/preview, /gateway/invoice/invoices |
| RMA | /gateway/return-type, return-reason, rma |
Ligar intervenções e RMA à Ordem de Serviço
A ordem de serviço tem de existir primeiro: a ligação usa sempre o GUID devolvido no POST /gateway/service-order (ou obtido em GET /gateway/service-order/{series}/{number}). Não é possível criar a ordem de serviço e as suas intervenções no mesmo pedido — o payload da ordem de serviço não aceita uma lista de intervenções.
Passo 5.1 — Ligar intervenções à Ordem de Serviço
Opção A — ligar ao criar a intervenção
POST /gateway/intervention
Content-Type: application/json
Authorization: Bearer {token}
{
"type": "DIAG",
"status": "CURSO",
"description": "Diagnóstico inicial da fonte de alimentação",
"userId": 1,
"entityKeyId": "C0001",
"equipmentId": 123,
"serviceOrderGuid": "GUID-DA-ORDEM",
"concluded": true,
"discountTime": 1.5,
"discountTimeItemId": "MO-HORA",
"details": [
{
"itemKeyId": "FONTE-19V",
"itemDescription": "Fonte de alimentação 19V / 65W",
"quantity": 1,
"retailPrice": 45.00
}
]
}
A API valida que a ordem de serviço existe e copia dela a série e o número, devolvidos depois em serviceOrderSeries e serviceOrderNumber. Se a ordem de serviço não existir, devolve 404 ServiceOrder.NotFound.
Se o serviceOrderGuid for enviado vazio ou não for um GUID válido, o campo é ignorado em silêncio e a intervenção fica sem ordem de serviço — não há erro. Confirme sempre com o GET da ordem de serviço.
Não há herança de dados da ordem de serviço: entityKeyId, equipmentId e entityContractId têm de ser enviados no payload da intervenção, mesmo que a ordem de serviço já os tenha.
Opção B — associar uma intervenção que já existe
POST /gateway/service-order/GUID-DA-ORDEM/interventions/46
Authorization: Bearer {token}
Resposta: 204 No Content, sem corpo. Para ligar várias intervenções à mesma ordem de serviço, repita a chamada — uma por intervenção; não existe endpoint em lote:
POST /gateway/service-order/GUID-DA-ORDEM/interventions/46
Authorization: Bearer {token}
POST /gateway/service-order/GUID-DA-ORDEM/interventions/47
Authorization: Bearer {token}
POST /gateway/service-order/GUID-DA-ORDEM/interventions/48
Authorization: Bearer {token}
| Situação | Resposta |
|---|---|
| Associada com sucesso | 204 |
| Já estava ligada a esta mesma ordem de serviço | 204 (a operação é idempotente) |
| Já está ligada a outra ordem de serviço | 409 Intervention.AlreadyLinked |
| Ordem de Serviço inexistente | 404 ServiceOrder.NotFound |
| Intervenção inexistente | 404 Intervention.NotFound |
Consultar as intervenções de uma Ordem de Serviço: GET /gateway/service-order/{guid}, na propriedade interventions[]. Não existe GET /service-order/{guid}/interventions, e a listagem GET /gateway/intervention não filtra por ordem de serviço.
Remover uma intervenção da Ordem de Serviço
DELETE /gateway/service-order/GUID-DA-ORDEM/interventions/46
Authorization: Bearer {token}
Este endpoint não desliga a intervenção da ordem de serviço: elimina-a (remoção lógica). Não há operação de “unlink” que devolva a intervenção ao estado de intervenção isolada. Se a intervenção não pertencer àquela ordem de serviço, devolve 409 Intervention.NotLinkedToServiceOrder.
Editar depois de ligada
Depois de ligada, a intervenção só se edita “através” da ordem de serviço. O PUT /gateway/intervention/{id} devolve 409 Intervention.CannotEditLinkedToServiceOrder — a não ser que o corpo do pedido repita o mesmo serviceOrderGuid, que é o sinal de que a edição vem do contexto da ordem de serviço (a mesma excepção se aplica a intervenções já facturadas, que de outro modo devolvem 409 Intervention.CannotEditInvoiced).
O serviceOrderGuid é ignorado no update: não serve para mudar a intervenção de ordem de serviço. Para mudar a ligação use o endpoint de associação, e só é possível se a intervenção não estiver já ligada a outra ordem de serviço.
RMA — ligar a uma ordem de serviço
Também aqui a ordem de serviço tem de estar criada primeiro, porque a ligação se faz pelo GUID dela. Há duas formas, e a escolha tem consequências.
Opção A — declarar a Ordem de Serviço no próprio RMA
POST /gateway/rma
Content-Type: application/json
Authorization: Bearer {token}
{
"rmaId": "RMA-2026-001",
"rmaType": 1,
"equipmentId": 123,
"quantity": 1,
"returnType": "Garantia",
"returnReason": "Avaria de fabrico",
"serviceOrderGuid": "GUID-DA-ORDEM"
}
Funciona igualmente no PUT /gateway/rma/{guid}, o que permite ligar a posteriori um RMA já criado.
Ao contrário da intervenção, o serviceOrderGuid do RMA não é validado: um GUID errado é aceite e o RMA fica órfão, sem aparecer no detalhe da Ordem de Serviço e sem qualquer erro. Confirme sempre com GET /gateway/service-order/{guid}.
Opção B — enviar os RMAs no payload da Ordem de Serviço
PUT /gateway/service-order/GUID-DA-ORDEM
Content-Type: application/json
Authorization: Bearer {token}
{
"status": "RECEB",
"priority": "URG",
"assistanceTypeKeyId": "REP",
"rmaList": [
{ "rmaId": "RMA-2026-001", "rmaType": 1, "equipmentId": 123, "quantity": 1 },
{ "rmaId": "RMA-2026-002", "rmaType": 2, "componentKeyId": "FONTE19V", "quantity": 1 }
]
}
A API preenche automaticamente o serviceOrderGuid e a serviceOrderDesignation de cada RMA a partir da ordem, e gera o GUID dos que não o trouxerem.
No PUT, o rmaList é uma substituição total e destrutiva: os RMAs existentes da Ordem de Serviço são apagados fisicamente da base de dados e recriados a partir da lista enviada — com GUIDs novos, se os não incluir. Omitir o campo (null) preserva os RMAs actuais; enviar [] apaga todos.
Por esta via, as validações do recurso RMA não são aplicadas: rmaId duplicado, existência de returnType/returnReason e a obrigatoriedade de equipmentId (tipo Equipment) ou componentKeyId (tipo Component) só são verificadas no POST/PUT /gateway/rma. Para dados vindos de integrações, prefira a Opção A.
Se a Ordem de Serviço estiver fechada, o PUT /gateway/service-order/{guid} devolve 409 ServiceOrder.CannotEditClosed. Nesse caso, ligue ou altere o RMA pelo PUT /gateway/rma/{guid}.
Desligar um RMA da Ordem de Serviço: PUT /gateway/rma/{guid} com serviceOrderGuid vazio, ou retirando-o do rmaList da ordem (lembrando que isso apaga e recria os restantes).
Consultar os RMAs de uma Ordem de Serviço: GET /gateway/service-order/{guid}, na propriedade rmaList[]. Não existe GET /service-order/{guid}/rmas.
Resumo das duas ligações
| Intervenção → Ordem de Serviço | RMA → Ordem de Serviço | |
|---|---|---|
| Ordem tem de existir antes | Sim | Sim |
| Campo de ligação | serviceOrderGuid (opcional) | serviceOrderGuid (opcional) |
| Existência da Ordem de Serviço é validada | Sim (404 se não existir) | Não (fica órfão em silêncio) |
| Endpoint dedicado | POST /gateway/service-order/{guid}/interventions/{id} | Não existe |
| Pelo payload da Ordem de Serviço | Não suportado | rmaList (substituição total no PUT) |
| Mudar de Ordem de Serviço no PUT do recurso | Não (campo ignorado) | Sim |
| Consulta | GET /service-order/{guid} → interventions[] | GET /service-order/{guid} → rmaList[] |
| Desfazer a ligação | Só apagando a intervenção | serviceOrderGuid vazio no PUT do RMA |
Relatórios SAT
O módulo inclui quatro relatórios próprios (disponíveis na UI do produto e através da API de Relatórios padrão):
| Relatório | Conteúdo | Identificador |
|---|---|---|
| Contratos de entidade | Contratos, plafond, horas usadas e disponíveis (agora calculadas) | D3B0946B-409F-477C-855D-A05BC517B186 |
| Equipamentos | Parque de equipamentos por cliente, marca, modelo e garantia | 367DD5A9-D7A4-4722-906F-3A88EDFC616E |
| Intervenções | Trabalho técnico por período, técnico, cliente e contrato | BE27808C-123D-4699-9107-666D255530DE |
| Ordens de serviço | Ordens por estado, prioridade, tipo de assistência e equipamento | B2D7C4E8-1A3F-4B9C-8D6E-5F2A7C3B1D9E |
Use GET /gateway/reports/{reportId}/info e GET /gateway/reports/{reportId}?jsonParameters=… conforme o guia da Report API.
Erros comuns
| HTTP | Situação | Como resolver |
|---|---|---|
400 | Campo obrigatório em falta (status, priority, assistanceTypeKeyId…) | A mensagem indica o primeiro campo em falta |
400 | keyId de catálogo inexistente | Criar primeiro a entrada no catálogo (Passo 1) |
400 | ExtraOnlyRequiresContract | O modo ExtraOnly exige intervenção com contrato associado |
400 | Invoice.Details.OnlyComments | O documento tem de ter pelo menos uma linha valorizada (details) |
400 | ServiceOrderInvoice.NothingToInvoice / InterventionInvoice.NothingToInvoice | Adicionar details e/ou horas/km valorizados |
400 | ServiceOrder.InvalidDetailItemKeyId / Intervention.InvalidDetailItemKeyId | Enviar itemKeyId nas linhas com quantity > 0 |
400 | ServiceOrder.ResponsibleUserRequired | Enviar responsibleUserId > 0 quando isEmployeeFillObligatory está activo |
400 | SatLineNotFromDeclaredOrigin | A linha enviada não pertence à ordem/intervenção declarada no cabeçalho |
404 | GUID/id inexistente | Confirmar com o GET de listagem |
404 | ServiceOrder.NotFound / Intervention.NotFound | Confirmar o GUID da ordem ou o id da intervenção |
404 | ServiceOrder.ItemNotFound / Intervention.ItemNotFound | Criar primeiro o artigo no catálogo de artigos |
404 | ServiceOrderConfiguration.NotFound | Tratar como valores por omissão, ou fazer PUT /gateway/sat-config |
409 | Fecho com intervenções abertas | Usar close-preview e enviar concludeOpenInterventions: true |
409 | ServiceOrder.CannotRemoveInvoicedDetail | Não omitir no PUT linhas de details já facturadas |
409 | Intervention.AlreadyLinked | A intervenção já está ligada a outra ordem |
409 | Intervention.CannotEditLinkedToServiceOrder | Repetir o mesmo serviceOrderGuid no PUT (edição no contexto da ordem) |
409 | Intervention.NotLinkedToServiceOrder | O DELETE só remove intervenções que pertencem àquela ordem |
409 | ServiceOrder.CannotEditClosed | Reabrir a ordem, ou alterar o RMA via PUT /gateway/rma/{guid} |
409 | keyId / rmaId duplicado | Escolher outra chave ou consultar o existente |