Penny Lens API 接口文档

2025年1月28日
10 分钟阅读
作者:Penny Lens Team

Penny Lens API 接口文档

🎯 概述

Penny Lens API 是基于支付宝小程序云 Serverless 的统一后端接口,为 PC 端和移动端提供完整的数据服务和业务逻辑处理。本文档详细介绍了所有 API 端点的使用方法。

🔧 基础信息

基础URL

https://your-domain.com/api

认证方式

所有需要认证的接口都需要在请求头中包含 JWT Token:

Authorization: Bearer <your-jwt-token>

请求格式

所有请求都使用 JSON 格式:

{
  "action": "service.method",
  "params": {
    // 请求参数
  }
}

响应格式

所有响应都遵循统一格式:

{
  "code": 200,
  "message": "操作成功",
  "data": {
    // 响应数据
  }
}

📊 用户认证接口

1. 用户登录

接口地址: POST /api

请求参数:

{
  "action": "user.login",
  "params": {
    "platform": "email",
    "email": "user@example.com",
    "password": "password123",
    "deviceId": "device123",
    "deviceInfo": "iOS 15.0, iPhone 13"
  }
}

响应示例:

{
  "code": 200,
  "message": "登录成功",
  "data": {
    "id": "61c0c50b6d1b2c001fd2a345",
    "username": "user123",
    "email": "user@example.com",
    "avatar": "https://example.com/avatar.jpg",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "createdAt": 1639149835278,
    "updatedAt": 1642345678901
  }
}

2. 微信登录

请求参数:

{
  "action": "user.login",
  "params": {
    "platform": "wechat",
    "code": "wx_auth_code",
    "deviceId": "device123",
    "deviceInfo": "iOS 15.0, iPhone 13"
  }
}

3. 支付宝登录

请求参数:

{
  "action": "user.login",
  "params": {
    "platform": "alipay",
    "authCode": "alipay_auth_code",
    "deviceId": "device123",
    "deviceInfo": "iOS 15.0, iPhone 13"
  }
}

4. 用户注册

请求参数:

{
  "action": "user.register",
  "params": {
    "username": "newuser",
    "email": "newuser@example.com",
    "password": "password123",
    "deviceId": "device123",
    "deviceInfo": "iOS 15.0, iPhone 13"
  }
}

5. Token 验证

请求参数:

{
  "action": "user.verifyToken",
  "params": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}

6. 用户注销

请求参数:

{
  "action": "user.logout",
  "params": {}
}

💰 资产管理接口

1. 创建资产

请求参数:

{
  "action": "asset.create",
  "params": {
    "name": "招商银行储蓄卡",
    "type": "bankCard",
    "balance": 10000,
    "currency": "CNY",
    "description": "工资卡",
    "icon": "bank-card",
    "isDefault": false
  }
}

响应示例:

{
  "code": 200,
  "message": "创建资产成功",
  "data": {
    "id": "61c0c50b6d1b2c001fd2a345"
  }
}

2. 查询资产列表

请求参数:

{
  "action": "asset.query",
  "params": {
    "type": "bankCard",
    "status": "normal",
    "page": 1,
    "pageSize": 10
  }
}

响应示例:

{
  "code": 200,
  "message": "查询成功",
  "data": {
    "list": [
      {
        "_id": "61c0c50b6d1b2c001fd2a345",
        "name": "招商银行储蓄卡",
        "type": "bankCard",
        "balance": 10000,
        "currency": "CNY",
        "description": "工资卡",
        "status": "normal",
        "icon": "bank-card",
        "isDefault": false,
        "createdAt": 1639149835278,
        "updatedAt": 1639149835278,
        "delFlag": false
      }
    ],
    "total": 1,
    "page": 1,
    "pageSize": 10
  }
}

3. 获取资产详情

请求参数:

{
  "action": "asset.detail",
  "params": {
    "id": "61c0c50b6d1b2c001fd2a345"
  }
}

4. 更新资产

请求参数:

{
  "action": "asset.update",
  "params": {
    "id": "61c0c50b6d1b2c001fd2a345",
    "name": "招商银行储蓄卡(更新)",
    "description": "工资卡和日常消费",
    "isDefault": true
  }
}

5. 删除资产

请求参数:

{
  "action": "asset.delete",
  "params": {
    "id": "61c0c50b6d1b2c001fd2a345"
  }
}

📝 记账管理接口

