Nordlet

← Documentacao / Guias

Convenções da API

Estrutura de pedidos, âmbitos de autenticação, consultas de listagem, valores monetários, erros, idempotência e limites de caudal.

Estrutura de pedidos

Todas as operações são do tipo RPC através de POST:

POST /v1/{module}/{resource}/{action}

Módulos: reference, partners, catalog, sales, purchases, ledger, bank, declarations, files, webhooks, audit. As ações são verbos: create, get, update, delete, list, além de ações de domínio como issue, register, match, apply-advance, generate.

Autenticação e âmbitos (scopes)

Authorization: Bearer <api key>. As chaves contêm âmbitos validados por ação:

  • {module}:read - ações de obtenção e listagem (get/list)
  • {module}:write - operações de alteração (mutations)
  • {module}:* ou * - carateres universal (wildcards)

Ámbito em falta → 403 forbidden. Chave em falta ou inválida → 401 unauthorized.

Consultas de listagem

Todas as ações list partilham o mesmo contrato:

{
  "page": 1,
  "pageSize": 50,
  "sort": [{ "field": "createdAt", "dir": "desc" }],
  "filter": [{ "field": "paymentStatus", "op": "eq", "value": "unpaid" }]
}

Operadores de filtro: eq (igual), ne (diferente), contains (correspondência de texto insensível a maiúsculas/minúsculas, apenas para campos de texto), gte (maior ou igual que), lte (menor ou igual que), in (qualquer valor de uma lista até 500 elementos). Os campos ordenáveis e filtráveis estão definidos numa lista branca por ponto de final endpoint (consulte a especificação OpenAPI); os campos desconhecidos devolvem o código 400. Adicione totals: ["field", …] ao pedido para somar campos numéricos em todas as linhas correspondentes; quando os registos contêm uma moeda, totalsByCurrency apresenta essas mesmas somas divididas por código de moeda. Respostas: { rows, total, page, pageSize, totals?, totalsByCurrency? }.

Valores monetários e datas

Os valores monetários são strings decimais com um máximo de 4 casas decimais ("121.0000") - nunca números de vírgula flutuante (floats). O IVA é calculado linha a linha com arredondamento comercial (meio para cima, ou half-up). As datas seguem o formato YYYY-MM-DD; os carateres de fecho temporal (timestamps) utilizam o formato ISO 8601 em UTC.

Erros

Existe um únicoinvólucro (envelope) para todas as respostas de erro:

{
  "error": {
    "code": "validation",
    "message": "Request validation failed",
    "requestId": "k1x…",
    "key": "request_invalid",
    "fieldErrors": { "lines.0.unitPriceExclVat": ["Invalid value"] }
  }
}

Códigos: validation (400/422, e 413 se um ficheiro carregado ou o corpo do pedido forem demasiado grandes), unauthorized (401), payment_required (402, o período de avaliação ou o crédito pré-pago terminaram; a mensagem indica como proceder), forbidden (403), not_found (404), conflict (409), idempotency_key_reuse (422), idempotency_in_progress (409), rate_limited (429), internal (5xx). Quando a mensagem corresponde a uma mensagem fixa, o campo key identifica-a para que o cliente possa apresentar a sua própria tradução, enquanto o campo params contém os respetivos valores (por exemplo, { "period": "2026-09" } para um período contabilístico encerrado). Inclua o requestId ao comunicar problemas.

Idempotência

Adicione Idempotency-Key: <qualquer string com ≤255 carateres> a qualquer operação de modificação:

  • Repetir com a mesma chave e a mesma carga útil (payload) → a resposta armazenada é reproduzida byte a byte com o cabeçalho x-idempotent-replay: true.
  • Mesma chave, carga útil diferente → 422 idempotency_key_reuse.
  • Pedido duplicado simultâneo enquanto o primeiro ainda está a ser processado → 409 idempotency_in_progress.
  • As chaves pertencem à chave de API ou ao utilizador que as envia, dentro da empresa em cujo nome a chamada é efetuada, permitindo que duas integrações da mesma empresa utilizem a mesma chave. As chamadas efetuadas antes de a empresa existir e as chamadas account/* mantêm as chaves por utilizador, pelo que uma chamada repetida a account/companies/create cria apenas uma empresa.
  • Uma resposta armazenada só é devolvida depois de o chamador passar novamente pelas mesmas validações de permissões (ámbitos, função, empresa e estado de faturação); caso contrário, a chamada obtém o erro atual.
  • As chaves expiram após 24 horas. As respostas de erro (4xx) também são reproduzidas; as respostas 5xx não são armazenadas, pelo que as tentativas são executadas novamente.

Limites de caudal (rate limits)

300 pedidos por minuto por chave de API (por credencial apresentada; os pedidos não autenticados têm limites aplicados por IP). Em caso de erro 429, respeite o cabeçalho retry-after. Os cabeçalhos x-ratelimit-* indicam o seu orçamento disponível.

Webhooks

Os eventos são gravados numa tabela de transações (transactional outbox) na mesma transação de base de dados da alteração - um documento revertido nunca emite um evento e nenhum evento é perdido. Entregas:

  • Um pedido POST para o seu URL com o JSON do evento
  • x-nordlet-timestamp: <segundos unix>, o momento em que a entrega foi assinada
  • x-nordlet-signature-v2: t=<timestamp>,v1=<hex HMAC-SHA256 de "<timestamp>.<raw body>"> utilizando o seu segredo de subscrição
  • x-nordlet-signature: sha256=<hex HMAC-SHA256 of the raw body>, mantido inalterado para recetores existentes
  • x-nordlet-delivery contém o identificador da entrega, que se mantém igual em todas as tentativas de uma mesma entrega
  • Uma resposta sem o código 2xx ou um redirecionamento motivam uma nova tentativa após 30 segundos, 2 minutos, 10 minutos, 30 minutos, 1 hora, 3 horas, 6 horas e 12 horas, num total aproximado de 24 horas, antes de a entrega ser marcada como falhada
  • Cada entrega é enviada por um único servidor de cada vez, pelo que a execução de várias instâncias da API não resulta em envios duplicados

Valide o cabeçalho x-nordlet-signature-v2 utilizando uma comparação de tempo constante antes de confiar na carga útil (payload) e rejeite entregas cuja marca temporal difira do seu relógio em mais de 5 minutos. A marca temporal faz parte do texto assinado, impedindo que uma entrega intercetada seja reutilizada mais tarde com uma nova marca temporal. Armazene os identificadores x-nordlet-delivery já processados para ignorar repetições dentro dessa janela temporal. Uma entrega falhada pode ser reenviada através de webhooks/deliveries/redeliver.

Auditoria

Todas as alterações são registadas (actor, action, entity, diff) e podem ser consultadas através de audit/list.

Garantias contabilísticas

  • Os lançamentos em diário são sempre equilibrados - isto é garantido por um gatilho (trigger) diferido na base de dados no momento da gravação, e não apenas pelo código da aplicação.
  • A numeração de documentos é contínua e sem saltos por série/ano; a atribuição é segura face à concorrência.
  • Os períodos contabilísticos bloqueados rejeitam qualquer lançamento com data no seu interior (código 409).
  • Os documentos eliminados logicamente (soft-deleted) mantêm o respetivo rasto de auditoria; os documentos emitidos ou registados não podem ser eliminados.