Listar Séries
POST /v2/series Obtém todas as séries de numeração registadas na AGT para um determinado contribuinte. Cada série define um intervalo de documentos fiscais que podem ser emitidos.
Porquê usar este endpoint? Antes de emitir documentos, precisas de saber que séries estão disponíveis. O código da série (ex: FT3926S9043N) é usado depois no endpoint de emitir documento para compor o número do documento (FT FT3926S9043N/1).
Request
Autenticação
Inclui a tua API Key num destes headers:
Authorization: Bearer feak_... ou
x-api-key: feak_... Scope necessário: series:listar ou *
Body (JSON)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
nif | string | ✅ Sim | NIF do contribuinte (ex: "5000537039") |
privateKey | string | ✅ Sim | Chave privada RSA do contribuinte em formato PEM |
Response
Sucesso (200 OK)
{
"success": true,
"total": 2283,
"series": [
{
"codigo": "FT3926S9043N",
"ano": "2026",
"tipoDocumento": "FT",
"estado": "activa",
"dataCriacao": "2026-07-25T11:44:25.500512",
"primeiroDocumento": "1",
"nif": "5000537039",
"nome": "SONHE TESTE"
}
]
} Campos da Resposta
| Campo | Tipo | Descrição |
|---|---|---|
success | boolean | true — pedido processado com sucesso |
total | number | Número total de séries encontradas |
series | array | Lista de séries de numeração |
series[].codigo | string | Código único da série (ex: FT3926S9043N) |
series[].ano | string | Ano de emissão da série |
series[].tipoDocumento | string | Tipo de documento: FT, FR, NC, ND, RC, etc. |
series[].estado | string | "activa" — a série está disponível para emissão |
series[].dataCriacao | string | Data/hora de criação da série (ISO 8601) |
series[].primeiroDocumento | string | Número do primeiro documento da série |
series[].nif | string | NIF do contribuinte proprietário |
series[].nome | string | Nome do contribuinte |
Contribuinte sem séries
Se o NIF não tiver séries registadas, a resposta é um array vazio:
{
"success": true,
"total": 0,
"series": []
} Erros
Erros de Autenticação
| HTTP | code | Mensagem | Causa |
|---|---|---|---|
| 401 | UNAUTHORIZED | Nao autorizado. | API Key não foi enviada |
| 401 | UNAUTHORIZED | API Key invalida. | API Key não existe ou foi revogada |
| 403 | FORBIDDEN | Scope insuficiente. | A key não tem o scope series:listar |
Erros de Validação
| HTTP | code | Mensagem | Causa |
|---|---|---|---|
| 400 | INVALID_JSON | Body JSON invalido. | O corpo do request não é JSON válido |
| 400 | VALIDATION_ERROR | Payload invalido. Campos obrigatorios: nif, privateKey. | Falta nif ou privateKey |
| 400 | VALIDATION_ERROR | Too small: expected string to have >=1 characters | nif ou privateKey vazios |
Erros da AGT
| HTTP | code | Mensagem | Causa |
|---|---|---|---|
| 502 | AGT_ERROR | secretOrPrivateKey must be an asymmetric key when using RS256 | Chave privada inválida ou corrompida |
| 502 | AGT_ERROR | Erro de comunicacao com a AGT | Serviço AGT indisponível |
Exemplos de Código
TypeScript / Node.js
const API_KEY = "feak_bfc76ba48c0c286c9ce4bb2fcd7e178a399e329c59e529776bb5e01b0bfe8712";
const GATEWAY_URL = "https://connect.factflexi.com";
async function listarSeries(nif: string, privateKey: string) {
const response = await fetch(`${GATEWAY_URL}/v2/series`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY,
},
body: JSON.stringify({ nif, privateKey }),
});
const data = await response.json();
if (!data.success) {
throw new Error(`${data.code}: ${data.error}`);
}
console.log(`Encontradas ${data.total} séries para NIF ${nif}`);
for (const s of data.series) {
console.log(` ${s.codigo} — ${s.tipoDocumento} ${s.ano} — ${s.estado}`);
}
return data.series;
}
// Uso
const series = await listarSeries("5000537039", `-----BEGIN PRIVATE KEY-----\n...`); Python
import requests
API_KEY = "feak_bfc76ba48c0c286c9ce4bb2fcd7e178a399e329c59e529776bb5e01b0bfe8712"
GATEWAY_URL = "https://connect.factflexi.com"
def listar_series(nif: str, private_key: str):
response = requests.post(
f"{GATEWAY_URL}/v2/series",
json={"nif": nif, "privateKey": private_key},
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')}")
print(f"Encontradas {data['total']} séries para NIF {nif}")
for s in data["series"]:
print(f" {s['codigo']} — {s['tipoDocumento']} {s['ano']} — {s['estado']}")
return data["series"]
# Uso
series = listar_series("5000537039", "-----BEGIN PRIVATE KEY-----\n...") PHP
<?php
define('API_KEY', 'feak_bfc76ba48c0c286c9ce4bb2fcd7e178a399e329c59e529776bb5e01b0bfe8712');
define('GATEWAY_URL', 'https://connect.factflexi.com');
function listarSeries(string $nif, string $privateKey): array {
$ch = curl_init(GATEWAY_URL . '/v2/series');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: ' . API_KEY,
],
CURLOPT_POSTFIELDS => json_encode([
'nif' => $nif,
'privateKey' => $privateKey,
]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true);
if (!$data['success']) {
throw new Exception("{$data['code']}: {$data['error']}");
}
echo "Encontradas {$data['total']} séries para NIF {$nif}\n";
foreach ($data['series'] as $s) {
echo " {$s['codigo']} — {$s['tipoDocumento']} {$s['ano']} — {$s['estado']}\n";
}
return $data['series'];
}
// Uso
$series = listarSeries('5000537039', "-----BEGIN PRIVATE KEY-----\n..."); Tipos de Documento
| Código | Nome | Código | Nome |
|---|---|---|---|
FT | Factura | NC | Nota de Crédito |
FR | Factura/Recibo | ND | Nota de Débito |
FA | Factura de Adiantamento | RC | Recibo Emitido |
FG | Factura Global | RG | Recibo Geral |
GF | Factura Genérica | AR | Aviso de Cobrança/Recibo |