Documentação
Portal do Cliente

Emitir Documento

POST /v2/documentos/emitir

Envia documentos fiscais para validação na AGT. Um mesmo endpoint trata todos os tipos de documentos: facturas, facturas/recibo, notas de crédito, notas de débito, recibos e mais.

Porquê usar este endpoint? Este é o endpoint principal do gateway. Após criares as séries necessárias, usas este endpoint para submeter cada documento fiscal. A AGT aceita o documento imediatamente e devolve um requestIdAGT. A validação final é diferida — deves consultar o resultado posteriormente via status.


Request

Autenticação

Authorization: Bearer feak_...

ou

x-api-key: feak_...

Scope necessário: facturas:emitir ou *

Body (JSON)

Estrutura geral

CampoTipoObrigatórioDescrição
nifstring✅ SimNIF do contribuinte emissor
privateKeystring✅ SimChave privada RSA do contribuinte em PEM
companyNamestring✅ SimNome/denominação do contribuinte emissor
idempotencyKeystringNãoChave única para evitar duplicados
documentosarray✅ SimLista de documentos (mín 1, máx 30)

Objecto documentos[]

CampoTipoObrigatórioDescrição
numerostring✅ SimNº único do documento (ex: "FT FT3926S9043N/1")
tipostring✅ SimTipo: FT, FR, NC, ND, RC, RG, etc.
datastring✅ SimData de emissão no formato YYYY-MM-DD
clienteobject✅ SimDados do cliente
cliente.nomestring✅ SimNome do cliente
cliente.nifstring✅ SimNIF do cliente ("999999999" para consumidor final)
cliente.paisstringNãoCódigo ISO do país (default: "AO")
itensarray⚠️Linhas do documento. Não usar para RC/RG/AR
reciboDearray⚠️Docs de origem do recibo. Apenas para RC/RG/AR
totaisobjectNãoTotais do documento (calculados automaticamente se omitido)
totais.totalnumberTotal com imposto
totais.subtotalnumberNãoTotal sem imposto
totais.totalImpostosnumberNãoTotal de imposto
eacCodestringNãoCódigo CAE (5 caracteres)

Objecto itens[] — Linhas do documento

CampoTipoObrigatórioDescrição
codigostring✅ SimCódigo do produto/serviço
descricaostring✅ SimDescrição do produto/serviço
quantidadenumber✅ SimQuantidade (inteiro ou decimal)
unidadestring✅ SimUnidade de medida (ex: "UN", "KG", "H")
precoUnitarionumber✅ SimPreço unitário sem imposto
taxanumberNãoPercentagem de IVA (default: 14). Usa 0 para isento
motivoIsencaostringNãoCódigo de isenção quando taxa: 0 (ex: "M00")
descontonumberNãoValor do desconto na linha (default: 0)
isServicobooleanNãotrue = serviço, false = bem (default)
operationTypestringNãoOverride do tipo de operação AGT
retencaoTipostringNãoTipo de retenção: "IRT", "II", "IS", "IVA"
retencaoTaxanumberNãoPercentagem de retenção (ex: 6.5 para 6.5%)
referenciaobject⚠️Documento origem. Obrigatório para NC e ND
referencia.documentostringNº do documento origem (ex: "FT FT3926S9043N/1")
referencia.motivostringNãoMotivo da rectificação

Objecto reciboDe[] — Apenas para RC/RG/AR

CampoTipoObrigatórioDescrição
documentostring✅ SimNº do documento a regularizar
dataDocumentostringNãoData do documento origem (YYYY-MM-DD)
valornumber✅ SimValor a regularizar (sem imposto)

Response

Sucesso (200 OK)

{
  "success": true,
  "requestIdAGT": "202600002471491",
  "dataEnvio": "2026-07-25T18:50:30.257Z",
  "documentos": [
    { "numero": "FT FT3926S9043N/1", "tipo": "FT" }
  ]
}

Campos da Resposta

CampoTipoDescrição
successbooleantrue — documento submetido à AGT
requestIdAGTstringID da AGT para consultar o estado depois
dataEnviostringTimestamp ISO 8601 do envio
documentosarrayLista de documentos submetidos

⚠️ Importante: A AGT faz validação diferida. O success: true significa apenas que o documento foi aceite para processamento. Para saber se foi validado ou rejeitado, usa o status com o requestIdAGT.


Exemplos de Payloads

Factura Simples (FT)

{
  "nif": "5000537039",
  "privateKey": "-----BEGIN PRIVATE KEY-----\n...",
  "companyName": "SONHE TESTE",
  "documentos": [{
    "numero": "FT FT3926S9043N/1",
    "tipo": "FT",
    "data": "2026-07-25",
    "cliente": { "nome": "Cliente Exemplo", "nif": "999999999", "pais": "AO" },
    "itens": [{
      "codigo": "PROD001",
      "descricao": "Produto de exemplo",
      "quantidade": 2,
      "unidade": "UN",
      "precoUnitario": 5000,
      "taxa": 14
    }]
  }]
}

