Guia de Utilização da API de Facturação
Versão da API: v1.0 Microserviço: XDPeople.Soba.Invoice.WebAPI
Visão geral
A API de Facturação gere o ciclo de vida de documentos de venda através de um único endpoint de criação. Uma chamada — POST /gateway/invoice/invoices — cria documentos cujo comportamento é determinado pelo documentTypeId.
Naturezas suportadas
| Natureza | Código | Guia dedicado |
|---|---|---|
| Fatura | FT | Guia de Faturas |
| Fatura simplificada | FS | Guia de Faturas |
| Fatura-recibo | FR | Guia de Faturas-Recibo |
| Nota de crédito | NC | Guia de Notas de Crédito |
| Nota de débito | ND | Guia de Notas de Débito |
| Encomenda | NE | Guia de Encomendas |
| Orçamento | ORC | Guia de Orçamentos |
| Guias de transporte | GT, GR, GA, GC, GD | Guias de Transporte |
Mecanismos de pagamento permitidos
Qualquer entrada em payments[] deve usar um tipo de pagamento cujo mecanismo (paymentMechanism) pertença à lista abaixo. Esta restrição aplica-se a todos os documentos, independentemente de os pagamentos serem obrigatórios ou opcionais. No pedido envia-se paymentTypeId.
| Código | Descrição |
|---|---|
NU | Numerário |
CC | Cartão de crédito |
CD | Cartão de débito |
OU | Outros |
Obtenha os identificadores válidos com GET /gateway/payment-types e seleccione registos cujo paymentMechanism corresponda a um dos códigos acima.
A API valida o mecanismo de cada entrada em payments[] na criação do documento. Tipos de pagamento com outros mecanismos (por exemplo TB, CH, MB, MW) são rejeitados, mesmo que estejam activos na base de dados do cliente.
Regras de tipo de pagamento com conta-corrente
Esta API não aceita tipos de pagamento com SendToCheckingAccount = true. Qualquer tentativa de os usar devolve Payment.CheckingAccount.NotSupported. Tipos de documento configurados com CheckingAccountFlow != 0 ou MoveSetting = CheckingAccount exigem precisamente esse tipo de pagamento — tornando-os incompatíveis com esta API.
Quando o tipo de documento tem requisitos de conta-corrente, o tipo de pagamento fornecido em payments[] tem de os satisfazer. Caso contrário, a entrada de pagamento é rejeitada:
| Configuração do tipo de documento | Erro |
|---|---|
MoveSetting = CheckingAccount e o tipo de pagamento não lança em conta-corrente | Payment.CheckingAccountType.RequiredForMoveSetting |
Modo de pagamento com IncrementDays > 0 e o tipo não é de conta-corrente | Payment.CheckingAccountType.RequiredForDeferredMode |
CheckingAccountFlow != 0 e o tipo de pagamento não é de conta-corrente | Payment.CheckingAccountType.RequiredForDocumentFlow |
A natureza RE (recibo) não pode ser criada através desta API. Utilize fatura-recibo (FR) quando o pagamento é feito no mesmo documento, ou consulte a documentação do produto para fluxos de conta corrente. O Guia de Recibos mantém-se apenas como referência.
Outras naturezas (proforma, CAS, DIS, etc.) não estão disponíveis nesta API e devolvem DocumentType.NotSupported.
Características principais
- Criação de documentos de ponta a ponta (validação, totais, pagamentos, persistência)
- Criação, atualização e consulta (formatos flat e completo)
- Filtros avançados e paginação
- Autenticação JWT
- Persistência de datas com fuso horário via header
X-Timezone
Como funciona a criação de documentos
Quando chama POST /gateway/invoice/invoices, a API:
- Validação inicial — natureza suportada, país/licença, mecanismos de pagamento, série, cliente, regras de emissão
- Preparação do cabeçalho — resolução de entidade, defaults de transporte, validações fiscais
- Cálculos — totais de linha e cabeçalho, impostos, descontos
- Pagamentos — multi-pagamento, troco; para tipos com pagamentos opcionais, no máximo uma entrada sem multi-pagamento nem troco
- Finalização — ATCUD, assinatura digital, observações legais
- Persistência transacional — cabeçalho, linhas, referências, stock, contadores
A movimentação de stock segue a configuração do tipo de documento e do artigo.
Informações técnicas
URL base
| Ambiente | URL base | Documentação |
|---|---|---|
| Produção | https://api.xdsoba.com/gateway | Swagger UI |
Headers de pedido
| Header | Obrigatório | Descrição |
|---|---|---|
Authorization | Sim | Bearer {jwt} |
Content-Type | Sim (POST/PUT) | application/json |
X-Timezone | Recomendado | Fuso IANA (ex.: Europe/Lisbon). Datas persistidas no fuso local configurado. |
Health checks
GET /gateway/invoice/health
Autenticação
POST https://api.xdsoba.com/gateway/auth/combined-login
Content-Type: application/json
{
"tenantKey": "XDPT.30010",
"tenantPassword": "your-tenant-password",
"userKey": "user@example.com",
"userPassword": "your-user-password"
}
Utilize o token em todos os pedidos:
Authorization: Bearer {token}
X-Timezone: Europe/Lisbon
Resolução dos IDs de tipo de documento
O documentTypeId numérico não é portável entre bases de dados de clientes. Obtenha-o com:
GET /gateway/document-type
Authorization: Bearer {token}
Use o id de cada linha como documentTypeId. Escolha a linha cuja description / keyId corresponda ao processo (orçamento, encomenda, fatura, nota de crédito, etc.).
Chame GET /gateway/document-type antes dos testes de integração. Substitua IDs ilustrativos dos guias pelos valores devolvidos por GET /gateway/document-type.
Ver Criar tipos de documento (API Base) se faltar um tipo de documento.
Criar tipos de documento (API Base)
POST /gateway/document-type
Content-Type: application/json
Authorization: Bearer {token}
{
"keyId": "ORC",
"description": "Orçamento",
"documentType": 0,
"invoiceType": "ORC",
"entityType": 0,
"checkingAccountFlow": 0,
"stockFlow": 0,
"stockBehaviour": 0,
"cashierFlow": 0,
"defaultEntityType": 0,
"printSystemType": 0,
"instances": 1,
"isValued": true,
"voucherExpirationDays": 0,
"voucherDeductibleAfter": 0,
"isAdvancement": false,
"forceAskBatches": false,
"defaultAccountId": 0,
"reportLayout": "",
"htmlLayout": ""
}
Endpoints disponíveis
Criar documento
POST /gateway/invoice/invoices
Content-Type: application/json
Authorization: Bearer {token}
X-Timezone: Europe/Lisbon
Cria um documento de venda (natureza definida por documentTypeId).
Atualizar documento
PUT /gateway/invoice/invoices/{id}
Obter documento por ID
GET /gateway/invoice/invoices/{id}
GET /gateway/invoice/invoices/{id}/flat
/flat— formato plano retrocompatível- Sem
/flat— formato completo para impressão
Obter por tipo, série e número
GET /gateway/invoice/invoices/{documentTypeId}/{serieId}/{number}
GET /gateway/invoice/invoices/{documentTypeId}/{serieId}/{number}/flat
Listar documentos
GET /gateway/invoice/invoices?page=1&pageSize=20&status=Open&startDate=2025-01-01&endDate=2025-12-31
Authorization: Bearer {token}
| Parâmetro | Descrição |
|---|---|
page | Número da página (predefinido: 1) |
pageSize | Tamanho da página (predefinido: 20) |
status | Open / Closed |
startDate | Documentos criados a partir desta data |
endDate | Documentos criados até esta data |
entityKeyId | Filtrar por cliente/fornecedor |
documentTypeId | Filtrar por tipo de documento |
sortBy | CreationDate, DocumentNumber, Total, EntityDescription |
sortDescending | Ordem decrescente (predefinido: false) |
Modelo de dados (criar documento)
Campos obrigatórios
{
"serieId": 1,
"documentTypeId": 5,
"currencyId": 1,
"documentBodies": [
{
"itemKeyId": "PROD001",
"quantity": 2,
"retailPrice": 50,
"taxId": 1,
"secondTaxId": 0
}
],
"payments": [
{
"paymentTypeId": 1,
"amount": 123
}
]
}
| Campo | Notas |
|---|---|
currencyId | Obrigatório no contrato API (> 0). A moeda efectiva vem actualmente do terminal/configuração. |
payments | Obrigatório quando o tipo de documento tem fluxo de caixa ou fluxo de conta-corrente activo. Opcional quando nenhum fluxo se aplica — omitir ou fornecer no máximo uma entrada igual ao total do documento. As guias de transporte (GT…GD), encomendas (NE) e orçamentos (ORC) são tipicamente configurados sem nenhum dos fluxos. |
discountPercentage | Desconto de cabeçalho opcional (0–100). Por linha: documentBodies[].discountPercentage. |
Resolução de entidade (cliente)
entityKeyId é opcional. Ao resolver a entidade, a API segue esta ordem:
entityKeyIdfornecido — a entidade é carregada directamente pela chave. Se não for encontrada, o pedido falha imediatamente comEntity.KeyId.NotFound(404). Não é feito qualquer fallback.entityKeyIdomitido,entityVatfornecido — é feita uma pesquisa por NIF. Se for encontrada uma correspondência, essa entidade é utilizada. Se não, é criado um registo temporário com os campos de substituição fornecidos (entityDescription,entityAddress, etc.) e a chave do consumidor final.- Ambos omitidos — o consumidor final por omissão configurado é carregado da base de dados.
Fornecer um entityKeyId inexistente é um erro definitivo (404). O campo entityVat é ignorado nesse caso — corrija ou omita o entityKeyId primeiro.
Campos opcionais comuns
{
"entityDescription": "Cliente Exemplo, Lda",
"entityVat": "PT123456789",
"entityAddress": "Rua Exemplo, 123",
"entityPostalCode": "1000-000",
"entityCity": "Lisboa",
"entityCountry": "Portugal",
"documentDate": "2025-11-28T10:00:00Z",
"dueDate": "2025-12-31",
"paymentModeId": 1,
"obs": "Observações",
"docReference": "2;1;2026-06-05;FAC;;FAC;",
"extraDocReference": "REF-EXTRA",
"emissionReason": "Devolução de mercadoria",
"loadPlaceDescription": "Armazém Central;Lisboa;1000-100;PT",
"unloadPlaceDescription": "Loja Cliente;Porto;4000-000;PT",
"loadPlaceDate": "2025-11-28T10:00:00",
"unloadPlaceDate": "2025-11-28T15:00:00",
"carrierDescription": "Transportadora XYZ",
"taxRegionId": 1,
"numberPersons": 2
}
Campos de local de carga e descarga
| Campo | Descrição |
|---|---|
loadPlaceDescription | Local de origem / carga (máx. 100 chars) |
unloadPlaceDescription | Local de destino / descarga (máx. 100 chars) |
loadPlaceDate | Data e hora de carga (date-time) |
unloadPlaceDate | Data e hora de descarga (date-time) |
carrierDescription | Nome ou descrição do transportador (máx. 100 chars) |
Local de carga (loadPlaceDescription)
Quando omitido, o motor resolve um valor por omissão nesta ordem:
- Valor fornecido pelo caller — utilizado tal como está.
LoadUnloadPlaceassociado ao armazém por defeito do terminal (formato estruturado).- Morada da licença (formato estruturado).
- Nome fiscal / nome comercial da licença como fallback.
Local de descarga (unloadPlaceDescription)
Quando omitido, o motor resolve nesta ordem:
- Valor fornecido pelo caller — utilizado tal como está.
EntityAddressdo cliente marcado comDefaultShipmentAddress = true(formato estruturado).
O formato esperado é "morada;cidade;codigoPostal;pais" — quatro segmentos separados por ponto e vírgula. Quando o campo está presente na requisição, deve seguir este mesmo formato. Quando omitido e resolvido automaticamente pelo motor, os endereços com múltiplas partes são formatados da mesma forma.
Datas
Quando loadPlaceDate ou unloadPlaceDate são omitidos:
| Data | Valor por omissão |
|---|---|
loadPlaceDate | Hora de criação + 15 minutos (ou LoadDateAdditionMinutes quando configurado) |
unloadPlaceDate | Final do dia seguinte às 23:59 |
LoadDateAdditionMinutes é um valor de configuração do sistema (XConfigMisc). Quando não configurado, são usados 15 minutos.
loadPlaceDescription, unloadPlaceDescription e campos de local de carga e descarga são ignorados em faturas simplificadas (FS), notas de crédito (NC) e notas de débito (ND). Não dependa deles nessas naturezas.
Linhas com referência (NC/ND)
Em cada linha referenciada, apenas originBodyGuid, relationType e quantity são obrigatórios. A API deriva itemKeyId, taxId, retailPrice e netPrice da linha de origem quando omitidos:
{
"quantity": 1,
"originBodyGuid": "660e8400-e29b-41d4-a716-446655440001",
"relationType": 1
}
- Obtenha
originBodyGuidviaGET /gateway/invoice/invoices/{documentTypeId}/{serieId}/{number}/flat(campoguidem cada linha). relationType:1= ReferenceOrigin (obrigatório para NC/ND).- Quantidades positivas; a natureza do documento define o sentido crédito/débito.
- Para substituir preços (ex. correcção de valor), forneça
retailPrice/netPriceexplicitamente. Em documentos angolanos, os preços devem corresponder atotalAmount / quantityda origem — consulte os guias dedicados para detalhes.
Para a referência completa de campos, regras de campos derivados e restrições específicas de Angola, consulte o Guia de Notas de Crédito e o Guia de Notas de Débito.
Linhas pai-filho (guid / parentGuid)
Menu e artigo composto são conceitos distintos no catálogo (ver abaixo). Quando envia linhas filho, ambos usam os mesmos campos de ligação no payload:
| Campo | Onde | Descrição |
|---|---|---|
guid | Apenas na linha pai | UUID gerado pelo cliente que identifica a linha pai no pedido |
parentGuid | Linhas filho | Deve ser igual ao guid da linha pai |
Regras comuns:
- Um nível apenas — linhas filho não podem ter filhos.
- Linhas com
parentGuidsão tratadas como informativas e excluídas do total fiscal; o valor de venda fica na linha pai. - Gere um UUID novo para cada linha pai em cada pedido.
Menu
Um menu é um artigo de tipo Menu no catálogo. O cliente ou operador escolhe opções definidas na composição do menu (ex.: entrada, prato principal, acompanhamento). Cada opção seleccionada vai numa linha filho.
O itemKeyId da linha pai deve ser o artigo menu. Os itemKeyId das linhas filho são as opções escolhidas.
Exemplo: Documento com menu.
Artigo composto
Um artigo composto é um artigo de tipo Composite no catálogo — um kit ou produto acabado com componentes definidos no detalhe de composição.
Ao contrário do menu, não é necessário enviar os artigos componentes em documentBodies. Basta uma linha com o itemKeyId do composto — o mesmo formato de um artigo normal (sem guid / parentGuid).
Opcionalmente, pode incluir linhas filho com parentGuid se quiser os componentes listados explicitamente no documento (quantidades e preços seguem a detalhe de composição do artigo).
Exemplo: Documento com artigo composto.
Exemplos de utilização
Fatura simples com pagamento
POST /gateway/invoice/invoices
Content-Type: application/json
Authorization: Bearer {token}
X-Timezone: Europe/Lisbon
{
"serieId": 1,
"documentTypeId": 5,
"entityKeyId": "CLI001",
"currencyId": 1,
"entityDescription": "Cliente Exemplo, Lda",
"entityVat": "PT123456789",
"paymentModeId": 1,
"payments": [
{
"paymentTypeId": 1,
"amount": 123
}
],
"documentBodies": [
{
"itemKeyId": "PROD001",
"itemDescription": "Produto 1",
"quantity": 2,
"retailPrice": 50,
"taxId": 1,
"secondTaxId": 0
}
]
}
A resposta 201 Created inclui documentNumber, total, totalTaxes, change (quando aplicável) e guid.
Multi-pagamento
{
"payments": [
{
"paymentTypeId": 1,
"amount": 50
},
{
"paymentTypeId": 3,
"amount": 73
}
]
}
A soma dos amount deve corresponder ao total entregue. O troco é calculado automaticamente quando o tipo de pagamento o permite.
Documento com menu
Utilize ao vender um artigo menu: linha pai com guid (o menu) e linhas filho com parentGuid (opções seleccionadas). Os itemKeyId, preços e total de pagamento são ilustrativos — obtenha valores reais via API.
POST /gateway/invoice/invoices
Content-Type: application/json
Authorization: Bearer {token}
X-Timezone: Europe/Lisbon
{
"serieId": 1,
"documentTypeId": 1,
"entityKeyId": "1",
"entityVat": "555666777",
"currencyId": 1,
"obs": "Observações do documento.",
"saleZoneAreaObjectId": 1,
"payments": [
{
"paymentTypeId": 1,
"amount": 1140
}
],
"documentBodies": [
{
"guid": "06a646ac-1101-4252-8fd9-20c7173ded78",
"itemKeyId": "353",
"quantity": 1,
"retailPrice": 10,
"taxId": 1
},
{
"parentGuid": "06a646ac-1101-4252-8fd9-20c7173ded78",
"itemKeyId": "366",
"quantity": 1,
"retailPrice": 0,
"taxId": 1
},
{
"parentGuid": "06a646ac-1101-4252-8fd9-20c7173ded78",
"itemKeyId": "354",
"quantity": 1,
"retailPrice": 0,
"taxId": 1
}
]
}
O artigo 353 é o menu; 366 e 354 são as opções seleccionadas. A soma de payments[].amount deve corresponder ao total calculado pela API.
Documento com artigo composto
Utilize ao vender um artigo composto. Envie apenas a linha do composto — os artigos componentes do detalhe de composição não precisam de ir no pedido.
POST /gateway/invoice/invoices
Content-Type: application/json
Authorization: Bearer {token}
X-Timezone: Europe/Lisbon
{
"serieId": 1,
"documentTypeId": 5,
"entityKeyId": "CLI001",
"currencyId": 1,
"payments": [
{
"paymentTypeId": 1,
"amount": 49.9
}
],
"documentBodies": [
{
"itemKeyId": "KIT001",
"quantity": 1,
"retailPrice": 49.9,
"taxId": 1
}
]
}
O artigo KIT001 deve ser de tipo Composite no catálogo. A API resolve os componentes a partir do detalhe de composição do artigo — não envie COMP-A, COMP-B ou semelhantes, excepto se quiser explicitamente linhas filho informativas no documento impresso.
Listar documentos abertos
GET /gateway/invoice/invoices?status=Open&page=1&pageSize=20
Authorization: Bearer {token}
Tratamento de erros
| Código | Quando |
|---|---|
201 Created | Documento criado |
200 OK | Actualização ou consulta com sucesso |
400 Bad Request | Validação falhou |
401 Unauthorized | Token em falta/inválido |
404 Not Found | Documento não encontrado |
409 Conflict | Conflito de concorrência |
500 Internal Server Error | Erro inesperado |
Códigos comuns: DocumentType.NotSupported, Payment.InsufficientValue, SaleDocumentRules.NCND.*, DocumentReferenceBalance.*.
Boas práticas
- Enviar sempre
X-Timezonepara datas locais correctas - Resolver
documentTypeIdcomGET /gateway/document-type— não copiar IDs dos exemplos - Usar
payments[]no cabeçalho nos documentos que exigem pagamento - NC/ND: indicar
emissionReason; referências por GUID nas linhas para origens no Soba (PT/AO) - Menus: enviar opções seleccionadas como linhas filho com
guid/parentGuid— ver exemplo de menu - Artigos compostos: basta uma linha com o
itemKeyIddo composto — ver exemplo de artigo composto
Guias especializados
| Guia | Tópico |
|---|---|
| Orçamentos | ORC |
| Encomendas | NE |
| Faturas | FT, FS |
| Faturas-Recibo | FR |
| Notas de Crédito | NC |
| Notas de Débito | ND |
| Guias de Transporte | GT, GR, GA, GC, GD |
| Recibos | RE (referência — não disponível na API) |
Última actualização: 7 de julho de 2026