1. 创建收入记录

请求参数:

{
  "action": "accounting.create",
  "params": {
    "type": "income",
    "amount": 5000,
    "category": "salary",
    "asset": "61c0c50b6d1b2c001fd2a345",
    "description": "工资收入",
    "date": 1642345678901,
    "tags": ["工资", "收入"]
  }
}

2. 创建支出记录

请求参数:

{
  "action": "accounting.create",
  "params": {
    "type": "expense",
    "amount": 100,
    "category": "food",
    "asset": "61c0c50b6d1b2c001fd2a345",
    "description": "午餐",
    "date": 1642345678901,
    "tags": ["餐饮", "日常"]
  }
}

3. 创建转账记录

请求参数:

{
  "action": "accounting.create",
  "params": {
    "type": "transfer",
    "amount": 1000,
    "fromAsset": "61c0c50b6d1b2c001fd2a345",
    "toAsset": "61c0c50b6d1b2c001fd2a346",
    "description": "转账到支付宝",
    "date": 1642345678901,
    "fee": 2
  }
}

4. 查询记账记录

请求参数:

{
  "action": "accounting.query",
  "params": {
    "type": "expense",
    "startDate": 1642345678901,
    "endDate": 1642345678901,
    "category": "food",
    "page": 1,
    "pageSize": 20
  }
}

5. 更新记账记录

请求参数:

{
  "action": "accounting.update",
  "params": {
    "id": "61c0c50b6d1b2c001fd2a347",
    "amount": 120,
    "description": "午餐(更新)",
    "category": "food"
  }
}

6. 删除记账记录

请求参数:

{
  "action": "accounting.delete",
  "params": {
    "id": "61c0c50b6d1b2c001fd2a347"
  }
}

🎯 储蓄游戏接口

1. 创建储蓄目标

请求参数:

{
  "action": "savings.createGoal",
  "params": {
    "title": "旅行基金",
    "description": "存钱去日本旅行",
    "targetAmount": 10000,
    "startDate": 1642345678901,
    "endDate": 1673881678901,
    "category": "vacation",
    "priority": "high",
    "isPublic": true
  }
}

2. 查询储蓄目标

请求参数:

{
  "action": "savings.queryGoals",
  "params": {
    "status": "active",
    "category": "vacation",
    "page": 1,
    "pageSize": 10
  }
}

3. 更新目标进度

请求参数:

{
  "action": "savings.updateProgress",
  "params": {
    "goalId": "61c0c50b6d1b2c001fd2a348",
    "amount": 500
  }
}

4. 虚拟交易 - 买入股票

请求参数:

{
  "action": "savings.buyStock",
  "params": {
    "stockId": "61c0c50b6d1b2c001fd2a349",
    "quantity": 100
  }
}

5. 虚拟交易 - 卖出股票

请求参数:

{
  "action": "savings.sellStock",
  "params": {
    "stockId": "61c0c50b6d1b2c001fd2a349",
    "quantity": 50
  }
}

6. 获取虚拟钱包

请求参数:

{
  "action": "savings.getWallet",
  "params": {}
}

7. 获取持仓信息

请求参数:

{
  "action": "savings.getPositions",
  "params": {}
}

8. 获取成就列表

请求参数:

{
  "action": "savings.getAchievements",
  "params": {
    "category": "savings",
    "completed": false
  }
}

9. 获取排行榜

请求参数:

{
  "action": "savings.getLeaderboard",
  "params": {
    "type": "total_savings",
    "period": "monthly"
  }
}

📊 统计分析接口

1. 收支统计

请求参数:

{
  "action": "stats.getIncomeExpense",
  "params": {
    "startDate": 1642345678901,
    "endDate": 1642345678901,
    "groupBy": "day"
  }
}

响应示例:

{
  "code": 200,
  "message": "查询成功",
  "data": {
    "income": {
      "total": 10000,
      "count": 5,
      "average": 2000,
      "trend": "up"
    },
    "expense": {
      "total": 3000,
      "count": 15,
      "average": 200,
      "trend": "stable"
    },
    "netIncome": 7000,
    "period": {
      "startDate": 1642345678901,
      "endDate": 1642345678901
    }
  }
}

2. 分类统计

请求参数:

{
  "action": "stats.getCategoryStats",
  "params": {
    "type": "expense",
    "startDate": 1642345678901,
    "endDate": 1642345678901,
    "limit": 10
  }
}