Factura com Retenção na Fonte (FT + IRT)

{
  "nif": "5000537039",
  "privateKey": "-----BEGIN PRIVATE KEY-----\n...",
  "companyName": "SONHE TESTE",
  "documentos": [{
    "numero": "FT FT3926S9043N/2",
    "tipo": "FT",
    "data": "2026-07-25",
    "cliente": { "nome": "Cliente Serviço", "nif": "999999999", "pais": "AO" },
    "itens": [{
      "codigo": "CONS001",
      "descricao": "Serviço de Consultoria",
      "quantidade": 1,
      "unidade": "UN",
      "precoUnitario": 100000,
      "taxa": 14,
      "isServico": true,
      "retencaoTipo": "IRT",
      "retencaoTaxa": 6.5
    }]
  }]
}

Nota de Crédito (NC) — Referência a documento origem

{
  "nif": "5000537039",
  "privateKey": "-----BEGIN PRIVATE KEY-----\n...",
  "companyName": "SONHE TESTE",
  "documentos": [{
    "numero": "NC NC3926S7016N/1",
    "tipo": "NC",
    "data": "2026-07-25",
    "cliente": { "nome": "Cliente Devolução", "nif": "999999999", "pais": "AO" },
    "itens": [{
      "codigo": "PROD001",
      "descricao": "Devolução de produto com defeito",
      "quantidade": 1,
      "unidade": "UN",
      "precoUnitario": 5000,
      "taxa": 14,
      "referencia": {
        "documento": "FT FT3926S9043N/1",
        "motivo": "Produto com defeito"
      }
    }]
  }]
}

Recibo (RC) — Sem linhas, com referência a documentos pagos

{
  "nif": "5000537039",
  "privateKey": "-----BEGIN PRIVATE KEY-----\n...",
  "companyName": "SONHE TESTE",
  "documentos": [{
    "numero": "RC RC3926S2186N/1",
    "tipo": "RC",
    "data": "2026-07-25",
    "cliente": { "nome": "Cliente Pagamento", "nif": "999999999", "pais": "AO" },
    "reciboDe": [{
      "documento": "FT FT3926S9043N/1",
      "dataDocumento": "2026-07-25",
      "valor": 10000
    }]
  }]
}

Lote / Batch (múltiplos documentos)

{
  "nif": "5000537039",
  "privateKey": "-----BEGIN PRIVATE KEY-----\n...",
  "companyName": "SONHE TESTE",
  "documentos": [
    {
      "numero": "FT FT3926S9043N/3",
      "tipo": "FT",
      "data": "2026-07-25",
      "cliente": { "nome": "Cliente A", "nif": "999999999", "pais": "AO" },
      "itens": [{ "codigo": "A001", "descricao": "Produto A", "quantidade": 1, "unidade": "UN", "precoUnitario": 3000, "taxa": 14 }]
    },
    {
      "numero": "FR FR3926S6237N/1",
      "tipo": "FR",
      "data": "2026-07-25",
      "cliente": { "nome": "Cliente B", "nif": "999999999", "pais": "AO" },
      "itens": [{ "codigo": "B001", "descricao": "Produto B", "quantidade": 2, "unidade": "UN", "precoUnitario": 1500, "taxa": 14 }]
    }
  ]
}

Erros

Erros de Autenticação

HTTPcodeMensagemCausa
401UNAUTHORIZEDNao autorizado.API Key não foi enviada
401UNAUTHORIZEDAPI Key invalida.API Key não existe ou foi revogada
403FORBIDDENScope insuficiente.A key não tem o scope facturas:emitir

Erros de Validação

HTTPcodeMensagemCausa
400INVALID_JSONBody JSON invalido.Corpo do request não é JSON válido
400VALIDATION_ERRORPayload invalido. Verifique a documentacao.Campos obrigatórios em falta ou inválidos
400VALIDATION_ERRORInvalid option: expected one of “FT”|“FR”|…tipo de documento inválido

Erros da AGT

HTTPcodeMensagemCausa
502AGT_ERRORsecretOrPrivateKey must be an asymmetric key…Chave privada inválida ou corrompida
502AGT_ERRORErro de comunicacao com a AGTServiço AGT indisponível

⚠️ Documento duplicado: A AGT aceita documentos com o mesmo número no momento do registo (HTTP 200). A rejeição por duplicado só aparece na validação diferida, ao consultar o status.


Exemplos de Código

TypeScript / Node.js

const API_KEY = "feak_bfc76ba48c0c286c9ce4bb2fcd7e178a399e329c59e529776bb5e01b0bfe8712";
const GATEWAY_URL = "https://connect.factflexi.com";

