{"openapi":"3.1.0","info":{"title":"DS Facto API","version":"1.0.0","description":"Disponível em todos os planos. Limite de 120 pedidos/minuto por chave. Valores em AOA. Idempotency-Key obrigatório nas emissões e recibos. O modo de teste gera documentos sem validade fiscal; produção exige validação externa."},"servers":[{"url":"https://dsfacto.com/api/v1"}],"security":[{"ApiKey":[]}],"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","description":"Chave ds_ apresentada apenas na criação."}},"schemas":{"Customer":{"type":"object","additionalProperties":false,"properties":{"nome":{"type":"string","minLength":2,"maxLength":255},"nif":{"type":"string","minLength":8,"maxLength":20,"pattern":"^[A-Za-z0-9]+$"},"email":{"type":"string","format":"email"},"telefone":{"type":"string","maxLength":50},"morada":{"type":"string","maxLength":1000}},"required":["nome","nif"]},"Line":{"type":"object","additionalProperties":false,"properties":{"artigoId":{"type":"string","format":"uuid"},"descricao":{"type":"string","minLength":1,"maxLength":1000},"quantidade":{"type":"number","exclusiveMinimum":0},"precoUnitario":{"type":"number","minimum":0},"taxaIva":{"type":"number","enum":[0,5,7,14]},"desconto":{"type":"number","minimum":0,"maximum":100},"motivoIsencao":{"type":"string"},"tipo":{"type":"string","enum":["produto","servico"],"description":"Necessário para aplicar retenção apenas aos serviços quando não é enviado artigoId."},"unidade":{"type":"string","maxLength":30},"codigo":{"type":"string","maxLength":50}},"required":["descricao","quantidade","precoUnitario","taxaIva"]},"Invoice":{"type":"object","additionalProperties":false,"properties":{"tipo":{"type":"string","enum":["FT","FR","FP","GT","NC","ND","RC","AF","FG"]},"clienteId":{"type":"string"},"serieId":{"type":"string","format":"uuid"},"serie":{"type":"string","maxLength":20,"description":"Nome de uma série existente, quando serieId é omitido."},"estabelecimentoId":{"type":"string","format":"uuid"},"armazemId":{"type":"string","format":"uuid"},"dataEmissao":{"type":"string","format":"date"},"dataVencimento":{"type":"string","format":"date"},"referenciaId":{"type":"string","format":"uuid"},"motivo":{"type":"string"},"clienteManual":{"type":"object","properties":{"nome":{"type":"string"},"nif":{"type":"string"},"morada":{"type":"string"}},"required":["nome","nif"]},"aplicarRetencao":{"type":"boolean","default":false},"retencaoTaxa":{"type":"number","minimum":0,"maximum":100,"description":"0 desactiva; 6.5 aplica retenção aos serviços. Outras taxas exigem Profissional."},"tipoRetencao":{"type":"string","enum":["II","IRT","IS","IVA","IP","IAC","OU"]},"fundamentoRetencao":{"type":"string","maxLength":1000,"description":"Obrigatório quando há retenção."},"meioPagamento":{"type":"string","description":"Obrigatório na factura-recibo (FR)."},"observacoes":{"type":"string","maxLength":5000},"rascunho":{"type":"boolean","default":false},"devolverStock":{"type":"boolean","default":false,"description":"Indica devolução de stock quando aplicável à correcção."},"transporte":{"type":"object","properties":{"matricula":{"type":"string"},"localCarga":{"type":"string"},"localDescarga":{"type":"string"},"inicio":{"type":"string","format":"date-time"}},"required":["matricula","localCarga","localDescarga","inicio"],"description":"Obrigatório para emitir uma guia de transporte (GT)."},"moeda":{"type":"string","enum":["AOA","USD","EUR","GBP","ZAR","MZN"],"default":"AOA"},"taxaCambio":{"type":"number","exclusiveMinimum":0,"description":"AOA por unidade de divisa. Os preços das linhas e o livro permanecem em AOA."},"fonteCambio":{"type":"string","minLength":10},"autofacturacao":{"type":"object","properties":{"cadastroConfirmado":{"const":true},"evidencia":{"type":"string","minLength":20}},"required":["cadastroConfirmado","evidencia"]},"origensGlobais":{"type":"array","maxItems":200,"items":{"type":"string","format":"uuid"},"description":"Guias de transporte da mesma empresa, cliente e estabelecimento. As linhas são reconstruídas no servidor."},"alocacoes":{"type":"array","items":{"type":"object","properties":{"facturaId":{"type":"string","format":"uuid"},"montante":{"type":"number","exclusiveMinimum":0}},"required":["facturaId","montante"]}},"linhas":{"type":"array","maxItems":500,"description":"Obrigatórias nas emissões normais. Na factura global, são obtidas das guias. No recibo, são geradas a partir das alocações.","items":{"$ref":"#/components/schemas/Line"}}},"required":["clienteId"]}}},"paths":{"/customers":{"get":{"summary":"Listar clientes","description":"Consulte os clientes da empresa. Use search para pesquisar pelo nome.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"start","in":"query","schema":{"type":"string","format":"date"}},{"name":"end","in":"query","schema":{"type":"string","format":"date"}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Parte do nome do cliente ou da descrição do artigo."}],"responses":{"200":{"description":"Pedido concluído. Listas: data,total,page,pageSize. Consulta individual: data. PDF: application/pdf. OpenAPI: especificação JSON.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}},"post":{"summary":"Criar cliente","description":"Registe um cliente para emitir documentos em seu nome. O nome e o NIF são obrigatórios.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"responses":{"201":{"description":"Registo criado ou emissão idempotente devolvida em data.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}},"/products":{"get":{"summary":"Listar artigos e serviços","description":"Consulte o catálogo. Use search para pesquisar pela descrição.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"start","in":"query","schema":{"type":"string","format":"date"}},{"name":"end","in":"query","schema":{"type":"string","format":"date"}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Parte do nome do cliente ou da descrição do artigo."}],"responses":{"200":{"description":"Pedido concluído. Listas: data,total,page,pageSize. Consulta individual: data. PDF: application/pdf. OpenAPI: especificação JSON.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}},"post":{"summary":"Criar artigo ou serviço","description":"Registe código, descrição, preço, IVA e tipo. Neste pedido, os nomes compostos usam sublinhado: preco_unitario, taxa_iva e motivo_isencao.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"codigo":{"type":"string"},"descricao":{"type":"string"},"preco_unitario":{"type":"number"},"taxa_iva":{"type":"number"},"tipo":{"type":"string","enum":["produto","servico"]},"unidade":{"type":"string"},"motivo_isencao":{"type":["string","null"],"description":"Motivo de isenção quando a taxa de IVA é 0."},"stock_inicial":{"type":"number","minimum":0,"default":0},"armazem_id":{"type":"string","format":"uuid"}},"required":["codigo","descricao","preco_unitario","taxa_iva","tipo"]}}}},"responses":{"201":{"description":"Registo criado ou emissão idempotente devolvida em data.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}},"/invoices":{"get":{"summary":"Listar documentos","description":"Liste os documentos de facturação, incluindo recibos. Pode filtrar por datas, cliente, tipo, estado, série, operador e estabelecimento.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"start","in":"query","schema":{"type":"string","format":"date"}},{"name":"end","in":"query","schema":{"type":"string","format":"date"}},{"name":"clienteId","in":"query","schema":{"type":"string"}},{"name":"tipo","in":"query","schema":{"type":"string"}},{"name":"estado","in":"query","schema":{"type":"string"}},{"name":"serieId","in":"query","schema":{"type":"string"}},{"name":"operadorId","in":"query","schema":{"type":"string"}},{"name":"estabelecimentoId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Pedido concluído. Listas: data,total,page,pageSize. Consulta individual: data. PDF: application/pdf. OpenAPI: especificação JSON.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}},"post":{"summary":"Emitir documento","description":"Emita facturas e os outros documentos indicados nas regras fiscais abaixo. A numeração, o IVA e os totais são calculados pelo sistema. Envie Idempotency-Key.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":150}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}}},"responses":{"201":{"description":"Registo criado ou emissão idempotente devolvida em data.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}},"/invoices/{id}":{"get":{"summary":"Consultar documento","description":"Consulte um documento pelo seu identificador. Inclui as linhas e, quando existirem, referências a outros documentos e alocações de recibos.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pedido concluído. Listas: data,total,page,pageSize. Consulta individual: data. PDF: application/pdf. OpenAPI: especificação JSON.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}},"/invoices/{id}/pdf":{"get":{"summary":"Descarregar PDF","description":"Obtenha o ficheiro do documento. A resposta é um PDF, não um objecto JSON.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pedido concluído. Listas: data,total,page,pageSize. Consulta individual: data. PDF: application/pdf. OpenAPI: especificação JSON.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}},"/receipts":{"post":{"summary":"Emitir recibo","description":"Registe a liquidação total ou parcial de uma ou mais facturas do mesmo cliente. Envie as alocações e Idempotency-Key; não envie linhas nem totais calculados.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":150}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clienteId":{"type":"string","format":"uuid"},"estabelecimentoId":{"type":"string","format":"uuid"},"serieId":{"type":"string","format":"uuid"},"meioPagamento":{"type":"string"},"alocacoes":{"type":"array","minItems":1,"items":{"type":"object","properties":{"facturaId":{"type":"string","format":"uuid"},"montante":{"type":"number","exclusiveMinimum":0}},"required":["facturaId","montante"]}}},"required":["clienteId","alocacoes"]}}}},"responses":{"201":{"description":"Registo criado ou emissão idempotente devolvida em data.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}},"/stock":{"get":{"summary":"Consultar stock","description":"Consulte as quantidades dos artigos por armazém. A resposta inclui a identificação do artigo e do armazém. Não existe operação de escrita de stock nesta API v1.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"start","in":"query","schema":{"type":"string","format":"date"}},{"name":"end","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Pedido concluído. Listas: data,total,page,pageSize. Consulta individual: data. PDF: application/pdf. OpenAPI: especificação JSON.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}},"required":["data"]}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}},"/openapi":{"get":{"summary":"Consultar especificação","description":"Obtenha a descrição OpenAPI 3.1 em JSON com uma chave válida. A mesma especificação também pode ser descarregada publicamente nesta documentação.","parameters":[],"responses":{"200":{"description":"Pedido concluído. Listas: data,total,page,pageSize. Consulta individual: data. PDF: application/pdf. OpenAPI: especificação JSON.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Dados inválidos ou regra de negócio violada."},"401":{"description":"Chave inválida ou expirada."},"403":{"description":"Plano, permissão ou empresa não autorizados."},"404":{"description":"Documento ou endereço não encontrado."},"405":{"description":"Método não permitido."},"409":{"description":"Conflito de idempotência ou série ocupada."},"415":{"description":"Envie o corpo como application/json."},"429":{"description":"Limite de pedidos atingido; consulte Retry-After."},"500":{"description":"Não foi possível concluir a operação. Consulte o suporte."},"503":{"description":"Serviço temporariamente indisponível."}}}}}}