Safira Paydocs
Guías de Integración

Consulta de Saldo

Descripción General

El endpoint de consulta de saldo le permite obtener información detallada sobre el saldo de la cuenta autenticada en tiempo real. La respuesta incluye tres tipos de saldo:

  • Saldo Bruto: Monto total disponible en la cuenta
  • Saldo Bloqueado: Montos reservados para operaciones pendientes
  • Saldo Neto: Monto disponible para uso inmediato

Este endpoint requiere un Bearer token válido. Consulte la documentación de autenticación para más detalles.

Endpoint

GET /api/balance

Retorna el saldo actual de la cuenta autenticada.

Encabezados Requeridos

Authorization: Bearer {token}

Solicitud

curl -X GET https://api.safirapay.com/api/balance \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Respuesta (200 OK)

{
  "grossBalance": 48734.90,
  "blockedBalance": 0.00,
  "netBalance": 48734.90,
  "consultedAt": "2025-11-19T20:18:29.384Z"
}

Estructura de la Respuesta

grossBalancenumbersempre presente

Saldo bruto total de la cuenta (saldo neto + saldo bloqueado)

Ejemplo: 48734.90

blockedBalancenumbersempre presente

Monto bloqueado por operaciones pendientes (pagos en proceso, cobros esperando confirmación)

Ejemplo: 0.00

netBalancenumbersempre presente

Saldo neto disponible para uso inmediato (grossBalance - blockedBalance)

Ejemplo: 48734.90

consultedAtstringsempre presente

Fecha y hora de la consulta en formato ISO 8601 (UTC)

Ejemplo: 2025-11-19T20:18:29.384Z

Ejemplos de Implementación

Node.js / TypeScript

import axios from 'axios';

interface BalanceResponse {
  grossBalance: number;
  blockedBalance: number;
  netBalance: number;
  consultedAt: string;
}

async function getBalance(token: string): Promise<BalanceResponse> {
  try {
    const response = await axios.get<BalanceResponse>(
      'https://api.safirapay.com/api/balance',
      {
        headers: {
          'Authorization': `Bearer ${token}`
        }
      }
    );

    console.log('=== Account Balance ===');
    console.log(`Gross Balance: R$ ${response.data.grossBalance.toFixed(2)}`);
    console.log(`Blocked Balance: R$ ${response.data.blockedBalance.toFixed(2)}`);
    console.log(`Net Balance: R$ ${response.data.netBalance.toFixed(2)}`);
    console.log(`Queried at: ${new Date(response.data.consultedAt).toLocaleString('pt-BR')}`);

    return response.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.error('Error querying balance:', error.response?.data);
      throw new Error(error.response?.data?.message || 'Error querying balance');
    }
    throw error;
  }
}

// Usage
const token = 'your_token_here';
getBalance(token);

Python

import requests
from datetime import datetime
from typing import Dict

def get_balance(token: str) -> Dict:
    """
    Query the account balance

    Args:
        token: Valid Bearer token

    Returns:
        Dictionary with balance information
    """
    url = 'https://api.safirapay.com/api/balance'
    headers = {
        'Authorization': f'Bearer {token}'
    }

    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()

        data = response.json()

        print('=== Account Balance ===')
        print(f"Gross Balance: R$ {data['grossBalance']:.2f}")
        print(f"Blocked Balance: R$ {data['blockedBalance']:.2f}")
        print(f"Net Balance: R$ {data['netBalance']:.2f}")

        consulted_at = datetime.fromisoformat(data['consultedAt'].replace('Z', '+00:00'))
        print(f"Queried at: {consulted_at.strftime('%d/%m/%Y %H:%M:%S')}")

        return data

    except requests.exceptions.RequestException as e:
        print(f'Error querying balance: {e}')
        if hasattr(e.response, 'json'):
            print(f'Details: {e.response.json()}')
        raise

# Usage
token = 'your_token_here'
balance = get_balance(token)

PHP

<?php

function getBalance(string $token): array
{
    $url = 'https://api.safirapay.com/api/balance';

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $token
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 200) {
        throw new Exception("Error querying balance: HTTP $httpCode");
    }

    $data = json_decode($response, true);

    echo "=== Account Balance ===" . PHP_EOL;
    echo "Gross Balance: R$ " . number_format($data['grossBalance'], 2, ',', '.') . PHP_EOL;
    echo "Blocked Balance: R$ " . number_format($data['blockedBalance'], 2, ',', '.') . PHP_EOL;
    echo "Net Balance: R$ " . number_format($data['netBalance'], 2, ',', '.') . PHP_EOL;
    echo "Queried at: " . date('d/m/Y H:i:s', strtotime($data['consultedAt'])) . PHP_EOL;

    return $data;
}

