docs
集成指南

余额查询

概述

余额查询端点允许您实时获取已认证账户余额的详细信息。响应包含三种类型的余额:

  • 总余额(Gross Balance):账户总金额(可用 + 冻结)
  • 冻结余额(Blocked Balance):为待处理操作预留的金额
  • 可用余额(Net Balance):可立即使用的金额

此端点需要有效的 Bearer token。详情请参阅认证文档。

端点

GET /api/balance

返回已认证账户的当前余额。

必需请求头

Authorization: Bearer {token}

请求

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

响应 (200 OK)

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

响应结构

grossBalancenumbersempre presente

账户总余额(可用余额 + 冻结余额)

示例: 48734.90

blockedBalancenumbersempre presente

存在于账户中但不可用的金额:正在处理的 PIX 付款、预防性冻结(例如因 MED)以及待扣除的冲正或手续费(grossBalance - netBalance)

示例: 0.00

netBalancenumbersempre presente

可立即使用的可用余额(grossBalance - blockedBalance)

示例: 48734.90

consultedAtstringsempre presente

查询的日期和时间,ISO 8601 格式(UTC)

示例: 2025-11-19T20:18:29.384Z

实现示例

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.fypay.me/api/balance',
      {
        headers: {
          'Authorization': `Bearer ${token}`
        }
      }
    );

    console.log('=== 账户余额 ===');
    console.log(`总余额:R$ ${response.data.grossBalance.toFixed(2)}`);
    console.log(`冻结余额:R$ ${response.data.blockedBalance.toFixed(2)}`);
    console.log(`可用余额:R$ ${response.data.netBalance.toFixed(2)}`);
    console.log(`查询时间:${new Date(response.data.consultedAt).toLocaleString('pt-BR')}`);

    return response.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.error('查询余额出错:', error.response?.data);
      throw new Error(error.response?.data?.message || '查询余额出错');
    }
    throw error;
  }
}

// 用法
const token = 'your_token_here';
getBalance(token);

Python

import requests
from datetime import datetime
from typing import Dict

def get_balance(token: str) -> Dict:
    """
    查询账户余额

    Args:
        token: 有效的 Bearer token

    Returns:
        包含余额信息的字典
    """
    url = 'https://api.fypay.me/api/balance'
    headers = {
        'Authorization': f'Bearer {token}'
    }

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

        data = response.json()

        print('=== 账户余额 ===')
        print(f"总余额:R$ {data['grossBalance']:.2f}")
        print(f"冻结余额:R$ {data['blockedBalance']:.2f}")
        print(f"可用余额:R$ {data['netBalance']:.2f}")

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

        return data

    except requests.exceptions.RequestException as e:
        print(f'查询余额出错:{e}')
        if hasattr(e.response, 'json'):
            print(f'详情:{e.response.json()}')
        raise

# 用法
token = 'your_token_here'
balance = get_balance(token)

PHP

<?php

function getBalance(string $token): array
{
    $url = 'https://api.fypay.me/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("查询余额出错:HTTP $httpCode");
    }

    $data = json_decode($response, true);

    echo "=== 账户余额 ===" . PHP_EOL;
    echo "总余额:R$ " . number_format($data['grossBalance'], 2, ',', '.') . PHP_EOL;
    echo "冻结余额:R$ " . number_format($data['blockedBalance'], 2, ',', '.') . PHP_EOL;
    echo "可用余额:R$ " . number_format($data['netBalance'], 2, ',', '.') . PHP_EOL;
    echo "查询时间:" . date('d/m/Y H:i:s', strtotime($data['consultedAt'])) . PHP_EOL;

    return $data;
}

// 用法
$token = 'your_token_here';
$balance = getBalance($token);

使用场景

1. 财务管理仪表板

在管理仪表板中实时显示余额:

// 每 30 秒更新一次余额
setInterval(async () => {
  const balance = await getBalance(token);

  // 更新 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 })}`;

  // 低余额告警
  if (balance.netBalance < 1000) {
    showLowBalanceAlert();
  }
}, 30000);

2. 付款前验证

在执行付款前检查余额是否充足:

async function processPayment(amount: number, token: string) {
  // 查询当前余额
  const balance = await getBalance(token);

  // 验证可用余额
  if (balance.netBalance < amount) {
    throw new Error(
      `余额不足。可用:R$ ${balance.netBalance.toFixed(2)} | ` +
      `所需:R$ ${amount.toFixed(2)}`
    );
  }

  // 继续付款
  return await createPixPayment(amount, token);
}

3. 对账报告

使用当前余额生成对账报告:

import json

def generate_reconciliation_report(token: str):
    """生成对账报告"""
    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
        )
    }

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

    return report

理解冻结余额

冻结余额 表示因以下原因暂时不可用的金额:

响应状态码

状态码描述含义
200成功余额查询成功
401无效 TokenToken 未提供、已过期或无效

请参阅 API 参考 获取响应字段的完整详情。

注意事项

返回的余额反映的是查询那一刻的状态。对于关键操作,请始终在交易前立即查询余额。

  • 缓存: 不建议缓存余额超过 1 分钟
  • 精度: 数值以 2 位小数返回
  • 货币: 所有金额均以巴西雷亚尔(BRL)计

监控和告警

实现余额告警

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', `余额严重不足:R$ ${netBalance.toFixed(2)}`);
    } else if (netBalance < this.thresholds.warning) {
      this.sendAlert('WARNING', `余额偏低:R$ ${netBalance.toFixed(2)}`);
    }

    // 冻结余额过高告警
    const blockedPercentage = (balance.blockedBalance / balance.grossBalance) * 100;
    if (blockedPercentage > 50) {
      this.sendAlert('WARNING', `${blockedPercentage.toFixed(1)}% 的余额已被冻结`);
    }

    return balance;
  }

  sendAlert(level, message) {
    console.log(`[${level}] ${message}`);
    // 与告警系统集成(邮件、短信、Slack 等)
  }
}

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

// 每 5 分钟执行一次
setInterval(() => monitor.checkAndAlert(), 5 * 60 * 1000);

后续步骤

本页目录