Files
Swarm/API_WALLET_FUNDS.md
2025-10-04 01:17:21 +08:00

16 KiB

Wallet Funds API Documentation

Overview

The Wallet Funds API provides red packet functionality for the DysonNetwork platform, allowing users to create and distribute funds among multiple recipients with expiration and claiming mechanisms.

Authentication

All endpoints require Bearer token authentication:

Authorization: Bearer {jwt_token}

Data Types

Enums

FundSplitType

enum FundSplitType {
  Even = 0,    // Equal distribution
  Random = 1   // Lucky draw distribution
}

FundStatus

enum FundStatus {
  Created = 0,           // Fund created, waiting for claims
  PartiallyReceived = 1, // Some recipients claimed
  FullyReceived = 2,     // All recipients claimed
  Expired = 3,           // Fund expired, unclaimed amounts refunded
  Refunded = 4           // Legacy status
}

Request/Response Models

CreateFundRequest

interface CreateFundRequest {
  recipientAccountIds: string[];  // UUIDs of recipients
  currency: string;               // e.g., "points", "golds"
  totalAmount: number;            // Total amount to distribute
  splitType: FundSplitType;       // Even or Random
  message?: string;               // Optional message
  expirationHours?: number;       // Optional: hours until expiration (default: 24)
  pinCode: string;                // Required: 6-digit PIN code for security
}

SnWalletFund

interface SnWalletFund {
  id: string;                     // UUID
  currency: string;
  totalAmount: number;
  splitType: FundSplitType;
  status: FundStatus;
  message?: string;
  creatorAccountId: string;       // UUID
  creatorAccount: SnAccount;      // Creator account details (includes profile)
  recipients: SnWalletFundRecipient[];
  expiredAt: string;              // ISO 8601 timestamp
  createdAt: string;              // ISO 8601 timestamp
  updatedAt: string;              // ISO 8601 timestamp
}

SnWalletFundRecipient

interface SnWalletFundRecipient {
  id: string;                     // UUID
  fundId: string;                 // UUID
  recipientAccountId: string;     // UUID
  recipientAccount: SnAccount;    // Recipient account details (includes profile)
  amount: number;                 // Allocated amount
  isReceived: boolean;
  receivedAt?: string;            // ISO 8601 timestamp (if claimed)
  createdAt: string;              // ISO 8601 timestamp
  updatedAt: string;              // ISO 8601 timestamp
}

SnWalletTransaction

interface SnWalletTransaction {
  id: string;                     // UUID
  payerWalletId?: string;         // UUID (null for system transfers)
  payeeWalletId?: string;         // UUID (null for system transfers)
  currency: string;
  amount: number;
  remarks?: string;
  type: TransactionType;
  createdAt: string;              // ISO 8601 timestamp
  updatedAt: string;              // ISO 8601 timestamp
}

Error Response

interface ErrorResponse {
  type: string;                   // Error type
  title: string;                  // Error title
  status: number;                 // HTTP status code
  detail: string;                 // Error details
  instance?: string;              // Request instance
}

API Endpoints

1. Create Fund

Creates a new fund (red packet) for distribution among recipients.

Endpoint: POST /api/wallets/funds

Request Body: CreateFundRequest

Response: SnWalletFund (201 Created)

Example Request:

curl -X POST "/api/wallets/funds" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "recipientAccountIds": [
      "550e8400-e29b-41d4-a716-446655440000",
      "550e8400-e29b-41d4-a716-446655440001",
      "550e8400-e29b-41d4-a716-446655440002"
    ],
    "currency": "points",
    "totalAmount": 100.00,
    "splitType": "Even",
    "message": "Happy New Year! 🎉",
    "expirationHours": 48,
    "pinCode": "123456"
  }'

Example Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440003",
  "currency": "points",
  "totalAmount": 100.00,
  "splitType": 0,
  "status": 0,
  "message": "Happy New Year! 🎉",
  "creatorAccountId": "550e8400-e29b-41d4-a716-446655440004",
  "creatorAccount": {
    "id": "550e8400-e29b-41d4-a716-446655440004",
    "username": "creator_user"
  },
  "recipients": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440005",
      "fundId": "550e8400-e29b-41d4-a716-446655440003",
      "recipientAccountId": "550e8400-e29b-41d4-a716-446655440000",
      "amount": 33.34,
      "isReceived": false,
      "createdAt": "2025-10-03T22:00:00Z",
      "updatedAt": "2025-10-03T22:00:00Z"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440006",
      "fundId": "550e8400-e29b-41d4-a716-446655440003",
      "recipientAccountId": "550e8400-e29b-41d4-a716-446655440001",
      "amount": 33.33,
      "isReceived": false,
      "createdAt": "2025-10-03T22:00:00Z",
      "updatedAt": "2025-10-03T22:00:00Z"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440007",
      "fundId": "550e8400-e29b-41d4-a716-446655440003",
      "recipientAccountId": "550e8400-e29b-41d4-a716-446655440002",
      "amount": 33.33,
      "isReceived": false,
      "createdAt": "2025-10-03T22:00:00Z",
      "updatedAt": "2025-10-03T22:00:00Z"
    }
  ],
  "expiredAt": "2025-10-05T22:00:00Z",
  "createdAt": "2025-10-03T22:00:00Z",
  "updatedAt": "2025-10-03T22:00:00Z"
}