3. 资产统计

请求参数:

{
  "action": "stats.getAssetStats",
  "params": {}
}

4. 趋势分析

请求参数:

{
  "action": "stats.getTrend",
  "params": {
    "type": "income",
    "startDate": 1642345678901,
    "endDate": 1642345678901,
    "groupBy": "week"
  }
}

📁 文件管理接口

1. 上传文件

请求参数:

{
  "action": "file.upload",
  "params": {
    "fileName": "receipt.jpg",
    "fileType": "image/jpeg",
    "fileSize": 1024000,
    "category": "receipt"
  }
}

响应示例:

{
  "code": 200,
  "message": "上传成功",
  "data": {
    "fileId": "61c0c50b6d1b2c001fd2a350",
    "url": "https://oss.example.com/files/receipt.jpg",
    "uploadUrl": "https://oss.example.com/upload/receipt.jpg"
  }
}

2. 查询文件列表

请求参数:

{
  "action": "file.query",
  "params": {
    "category": "receipt",
    "page": 1,
    "pageSize": 20
  }
}

3. 删除文件

请求参数:

{
  "action": "file.delete",
  "params": {
    "fileId": "61c0c50b6d1b2c001fd2a350"
  }
}

🔗 短链接接口

1. 创建短链接

请求参数:

{
  "action": "shortlink.create",
  "params": {
    "url": "https://example.com/very-long-url",
    "title": "示例链接",
    "description": "这是一个示例链接",
    "expireAt": 1673881678901,
    "isPublic": true
  }
}

2. 查询短链接

请求参数:

{
  "action": "shortlink.query",
  "params": {
    "code": "abc123"
  }
}

3. 更新短链接

请求参数:

{
  "action": "shortlink.update",
  "params": {
    "id": "61c0c50b6d1b2c001fd2a351",
    "title": "更新后的标题",
    "description": "更新后的描述"
  }
}

4. 删除短链接

请求参数:

{
  "action": "shortlink.delete",
  "params": {
    "id": "61c0c50b6d1b2c001fd2a351"
  }
}

❌ 错误码说明

通用错误码

错误码错误类型错误消息处理建议
200Success操作成功-
400ValidationException参数验证失败检查输入参数是否正确
401UnauthorizedException未授权访问请先登录获取有效Token
403ForbiddenException权限不足检查用户权限
404NotFoundException资源不存在确认资源ID是否正确
409ConflictException资源冲突检查资源状态
429RateLimitException请求频率过高请稍后重试
500InternalServerException服务器内部错误稍后重试或联系管理员
502BadGatewayException网关错误稍后重试
503ServiceUnavailableException服务不可用稍后重试

业务错误码

错误码错误类型错误消息处理建议
1001UserNotFound用户不存在确认用户是否已注册
1002InvalidCredentials用户名或密码错误检查登录凭据
1003TokenExpiredToken已过期重新登录获取新Token
1004AccountLocked账号已锁定联系管理员解锁
2001AssetNotFound资产不存在确认资产ID是否正确
2002InsufficientBalance余额不足检查资产余额
2003InvalidAssetType无效的资产类型使用正确的资产类型
3001RecordNotFound记录不存在确认记录ID是否正确
3002InvalidRecordType无效的记录类型使用正确的记录类型
3003InvalidAmount无效的金额检查金额是否为正数
4001GoalNotFound目标不存在确认目标ID是否正确
4002GoalCompleted目标已完成目标已完成,无法修改
4003InsufficientFunds资金不足检查虚拟钱包余额
5001FileNotFound文件不存在确认文件ID是否正确
5002FileTooLarge文件过大使用较小的文件
5003InvalidFileType无效的文件类型使用支持的文件类型

🔧 使用示例

JavaScript/TypeScript 示例

// API 客户端类
class PennyLensAPI {
  private baseURL: string;
  private token: string | null = null;
 
  constructor(baseURL: string) {
    this.baseURL = baseURL;
  }
 
  // 设置认证Token
  setToken(token: string) {
    this.token = token;
  }
 
