Pular para o conteúdo principal

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

NaturezaCódigoGuia dedicado
FaturaFTGuia de Faturas
Fatura simplificadaFSGuia de Faturas
Fatura-reciboFRGuia de Faturas-Recibo
Nota de créditoNCGuia de Notas de Crédito
Nota de débitoNDGuia de Notas de Débito
EncomendaNEGuia de Encomendas
OrçamentoORCGuia de Orçamentos
Guias de transporteGT, GR, GA, GC, GDGuias 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ódigoDescrição
NUNumerário
CCCartão de crédito
CDCartão de débito
OUOutros

Obtenha os identificadores válidos com GET /gateway/payment-types e seleccione registos cujo paymentMechanism corresponda a um dos códigos acima.

Validação

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

Pagamentos de conta-corrente não suportados

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 documentoErro
MoveSetting = CheckingAccount e o tipo de pagamento não lança em conta-correntePayment.CheckingAccountType.RequiredForMoveSetting
Modo de pagamento com IncrementDays > 0 e o tipo não é de conta-correntePayment.CheckingAccountType.RequiredForDeferredMode
CheckingAccountFlow != 0 e o tipo de pagamento não é de conta-correntePayment.CheckingAccountType.RequiredForDocumentFlow
Recibos (RE) não disponíveis na API de Facturação

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:

  1. Validação inicial — natureza suportada, país/licença, mecanismos de pagamento, série, cliente, regras de emissão
  2. Preparação do cabeçalho — resolução de entidade, defaults de transporte, validações fiscais
  3. Cálculos — totais de linha e cabeçalho, impostos, descontos
  4. Pagamentos — multi-pagamento, troco; para tipos com pagamentos opcionais, no máximo uma entrada sem multi-pagamento nem troco
  5. Finalização — ATCUD, assinatura digital, observações legais
  6. Persistência transacional — cabeçalho, linhas, referências, stock, contadores
Movimento de stock

A movimentação de stock segue a configuração do tipo de documento e do artigo.


Informações técnicas

URL base

AmbienteURL baseDocumentação
Produçãohttps://api.xdsoba.com/gatewaySwagger UI

Headers de pedido

HeaderObrigatórioDescrição
AuthorizationSimBearer {jwt}
Content-TypeSim (POST/PUT)application/json
X-TimezoneRecomendadoFuso 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.).

dica

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âmetroDescrição
pageNúmero da página (predefinido: 1)
pageSizeTamanho da página (predefinido: 20)
statusOpen / Closed
startDateDocumentos criados a partir desta data
endDateDocumentos criados até esta data
entityKeyIdFiltrar por cliente/fornecedor
documentTypeIdFiltrar por tipo de documento
sortByCreationDate, DocumentNumber, Total, EntityDescription
sortDescendingOrdem 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
}
]
}
CampoNotas
currencyIdObrigatório no contrato API (> 0). A moeda efectiva vem actualmente do terminal/configuração.
paymentsObrigató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.
discountPercentageDesconto 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:

  1. entityKeyId fornecido — a entidade é carregada directamente pela chave. Se não for encontrada, o pedido falha imediatamente com Entity.KeyId.NotFound (404). Não é feito qualquer fallback.
  2. entityKeyId omitido, entityVat fornecido — é 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.
  3. Ambos omitidos — o consumidor final por omissão configurado é carregado da base de dados.
cuidado

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

CampoDescrição
loadPlaceDescriptionLocal de origem / carga (máx. 100 chars)
unloadPlaceDescriptionLocal de destino / descarga (máx. 100 chars)
loadPlaceDateData e hora de carga (date-time)
unloadPlaceDateData e hora de descarga (date-time)
carrierDescriptionNome 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:

  1. Valor fornecido pelo caller — utilizado tal como está.
  2. LoadUnloadPlace associado ao armazém por defeito do terminal (formato estruturado).
  3. Morada da licença (formato estruturado).
  4. Nome fiscal / nome comercial da licença como fallback.

Local de descarga (unloadPlaceDescription)

Quando omitido, o motor resolve nesta ordem:

  1. Valor fornecido pelo caller — utilizado tal como está.
  2. EntityAddress do cliente marcado com DefaultShipmentAddress = true (formato estruturado).
Formato estruturado de endereço

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:

DataValor por omissão
loadPlaceDateHora de criação + 15 minutos (ou LoadDateAdditionMinutes quando configurado)
unloadPlaceDateFinal do dia seguinte às 23:59

LoadDateAdditionMinutes é um valor de configuração do sistema (XConfigMisc). Quando não configurado, são usados 15 minutos.

Ignorado em FS, NC e ND

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 originBodyGuid via GET /gateway/invoice/invoices/{documentTypeId}/{serieId}/{number}/flat (campo guid em 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 / netPrice explicitamente. Em documentos angolanos, os preços devem corresponder a totalAmount / quantity da 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:

CampoOndeDescrição
guidApenas na linha paiUUID gerado pelo cliente que identifica a linha pai no pedido
parentGuidLinhas filhoDeve ser igual ao guid da linha pai

Regras comuns:

  • Um nível apenas — linhas filho não podem ter filhos.
  • Linhas com parentGuid sã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.

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.

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ódigoQuando
201 CreatedDocumento criado
200 OKActualização ou consulta com sucesso
400 Bad RequestValidação falhou
401 UnauthorizedToken em falta/inválido
404 Not FoundDocumento não encontrado
409 ConflictConflito de concorrência
500 Internal Server ErrorErro inesperado

Códigos comuns: DocumentType.NotSupported, Payment.InsufficientValue, SaleDocumentRules.NCND.*, DocumentReferenceBalance.*.


Boas práticas

  • Enviar sempre X-Timezone para datas locais correctas
  • Resolver documentTypeId com GET /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 itemKeyId do composto — ver exemplo de artigo composto

Guias especializados

GuiaTópico
OrçamentosORC
EncomendasNE
FaturasFT, FS
Faturas-ReciboFR
Notas de CréditoNC
Notas de DébitoND
Guias de TransporteGT, GR, GA, GC, GD
RecibosRE (referência — não disponível na API)

Última actualização: 7 de julho de 2026