API · OpenAPI 3.1 · OAuth2 · webhooks HMAC

Documentação ao vivo. curl · Node · Python.

Da primeira chamada à integração completa. Connect · Score · ERP · Webhooks — todos os endpoints com code examples copy-paste, OpenAPI machine-readable, e reference Node app no GitHub.

Connect — criar sessão

Cria uma sessão Connect para uma SME ligar o ERP. Devolve link_token (para iframe / SDK) e connect_url (para redirecionamento).

POST /v1/connect/sessions P95 <200 ms
# Bank's backend creates a Connect session for an SME
curl -X POST https://sandbox.advanta.pt/v1/connect/sessions \
  -H "Authorization: Bearer $ADVANTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "nif": "509123456",
      "name": "Construções Ibéricas, Lda.",
      "email": "joao@construcoes.pt"
    },
    "branding": "co-branded",
    "scopes": ["invoices:read", "receivables:read"],
    "redirect_url": "https://factoring.banco.pt/connect/done"
  }'
import Advanta from '@advanta/sdk';
const advanta = new Advanta(process.env.ADVANTA_API_KEY);

const session = await advanta.connect.sessions.create({
  customer: {
    nif: '509123456',
    name: 'Construções Ibéricas, Lda.',
    email: 'joao@construcoes.pt',
  },
  branding: 'co-branded',
  scopes: ['invoices:read', 'receivables:read'],
  redirect_url: 'https://factoring.banco.pt/connect/done',
});

// Open session.connect_url in browser, or render <AdvantaConnect> with session.link_token
console.log(session.connect_url);
import os
from advanta import Advanta

advanta = Advanta(api_key=os.environ['ADVANTA_API_KEY'])

session = advanta.connect.sessions.create(
    customer={
        'nif': '509123456',
        'name': 'Construções Ibéricas, Lda.',
        'email': 'joao@construcoes.pt',
    },
    branding='co-branded',
    scopes=['invoices:read', 'receivables:read'],
    redirect_url='https://factoring.banco.pt/connect/done',
)

# Open session.connect_url in browser
print(session.connect_url)

Response 201

{
  "session_id": "cs_2026_xY7p9R8qK2mN4tL3",
  "link_token": "ltk_test_eyJhbGciOiJIUzI1NiIsInR5cCI6...",
  "connect_url": "https://connect.advanta.pt/cs_2026_xY7p9R8qK2mN4tL3",
  "expires_at": "2026-04-26T14:30:00Z",
  "branding": "co-branded",
  "status": "pending"
}

Connect — inspecionar sessão

Verifica o estado de uma sessão. Útil para polling ou debug.

GET /v1/connect/sessions/{session_id}
curl https://sandbox.advanta.pt/v1/connect/sessions/cs_2026_xY7p9R8qK2mN4tL3 \
  -H "Authorization: Bearer $ADVANTA_API_KEY"
const session = await advanta.connect.sessions.get('cs_2026_xY7p9R8qK2mN4tL3');
console.log(session.status); // 'completed' | 'in_progress' | ...
session = advanta.connect.sessions.get('cs_2026_xY7p9R8qK2mN4tL3')
print(session.status)

Score — gerar

Calcula score de risco para uma SME (0-100 + ESG + recommended limit/spread). Aceita connection_id (dados live do ERP) ou nif (último pull cacheado). P95 < 2 s.

POST /v1/score P95 <2 s
curl -X POST https://sandbox.advanta.pt/v1/score \
  -H "Authorization: Bearer $ADVANTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "nif": "509123456",
    "product": "factoring",
    "horizon_days": 90
  }'
const score = await advanta.score.create({
  nif: '509123456',
  product: 'factoring',
  horizon_days: 90,
});

console.log(`Score: ${score.score}/100, Tier ${score.tier}`);
console.log(`Recommended limit: €${score.recommended_limit_eur}, spread ${score.recommended_spread_pct}%`);
score = advanta.score.create(
    nif='509123456',
    product='factoring',
    horizon_days=90,
)

print(f'Score: {score.score}/100, Tier {score.tier}')
print(f'Recommended: €{score.recommended_limit_eur}, spread {score.recommended_spread_pct}%')

Response 200

{
  "score_id": "sc_2026_xY7p9R",
  "score": 78,
  "tier": "A-",
  "esg_score": 71,
  "recommended_limit_eur": 240000,
  "recommended_spread_pct": 1.8,
  "factors": {
    "payment_history": 82,
    "concentration_risk": 65,
    "sector_outlook": 75,
    "sustainability_signals": 71
  },
  "data_freshness": "2026-04-26T03:00:00Z"
}

ERP — listar faturas

Devolve faturas do ERP ligado. Filtros por status, since, paginação por cursor.

GET /v1/erp/{connection_id}/invoices
curl "https://sandbox.advanta.pt/v1/erp/conn_2026_aB3xC9D1fK7p/invoices?status=open&limit=50" \
  -H "Authorization: Bearer $ADVANTA_API_KEY"
const { data, next_cursor } = await advanta.erp.invoices.list({
  connection_id: 'conn_2026_aB3xC9D1fK7p',
  status: 'open',
  limit: 50,
});
invoices = advanta.erp.invoices.list(
    connection_id='conn_2026_aB3xC9D1fK7p',
    status='open',
    limit=50,
)

ERP — trigger SAFT-PT

Força um pull SAFT-PT out-of-band (útil para reconciliação trimestral ou após import manual).

POST /v1/erp/{connection_id}/saft/refresh

ERP — desligar (revoke OAuth)

Revoga o grant OAuth no ERP e elimina os tokens. Operação irreversível — a SME terá de passar pelo Connect de novo se quiser religar.

DELETE /v1/erp/{connection_id}

Webhooks — catálogo

Eventos emitidos pela Advanta. Assinados HMAC-SHA256, retried com exponential backoff (até 7 tentativas, 24 h máximo).

connection.completed · connection.failed · connection.token_expired · invoice.created · invoice.paid · invoice.overdue · score.generated · score.deteriorating

Exemplo: connection.completed

{
  "id": "evt_2026_aB3xC9D1fK7p",
  "type": "connection.completed",
  "created": "2026-04-26T14:12:34Z",
  "data": {
    "connection_id": "conn_2026_aB3xC9D1fK7p",
    "nif": "509123456",
    "company_name": "Construções Ibéricas, Lda.",
    "erp_provider": "primavera",
    "scopes_granted": ["invoices:read", "receivables:read"]
  }
}

Webhooks — verificar assinatura

Cada evento inclui header Advanta-Signature: t=<ts>,v1=<hmac>. Verifiquem antes de processar — protege contra spoofing.

import crypto from 'node:crypto';

function verifyAdvantaWebhook(payload, header, secret) {
  const [t, v1] = header.split(',').map(s => s.split('=')[1]);
  if (Date.now() / 1000 - parseInt(t, 10) > 300) return false;
  const expected = crypto.createHmac('sha256', secret)
    .update(`${t}.${payload}`)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
import hmac, hashlib, time

def verify_advanta_webhook(payload: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split('=') for p in header.split(','))
    t, v1 = parts['t'], parts['v1']
    if time.time() - int(t) > 300: return False
    expected = hmac.new(secret.encode(), f'{t}.'.encode() + payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)