  // 发送请求
  async request(action: string, params: any = {}) {
    const response = await fetch(`${this.baseURL}/api`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...(this.token && { 'Authorization': `Bearer ${this.token}` })
      },
      body: JSON.stringify({ action, params })
    });
 
    const data = await response.json();
    
    if (data.code !== 200) {
      throw new Error(data.message);
    }
 
    return data.data;
  }
 
  // 用户登录
  async login(platform: string, credentials: any) {
    return this.request('user.login', { platform, ...credentials });
  }
 
  // 创建资产
  async createAsset(assetData: any) {
    return this.request('asset.create', assetData);
  }
 
  // 查询资产列表
  async getAssets(params: any = {}) {
    return this.request('asset.query', params);
  }
 
  // 创建记账记录
  async createRecord(recordData: any) {
    return this.request('accounting.create', recordData);
  }
 
  // 查询记账记录
  async getRecords(params: any = {}) {
    return this.request('accounting.query', params);
  }
}
 
// 使用示例
const api = new PennyLensAPI('https://your-domain.com');
 
// 用户登录
try {
  const loginResult = await api.login('email', {
    email: 'user@example.com',
    password: 'password123',
    deviceId: 'device123',
    deviceInfo: 'iOS 15.0, iPhone 13'
  });
  
  api.setToken(loginResult.token);
  console.log('登录成功:', loginResult);
} catch (error) {
  console.error('登录失败:', error.message);
}
 
// 创建资产
try {
  const asset = await api.createAsset({
    name: '招商银行储蓄卡',
    type: 'bankCard',
    balance: 10000,
    currency: 'CNY',
    description: '工资卡'
  });
  console.log('创建资产成功:', asset);
} catch (error) {
  console.error('创建资产失败:', error.message);
}
 
// 创建支出记录
try {
  const record = await api.createRecord({
    type: 'expense',
    amount: 100,
    category: 'food',
    asset: 'asset-id',
    description: '午餐',
    date: Date.now()
  });
  console.log('创建记录成功:', record);
} catch (error) {
  console.error('创建记录失败:', error.message);
}

Python 示例

import requests
import json
 
class PennyLensAPI:
    def __init__(self, base_url):
        self.base_url = base_url
        self.token = None
 
    def set_token(self, token):
        self.token = token
 
    def request(self, action, params=None):
        if params is None:
            params = {}
        
        headers = {
            'Content-Type': 'application/json'
        }
        
        if self.token:
            headers['Authorization'] = f'Bearer {self.token}'
        
        response = requests.post(
            f'{self.base_url}/api',
            headers=headers,
            data=json.dumps({'action': action, 'params': params})
        )
        
        data = response.json()
        
        if data['code'] != 200:
            raise Exception(data['message'])
        
        return data['data']
 
    def login(self, platform, **credentials):
        return self.request('user.login', {'platform': platform, **credentials})
 
    def create_asset(self, asset_data):
        return self.request('asset.create', asset_data)
 
    def get_assets(self, params=None):
        if params is None:
            params = {}
        return self.request('asset.query', params)
 
    def create_record(self, record_data):
        return self.request('accounting.create', record_data)
 
    def get_records(self, params=None):
        if params is None:
            params = {}
        return self.request('accounting.query', params)
 
# 使用示例
api = PennyLensAPI('https://your-domain.com')
 
# 用户登录
try:
    login_result = api.login('email', 
        email='user@example.com',
        password='password123',
        deviceId='device123',
        deviceInfo='iOS 15.0, iPhone 13'
    )
    
    api.set_token(login_result['token'])
    print('登录成功:', login_result)
except Exception as e:
    print('登录失败:', str(e))
 
# 创建资产
try:
    asset = api.create_asset({
        'name': '招商银行储蓄卡',
        'type': 'bankCard',
        'balance': 10000,
        'currency': 'CNY',
        'description': '工资卡'
    })
    print('创建资产成功:', asset)
except Exception as e:
    print('创建资产失败:', str(e))

📚 最佳实践

1. 错误处理

  • 始终检查响应状态码
  • 实现重试机制处理网络错误
  • 提供用户友好的错误提示
  • 记录错误日志便于调试

2. 性能优化

  • 使用分页查询避免一次性加载大量数据
  • 实现本地缓存减少重复请求
  • 使用批量操作提高效率
  • 合理设置请求超时时间

3. 安全考虑

  • 妥善保管API Token
  • 使用HTTPS传输敏感数据
  • 验证所有输入参数
  • 定期更新Token

4. 开发建议

  • 使用TypeScript获得更好的类型安全
  • 实现统一的错误处理机制
  • 编写单元测试确保接口稳定性
  • 使用API文档工具生成文档

Penny Lens API - 让后端集成更简单、更可靠 🚀