interface EmitirResultado {
  success: boolean;
  requestIdAGT: string;
  dataEnvio: string;
  documentos: { numero: string; tipo: string }[];
}

async function emitirDocumento(payload: object): Promise<EmitirResultado> {
  const response = await fetch(`${GATEWAY_URL}/v2/documentos/emitir`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY,
    },
    body: JSON.stringify(payload),
  });

  const data = await response.json();
  if (!data.success) throw new Error(`${data.code}: ${data.error}`);
  return data;
}

// Uso — emitir uma factura simples
const resultado = await emitirDocumento({
  nif: "5000537039",
  privateKey: "-----BEGIN PRIVATE KEY-----\n...",
  companyName: "SONHE TESTE",
  documentos: [{
    numero: "FT FT3926S9043N/1",
    tipo: "FT",
    data: "2026-07-25",
    cliente: { nome: "Cliente", nif: "999999999", pais: "AO" },
    itens: [{
      codigo: "PROD001", descricao: "Produto",
      quantidade: 2, unidade: "UN", precoUnitario: 5000, taxa: 14,
    }],
  }],
});

console.log(`Documento submetido. requestIdAGT: ${resultado.requestIdAGT}`);

Python

import requests

API_KEY = "feak_bfc76ba48c0c286c9ce4bb2fcd7e178a399e329c59e529776bb5e01b0bfe8712"
GATEWAY_URL = "https://connect.factflexi.com"

def emitir_documento(payload: dict) -> dict:
    response = requests.post(
        f"{GATEWAY_URL}/v2/documentos/emitir",
        json=payload,
        headers={
            "Content-Type": "application/json",
            "x-api-key": API_KEY,
        },
    )
    data = response.json()
    if not data.get("success"):
        raise Exception(f"{data.get('code')}: {data.get('error')}")
    return data

# Uso — emitir factura com retenção
resultado = emitir_documento({
    "nif": "5000537039",
    "privateKey": "-----BEGIN PRIVATE KEY-----\n...",
    "companyName": "SONHE TESTE",
    "documentos": [{
        "numero": "FT FT3926S9043N/3",
        "tipo": "FT",
        "data": "2026-07-25",
        "cliente": {"nome": "Cliente", "nif": "999999999", "pais": "AO"},
        "itens": [{
            "codigo": "CONS001", "descricao": "Consultoria",
            "quantidade": 1, "unidade": "UN", "precoUnitario": 100000,
            "taxa": 14, "isServico": True,
            "retencaoTipo": "IRT", "retencaoTaxa": 6.5,
        }],
    }],
})

print(f"Submetido. requestIdAGT: {resultado['requestIdAGT']}")

PHP

<?php
define('API_KEY', 'feak_bfc76ba48c0c286c9ce4bb2fcd7e178a399e329c59e529776bb5e01b0bfe8712');
define('GATEWAY_URL', 'https://connect.factflexi.com');

function emitirDocumento(array $payload): array {
    $ch = curl_init(GATEWAY_URL . '/v2/documentos/emitir');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'x-api-key: ' . API_KEY,
        ],
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_RETURNTRANSFER => true,
    ]);

    $response = curl_exec($ch);
    curl_close($ch);
    $data = json_decode($response, true);

    if (!$data['success']) {
        throw new Exception("{$data['code']}: {$data['error']}");
    }
    return $data;
}

// Uso
$resultado = emitirDocumento([
    'nif' => '5000537039',
    'privateKey' => "-----BEGIN PRIVATE KEY-----\n...",
    'companyName' => 'SONHE TESTE',
    'documentos' => [[
        'numero' => 'FT FT3926S9043N/5',
        'tipo' => 'FT',
        'data' => '2026-07-25',
        'cliente' => ['nome' => 'Cliente', 'nif' => '999999999', 'pais' => 'AO'],
        'itens' => [[
            'codigo' => 'PROD001', 'descricao' => 'Produto',
            'quantidade' => 2, 'unidade' => 'UN',
            'precoUnitario' => 5000, 'taxa' => 14,
        ]],
    ]],
]);

echo "Submetido. requestIdAGT: {$resultado['requestIdAGT']}\n";

Regras por Tipo de Documento

TipoitensreciboDereferenciaNotas
FT Factura✅ ObrigatórioDocumento fiscal normal
FR Factura/Recibo✅ ObrigatórioFactura que também serve de recibo
NC Nota de Crédito✅ Obrigatório✅ ObrigatórioDevolução/desconto — referenciar doc origem
ND Nota de Débito✅ ObrigatórioOpcionalCorreção de valor a maior
RC Recibo✅ ObrigatórioRecibo de pagamento
RG Recibo Geral✅ ObrigatórioOutros recibos
AR Aviso Cobrança/Recibo✅ ObrigatórioAviso + recibo