Error Responses:

  • 400 Bad Request: Invalid parameters, insufficient funds, invalid recipients
  • 401 Unauthorized: Missing or invalid authentication
  • 403 Forbidden: Invalid PIN code
  • 422 Unprocessable Entity: Business logic violations

2. Get Funds

Retrieves funds that the authenticated user is involved in (as creator or recipient).

Endpoint: GET /api/wallets/funds

Query Parameters:

  • offset (number, optional): Pagination offset (default: 0)
  • take (number, optional): Number of items to return (default: 20, max: 100)
  • status (FundStatus, optional): Filter by fund status

Response: SnWalletFund[] (200 OK)

Headers:

  • X-Total: Total number of funds matching the criteria

Example Request:

curl -X GET "/api/wallets/funds?offset=0&take=10&status=0" \
  -H "Authorization: Bearer {token}"

Example Response:

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440003",
    "currency": "points",
    "totalAmount": 100.00,
    "splitType": 0,
    "status": 0,
    "message": "Happy New Year! 🎉",
    "creatorAccountId": "550e8400-e29b-41d4-a716-446655440004",
    "creatorAccount": {
      "id": "550e8400-e29b-41d4-a716-446655440004",
      "username": "creator_user"
    },
    "recipients": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440005",
        "fundId": "550e8400-e29b-41d4-a716-446655440003",
        "recipientAccountId": "550e8400-e29b-41d4-a716-446655440000",
        "amount": 33.34,
        "isReceived": false
      }
    ],
    "expiredAt": "2025-10-05T22:00:00Z",
    "createdAt": "2025-10-03T22:00:00Z",
    "updatedAt": "2025-10-03T22:00:00Z"
  }
]

Error Responses:

  • 401 Unauthorized: Missing or invalid authentication

3. Get Fund

Retrieves details of a specific fund.

Endpoint: GET /api/wallets/funds/{id}

Path Parameters:

  • id (string): Fund UUID

Response: SnWalletFund (200 OK)

Example Request:

curl -X GET "/api/wallets/funds/550e8400-e29b-41d4-a716-446655440003" \
  -H "Authorization: Bearer {token}"

Example Response: (Same as create fund response)

Error Responses:

  • 401 Unauthorized: Missing or invalid authentication
  • 403 Forbidden: User doesn't have permission to view this fund
  • 404 Not Found: Fund not found

4. Receive Fund

Claims the authenticated user's portion of a fund.

Endpoint: POST /api/wallets/funds/{id}/receive

Path Parameters:

  • id (string): Fund UUID

Response: SnWalletTransaction (200 OK)

Example Request:

curl -X POST "/api/wallets/funds/550e8400-e29b-41d4-a716-446655440003/receive" \
  -H "Authorization: Bearer {token}"

Example Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440008",
  "payerWalletId": null,
  "payeeWalletId": "550e8400-e29b-41d4-a716-446655440009",
  "currency": "points",
  "amount": 33.34,
  "remarks": "Received fund portion from 550e8400-e29b-41d4-a716-446655440004",
  "type": 1,
  "createdAt": "2025-10-03T22:05:00Z",
  "updatedAt": "2025-10-03T22:05:00Z"
}

Error Responses:

  • 400 Bad Request: Fund expired, already claimed, not a recipient
  • 401 Unauthorized: Missing or invalid authentication
  • 404 Not Found: Fund not found

5. Get Wallet Overview

Retrieves a summarized overview of wallet transactions grouped by type for graphing/charting purposes.

Endpoint: GET /api/wallets/overview

Query Parameters:

  • startDate (string, optional): Start date in ISO 8601 format (e.g., "2025-01-01T00:00:00Z")
  • endDate (string, optional): End date in ISO 8601 format (e.g., "2025-12-31T23:59:59Z")

Response: WalletOverview (200 OK)

Example Request:

curl -X GET "/api/wallets/overview?startDate=2025-01-01T00:00:00Z&endDate=2025-12-31T23:59:59Z" \
  -H "Authorization: Bearer {token}"

Example Response:

{
  "accountId": "550e8400-e29b-41d4-a716-446655440000",
  "startDate": "2025-01-01T00:00:00.0000000Z",
  "endDate": "2025-12-31T23:59:59.0000000Z",
  "summary": {
    "System": {
      "type": "System",
      "currencies": {
        "points": {
          "currency": "points",
          "income": 150.00,
          "spending": 0.00,
          "net": 150.00
        }
      }
    },
    "Transfer": {
      "type": "Transfer",
      "currencies": {
        "points": {
          "currency": "points",
          "income": 25.00,
          "spending": 75.00,
          "net": -50.00
        },
        "golds": {
          "currency": "golds",
          "income": 0.00,
          "spending": 10.00,
          "net": -10.00
        }
      }
    },
    "Order": {
      "type": "Order",
      "currencies": {
        "points": {
          "currency": "points",
          "income": 0.00,
          "spending": 200.00,
          "net": -200.00
        }
      }
    }
  },
  "totalIncome": 175.00,
  "totalSpending": 285.00,
  "netTotal": -110.00
}

Response Fields:

  • accountId: User's account UUID
  • startDate/endDate: Date range applied (ISO 8601 format)
  • summary: Object keyed by transaction type
    • type: Transaction type name
    • currencies: Object keyed by currency code
      • currency: Currency name
      • income: Total money received
      • spending: Total money spent
      • net: Income minus spending
  • totalIncome: Sum of all income across all types/currencies
  • totalSpending: Sum of all spending across all types/currencies
  • netTotal: Overall net (totalIncome - totalSpending)

Error Responses:

  • 401 Unauthorized: Missing or invalid authentication

Error Codes

Common Error Types

Validation Errors

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "At least one recipient is required",
  "instance": "/api/wallets/funds"
}

Insufficient Funds

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "Insufficient funds",
  "instance": "/api/wallets/funds"
}

Fund Not Available

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "Fund is no longer available",
  "instance": "/api/wallets/funds/550e8400-e29b-41d4-a716-446655440003/receive"
}

Already Claimed

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "You have already received this fund",
  "instance": "/api/wallets/funds/550e8400-e29b-41d4-a716-446655440003/receive"
}

Rate Limiting

  • Create Fund: 10 requests per minute per user
  • Get Funds: 60 requests per minute per user
  • Get Fund: 60 requests per minute per user
  • Receive Fund: 30 requests per minute per user

Webhooks/Notifications

The system integrates with the platform's notification system:

  • Fund Created: Creator receives confirmation
  • Fund Claimed: Creator receives notification when someone claims
  • Fund Expired: Creator receives refund notification

SDK Examples

JavaScript/TypeScript

// Create a fund
const createFund = async (fundData: CreateFundRequest): Promise<SnWalletFund> => {
  const response = await fetch('/api/wallets/funds', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(fundData)
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return response.json();
};

// Get user's funds
const getFunds = async (params?: {
  offset?: number;
  take?: number;
  status?: FundStatus;
}): Promise<SnWalletFund[]> => {
  const queryParams = new URLSearchParams();
  if (params?.offset) queryParams.set('offset', params.offset.toString());
  if (params?.take) queryParams.set('take', params.take.toString());
  if (params?.status !== undefined) queryParams.set('status', params.status.toString());

  const response = await fetch(`/api/wallets/funds?${queryParams}`, {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return response.json();
};

// Claim a fund
const receiveFund = async (fundId: string): Promise<SnWalletTransaction> => {
  const response = await fetch(`/api/wallets/funds/${fundId}/receive`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return response.json();
};

Python

import requests
from typing import List, Optional
from enum import Enum

class FundSplitType(Enum):
    EVEN = 0
    RANDOM = 1

class FundStatus(Enum):
    CREATED = 0
    PARTIALLY_RECEIVED = 1
    FULLY_RECEIVED = 2
    EXPIRED = 3
    REFUNDED = 4

def create_fund(token: str, fund_data: dict) -> dict:
    """Create a new fund"""
    response = requests.post(
        '/api/wallets/funds',
        json=fund_data,
        headers={
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        }
    )
    response.raise_for_status()
    return response.json()

def get_funds(
    token: str,
    offset: int = 0,
    take: int = 20,
    status: Optional[FundStatus] = None
) -> List[dict]:
    """Get user's funds"""
    params = {'offset': offset, 'take': take}
    if status is not None:
        params['status'] = status.value

    response = requests.get(
        '/api/wallets/funds',
        params=params,
        headers={'Authorization': f'Bearer {token}'}
    )
    response.raise_for_status()
    return response.json()

def receive_fund(token: str, fund_id: str) -> dict:
    """Claim a fund portion"""
    response = requests.post(
        f'/api/wallets/funds/{fund_id}/receive',
        headers={'Authorization': f'Bearer {token}'}
    )
    response.raise_for_status()
    return response.json()

Changelog

Version 1.0.0

  • Initial release with basic red packet functionality
  • Support for even and random split types
  • 24-hour expiration with automatic refunds
  • RESTful API endpoints
  • Comprehensive error handling

Support

For API support or questions:

  • Check the main documentation at README_WALLET_FUNDS.md
  • Review error messages for specific guidance
  • Contact the development team for technical issues