---
name: moloni-api
description: Referência da API Moloni v2 para facturação portuguesa — autenticação, documentos, clientes e produtos.
---

# Moloni API v2

Operações de facturação portuguesa via Moloni API. MCP server disponível em `/opt/moloni/`.

## 4 Regras Críticas

1. **`access_token` na QUERY STRING** - Nunca no POST body (causa 403)
2. **Endpoints camelCase** - `creditNotes/`, `invoiceReceipts/`, `documentSets/`
3. **Arrays form-encoded** - `payments[0][payment_method_id]`, nunca `json.dumps()`
4. **`net_value` = Total COM IVA** - Nome enganador! Desk `total` = Moloni `net_value`. Base = `net_value / 1.23`

## Autenticação

```python
# Grant = GET (não POST!)
r = requests.get('https://api.moloni.pt/v2/grant/', params={
    'grant_type': 'password',
    'client_id': 'evidentedespertar',
    'client_secret': 'aa48e86bd574bf81ca2d7f624c8b5de0284fb97d',
    'username': 'contabilidade@descomplicar.pt',
    'password': '6EMVh^RHA)d5k!%s'  # %s literal, sem f-string!
})
token = r.json()['access_token']
```

## Empresa

| Campo | Valor |
|-------|-------|
| Company ID | 69473 |
| Série D | document_set_id: 630300 |
| Transf. Bancária | payment_method_id: 400878 |

## Formato Chamadas

```python
# CORRECTO
r = requests.post('https://api.moloni.pt/v2/invoices/getAll/',
    params={'access_token': token},            # token aqui!
    data={'company_id': '69473', 'qty': '50'}  # dados aqui
)
```

## Workflows Comuns

### Listar facturas
```python
data = {'company_id': '69473', 'document_set_id': '630300', 'qty': '50', 'offset': '0'}
```

### Criar recibo
```python
data = {
    'company_id': '69473',
    'date': '2026-02-05',
    'document_set_id': '630300',
    'customer_id': str(customer_id),
    'net_value': str(valor),
    'associated_documents[0][associated_id]': str(invoice_document_id),
    'associated_documents[0][value]': str(valor),
    'payments[0][payment_method_id]': '400878',
    'payments[0][date]': '2026-02-05',
    'payments[0][value]': str(valor),
    'status': '1'
}
r = requests.post('.../receipts/insert/', params={'access_token': token}, data=data)
```

### Verificar reconciliação
Antes de criar recibo, verificar `reconciled_value` e `reverse_associated_documents` da factura.

## Restrições

- Data mínima documentos: **>= 2025-10-28** (período AT)
- Para facturas antigas: usar data actual no recibo

## Erros Comuns

| Erro | Causa | Solução |
|------|-------|---------|
| 403 Forbidden | Token no body | Mover para `params=` |
| 404 Not Found | Case errado ou sem `/` | Verificar camelCase + trailing slash |
| `["12 date >= ..."]` | Data antiga | Usar data actual |
| `["10 associated_id"]` | Factura já reconciliada | Verificar `reconciled_value` |

## MCP vs API Directa

O MCP Moloni (`mcp__moloni__*`) gere tokens automaticamente. Para operações pontuais ou scripts batch, usar API directa via SSH no mcp-hub.

## Sandbox (Desenvolvimento)

Para testes sem afectar dados reais: https://www.moloni.pt/dev/sandbox/

A sandbox fornece um ambiente isolado com dados fictícios para desenvolvimento e testes de integração.

## Referências

- **[references/api-reference.md](references/api-reference.md)** - Credenciais, formatos, mapeamento clientes, erros
- **[references/endpoints.md](references/endpoints.md)** - Catálogo completo de endpoints
- **Docs oficiais:** https://www.moloni.pt/dev/endpoints/
- **Sandbox:** https://www.moloni.pt/dev/sandbox/

---

## Healing Log

Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.

```jsonl
{"date":"","issue":"","fix":"","source":"user|auto"}
```

*Adicionar nova linha após cada erro corrigido.*