// Usage
$token = 'your_token_here';
$balance = getBalance($token);

Casos de Uso

1. Dashboard de Gestión Financiera

Muestre el saldo en tiempo real en un panel administrativo:

// Update balance every 30 seconds
setInterval(async () => {
  const balance = await getBalance(token);

  // Update UI
  document.getElementById('gross-balance').textContent =
    `R$ ${balance.grossBalance.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}`;

  document.getElementById('net-balance').textContent =
    `R$ ${balance.netBalance.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}`;

  // Low balance alert
  if (balance.netBalance < 1000) {
    showLowBalanceAlert();
  }
}, 30000);

2. Validación Previa al Pago

Verifique que haya saldo suficiente antes de realizar un pago:

async function processPayment(amount: number, token: string) {
  // Query current balance
  const balance = await getBalance(token);

  // Validate available balance
  if (balance.netBalance < amount) {
    throw new Error(
      `Insufficient balance. Available: R$ ${balance.netBalance.toFixed(2)} | ` +
      `Required: R$ ${amount.toFixed(2)}`
    );
  }

  // Proceed with payment
  return await createPixPayment(amount, token);
}

3. Reporte de Conciliación

Genere reportes de conciliación con el saldo actual:

def generate_reconciliation_report(token: str):
    """Generate reconciliation report"""
    balance = get_balance(token)

    report = {
        'report_date': datetime.now().isoformat(),
        'balance_snapshot': balance,
        'status': 'OK' if balance['netBalance'] > 0 else 'ALERT',
        'blocked_percentage': (
            balance['blockedBalance'] / balance['grossBalance'] * 100
            if balance['grossBalance'] > 0 else 0
        )
    }

    # Save report
    with open(f"reconciliation_{datetime.now().strftime('%Y%m%d')}.json", 'w') as f:
        json.dump(report, f, indent=2)

    return report

Entendiendo el Saldo Bloqueado

El saldo bloqueado representa montos temporalmente no disponibles debido a:

Códigos de Respuesta

CódigoDescripciónSignificado
200ÉxitoSaldo consultado exitosamente
401Token InválidoToken no proporcionado, expirado o inválido

Consulte la Referencia de la API para detalles completos de los campos de respuesta.

Consideraciones

El saldo retornado refleja el estado en el momento exacto de la consulta. Para operaciones críticas, siempre consulte el saldo inmediatamente antes de la transacción.

  • Caché: No recomendamos almacenar en caché el saldo por más de 1 minuto
  • Precisión: Los valores se retornan con 2 decimales
  • Moneda: Todos los valores están en Reales brasileños (BRL)

Monitoreo y Alertas

Implementando Alertas de Saldo

class BalanceMonitor {
  constructor(token, thresholds) {
    this.token = token;
    this.thresholds = {
      critical: thresholds.critical || 500,
      warning: thresholds.warning || 2000,
      high: thresholds.high || 10000
    };
  }

  async checkAndAlert() {
    const balance = await getBalance(this.token);
    const netBalance = balance.netBalance;

    if (netBalance < this.thresholds.critical) {
      this.sendAlert('CRITICAL', `Critical balance: R$ ${netBalance.toFixed(2)}`);
    } else if (netBalance < this.thresholds.warning) {
      this.sendAlert('WARNING', `Low balance: R$ ${netBalance.toFixed(2)}`);
    }

    // High blocked balance alert
    const blockedPercentage = (balance.blockedBalance / balance.grossBalance) * 100;
    if (blockedPercentage > 50) {
      this.sendAlert('WARNING', `${blockedPercentage.toFixed(1)}% of balance is blocked`);
    }

    return balance;
  }

  sendAlert(level, message) {
    console.log(`[${level}] ${message}`);
    // Integrate with alerting system (email, SMS, Slack, etc.)
  }
}

// Usage
const monitor = new BalanceMonitor(token, {
  critical: 1000,
  warning: 5000
});

// Run every 5 minutes
setInterval(() => monitor.checkAndAlert(), 5 * 60 * 1000);

Próximos Pasos

En esta página