cuatrolabs-spa-ms / WALLET_API_QUICK_REF.md
MukeshKapoor25's picture
feat(leave,wallet): Add leave and wallet modules with JWT auth
a558c77
# Wallet Management API - Quick Reference
## Authentication
All wallet endpoints require JWT authentication. Include the token in the Authorization header:
```
Authorization: Bearer <your_jwt_token>
```
The `partner_id` is automatically extracted from the JWT token - you don't need to provide it in the request body.
## Base URL
```
http://localhost:8000/wallet
```
## Endpoints
### 1. Create Wallet
**POST** `/wallet/create`
Create a new wallet for the authenticated service professional.
**Headers:**
```
Authorization: Bearer <jwt_token>
Content-Type: application/json
```
**Request:**
```json
{
"initial_balance": 5000.00,
"currency": "INR"
}
```
**Response:**
```json
{
"success": true,
"message": "Wallet created successfully",
"data": {
"wallet_id": "550e8400-e29b-41d4-a716-446655440000",
"partner_id": "staff_123",
"balance": 5000.00,
"currency": "INR",
"status": "active",
"last_transaction_at": null,
"created_at": "2024-01-20T10:00:00",
"updated_at": "2024-01-20T10:00:00"
}
}
```
---
### 2. Get My Wallet
**GET** `/wallet/me`
Retrieve complete wallet information for the authenticated user.
**Headers:**
```
Authorization: Bearer <jwt_token>
```
**Response:**
```json
{
"success": true,
"message": "Wallet retrieved successfully",
"data": {
"wallet_id": "550e8400-e29b-41d4-a716-446655440000",
"partner_id": "staff_123",
"balance": 5000.00,
"currency": "INR",
"status": "active",
"last_transaction_at": "2024-01-20T10:30:00",
"created_at": "2024-01-20T10:00:00",
"updated_at": "2024-01-20T10:30:00"
}
}
```
---
### 3. Get My Balance
**GET** `/wallet/balance`
Quick endpoint to check current balance for the authenticated user.
**Headers:**
```
Authorization: Bearer <jwt_token>
```
**Response:**
```json
{
"success": true,
"message": "Balance retrieved successfully",
"data": {
"partner_id": "staff_123",
"balance": 5000.00,
"currency": "INR",
"status": "active"
}
}
```
---
### 4. Create Transaction
**POST** `/wallet/transaction`
Add or deduct money from the authenticated user's wallet.
**Headers:**
```
Authorization: Bearer <jwt_token>
Content-Type: application/json
```
**Credit Transaction (Add Money):**
```json
{
"transaction_type": "credit",
"amount": 1000.00,
"reference_type": "topup",
"reference_id": "TOPUP-2024-001",
"description": "Wallet recharge via UPI",
"metadata": {
"payment_method": "upi",
"upi_id": "user@paytm",
"transaction_ref": "UPI123456"
}
}
```
**Debit Transaction (Deduct Money):**
```json
{
"transaction_type": "debit",
"amount": 500.00,
"reference_type": "order",
"reference_id": "ORDER-123",
"description": "Payment for order ORDER-123"
}
```
**Response:**
```json
{
"success": true,
"message": "Transaction completed successfully",
"data": {
"transaction_id": "660e8400-e29b-41d4-a716-446655440000",
"wallet_id": "550e8400-e29b-41d4-a716-446655440000",
"partner_id": "staff_123",
"transaction_type": "credit",
"amount": 1000.00,
"balance_after": 6000.00,
"reference_type": "topup",
"reference_id": "TOPUP-2024-001",
"description": "Wallet recharge via UPI",
"metadata": {
"payment_method": "upi",
"upi_id": "user@paytm"
},
"created_at": "2024-01-20T10:30:00"
}
}
```
**Transaction Types:**
- `credit` - Add money
- `debit` - Deduct money
**Reference Types:**
- `order` - Payment for orders
- `refund` - Refund from cancelled orders
- `topup` - Manual wallet recharge
- `commission` - Commission earnings
- `withdrawal` - Money withdrawal
---
### 5. List My Transactions
**POST** `/wallet/transactions/list`
Get transaction history for the authenticated user with filters.
**Headers:**
```
Authorization: Bearer <jwt_token>
Content-Type: application/json
```
**Request:**
```json
{
"transaction_type": "credit",
"reference_type": "topup",
"start_date": "2024-01-01T00:00:00",
"end_date": "2024-12-31T23:59:59",
"limit": 20,
"offset": 0
}
```
**Response:**
```json
{
"success": true,
"message": "Transactions retrieved successfully",
"data": {
"transactions": [
{
"transaction_id": "660e8400-e29b-41d4-a716-446655440000",
"wallet_id": "550e8400-e29b-41d4-a716-446655440000",
"partner_id": "staff_123",
"transaction_type": "credit",
"amount": 1000.00,
"balance_after": 6000.00,
"reference_type": "topup",
"reference_id": "TOPUP-2024-001",
"description": "Wallet recharge",
"metadata": {},
"created_at": "2024-01-20T10:30:00"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 45
}
}
}
```
---
## Admin Endpoints
### 6. [Admin] Get Wallet by Partner ID
**GET** `/wallet/admin/{partner_id}`
Admin endpoint to retrieve any wallet by partner ID.
**Headers:**
```
Authorization: Bearer <admin_jwt_token>
```
**Response:** Same as "Get My Wallet"
---
### 7. [Admin] Update Wallet Status
**PATCH** `/wallet/admin/{partner_id}/status?status={status}`
Admin endpoint to change wallet status.
**Headers:**
```
Authorization: Bearer <admin_jwt_token>
```
**Query Parameters:**
- `status` - New status: `active` | `suspended` | `closed`
**Example:**
```
PATCH /wallet/admin/staff_123/status?status=suspended
```
**Status Values:**
- `active` - Normal operation (default)
- `suspended` - Temporarily disabled, no transactions allowed
- `closed` - Permanently disabled
---
## Error Responses
### Unauthorized (Missing/Invalid Token)
```json
{
"detail": "Authorization header missing"
}
```
**Status Code:** 401
### Wallet Not Found
```json
{
"detail": "Wallet not found. Please create a wallet first."
}
```
**Status Code:** 404
### Wallet Already Exists
```json
{
"detail": "Wallet already exists for partner_id: staff_123"
}
```
**Status Code:** 400
### Insufficient Balance
```json
{
"detail": "Insufficient balance. Current: 100.00, Required: 500.00"
}
```
**Status Code:** 400
### Wallet Not Active
```json
{
"detail": "Wallet is not active. Current status: suspended"
}
```
**Status Code:** 400
---
## cURL Examples
### Create Wallet
```bash
curl -X POST "http://localhost:8000/wallet/create" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"initial_balance": 5000.00
}'
```
### Get My Balance
```bash
curl "http://localhost:8000/wallet/balance" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
### Add Money (Credit)
```bash
curl -X POST "http://localhost:8000/wallet/transaction" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transaction_type": "credit",
"amount": 1000.00,
"reference_type": "topup",
"description": "Wallet top-up"
}'
```
### Deduct Money (Debit)
```bash
curl -X POST "http://localhost:8000/wallet/transaction" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transaction_type": "debit",
"amount": 500.00,
"reference_type": "order",
"reference_id": "ORDER-123",
"description": "Payment for order"
}'
```
### List My Transactions
```bash
curl -X POST "http://localhost:8000/wallet/transactions/list" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"limit": 20,
"offset": 0
}'
```
---
## JWT Token Structure
Your JWT token should contain the following claims:
```json
{
"partner_id": "staff_123",
"user_id": "staff_123",
"merchant_id": "merchant_456",
"role": "service_professional",
"email": "staff@example.com",
"phone": "+919876543210",
"exp": 1234567890
}
```
The API will extract `partner_id` from the token. If `partner_id` is not present, it will fall back to `user_id` or `staff_id`.
---
## Security Notes
1. **JWT Authentication**: All endpoints require valid JWT token
2. **Encrypted Balance**: Wallet balance is encrypted in the database using AES encryption
3. **Partner Isolation**: Users can only access their own wallet data
4. **Admin Endpoints**: Admin endpoints should verify admin role (TODO: implement role check)
5. **Rate Limiting**: Implement rate limiting in production to prevent abuse
---
## Integration Example
### Order Payment with Wallet
```python
from app.wallet.services.service import WalletService
from app.wallet.schemas.schema import WalletTransactionRequest
from app.dependencies.auth import get_partner_id
# In your order endpoint
@router.post("/orders/create")
async def create_order(
order_data: OrderCreateRequest,
db: AsyncSession = Depends(get_db),
token_data: dict = Depends(verify_token)
):
partner_id = get_partner_id(token_data)
# Create order
order = await create_order_logic(order_data, partner_id)
# If payment mode is wallet, debit the wallet
if order_data.payment_mode == "wallet":
try:
transaction = await WalletService.create_transaction(
db,
partner_id,
WalletTransactionRequest(
transaction_type="debit",
amount=order.net_amount,
reference_type="order",
reference_id=str(order.order_id),
description=f"Payment for order {order.order_number}",
metadata={
"order_number": order.order_number,
"items_count": len(order.items)
}
)
)
order.payment_status = "paid"
await db.commit()
except ValueError as e:
# Handle insufficient balance
raise HTTPException(status_code=400, detail=str(e))
return order
```
### Refund to Wallet
```python
# When cancelling an order
@router.post("/orders/{order_id}/cancel")
async def cancel_order(
order_id: UUID,
db: AsyncSession = Depends(get_db),
token_data: dict = Depends(verify_token)
):
partner_id = get_partner_id(token_data)
# Get order
order = await get_order_by_id(order_id, partner_id)
# Refund to wallet if paid via wallet
if order.payment_mode == "wallet" and order.payment_status == "paid":
transaction = await WalletService.create_transaction(
db,
partner_id,
WalletTransactionRequest(
transaction_type="credit",
amount=order.net_amount,
reference_type="refund",
reference_id=str(order.order_id),
description=f"Refund for cancelled order {order.order_number}"
)
)
# Cancel order
order.order_status = "cancelled"
order.payment_status = "refunded"
await db.commit()
return order
```