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"
}
}❌ 错误码说明
通用错误码
| 错误码 | 错误类型 | 错误消息 | 处理建议 |
|---|---|---|---|
| 200 | Success | 操作成功 | - |
| 400 | ValidationException | 参数验证失败 | 检查输入参数是否正确 |
| 401 | UnauthorizedException | 未授权访问 | 请先登录获取有效Token |
| 403 | ForbiddenException | 权限不足 | 检查用户权限 |
| 404 | NotFoundException | 资源不存在 | 确认资源ID是否正确 |
| 409 | ConflictException | 资源冲突 | 检查资源状态 |
| 429 | RateLimitException | 请求频率过高 | 请稍后重试 |
| 500 | InternalServerException | 服务器内部错误 | 稍后重试或联系管理员 |
| 502 | BadGatewayException | 网关错误 | 稍后重试 |
| 503 | ServiceUnavailableException | 服务不可用 | 稍后重试 |
业务错误码
| 错误码 | 错误类型 | 错误消息 | 处理建议 |
|---|---|---|---|
| 1001 | UserNotFound | 用户不存在 | 确认用户是否已注册 |
| 1002 | InvalidCredentials | 用户名或密码错误 | 检查登录凭据 |
| 1003 | TokenExpired | Token已过期 | 重新登录获取新Token |
| 1004 | AccountLocked | 账号已锁定 | 联系管理员解锁 |
| 2001 | AssetNotFound | 资产不存在 | 确认资产ID是否正确 |
| 2002 | InsufficientBalance | 余额不足 | 检查资产余额 |
| 2003 | InvalidAssetType | 无效的资产类型 | 使用正确的资产类型 |
| 3001 | RecordNotFound | 记录不存在 | 确认记录ID是否正确 |
| 3002 | InvalidRecordType | 无效的记录类型 | 使用正确的记录类型 |
| 3003 | InvalidAmount | 无效的金额 | 检查金额是否为正数 |
| 4001 | GoalNotFound | 目标不存在 | 确认目标ID是否正确 |
| 4002 | GoalCompleted | 目标已完成 | 目标已完成,无法修改 |
| 4003 | InsufficientFunds | 资金不足 | 检查虚拟钱包余额 |
| 5001 | FileNotFound | 文件不存在 | 确认文件ID是否正确 |
| 5002 | FileTooLarge | 文件过大 | 使用较小的文件 |
| 5003 | InvalidFileType | 无效的文件类型 | 使用支持的文件类型 |
🔧 使用示例
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 - 让后端集成更简单、更可靠 🚀
