346 lines
9.0 KiB
Markdown
346 lines
9.0 KiB
Markdown
# Gift Subscriptions API Documentation
|
|
|
|
## Overview
|
|
|
|
The Gift Subscriptions feature allows users to purchase subscription gifts that can be redeemed by other users, enabling social gifting and subscription sharing within the DysonNetwork platform.
|
|
|
|
If you use it through the gateway, the `/api` should be replaced with the `/id`
|
|
|
|
### Key Features
|
|
|
|
- **Purchase Gifts**: Users can buy subscriptions as gifts for specific recipients or as open gifts
|
|
- **Gift Codes**: Each gift has a unique redemption code
|
|
- **Flexible Redemption**: Open gifts can be redeemed by anyone, while targeted gifts are recipient-specific
|
|
- **Security**: Prevents duplicate subscriptions and enforces account level requirements
|
|
- **Integration**: Full integration with existing subscription, coupon, and pricing systems
|
|
- **Clean User Experience**: Unpaid gifts are hidden from users and automatically cleaned up
|
|
- **Automatic Maintenance**: Old unpaid gifts are removed after 24 hours
|
|
|
|
## API Endpoints
|
|
|
|
All endpoints are authenticated and require a valid user session. The base path for gift endpoints is `/api/gifts`.
|
|
|
|
### 1. List Sent Gifts
|
|
|
|
Retrieve gifts you have purchased.
|
|
|
|
```http
|
|
GET /api/gifts/sent?offset=0&take=20
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response**: Array of `SnWalletGift` objects
|
|
|
|
### 2. List Received Gifts
|
|
|
|
Retrieve gifts sent to you or redeemed by you (for open gifts).
|
|
|
|
```http
|
|
GET /api/gifts/received?offset=0&take=20
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response**: Array of `SnWalletGift` objects
|
|
|
|
### 3. Get Specific Gift
|
|
|
|
Retrieve details for a specific gift.
|
|
|
|
```http
|
|
GET /api/gifts/{giftId}
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Parameters**:
|
|
- `giftId`: GUID of the gift
|
|
|
|
**Response**: `SnWalletGift` object
|
|
|
|
### 4. Check Gift Code
|
|
|
|
Validate if a gift code can be redeemed by the current user.
|
|
|
|
```http
|
|
GET /api/gifts/check/{giftCode}
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"gift_code": "ABCD1234EFGH",
|
|
"subscription_identifier": "basic",
|
|
"can_redeem": true,
|
|
"error": null,
|
|
"message": "Happy birthday!"
|
|
}
|
|
```
|
|
|
|
### 5. Purchase a Gift
|
|
|
|
Create and purchase a gift subscription.
|
|
|
|
```http
|
|
POST /api/gifts/purchase
|
|
Authorization: Bearer <token>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"subscription_identifier": "premium",
|
|
"recipient_id": "550e8400-e29b-41d4-a716-446655440000", // Optional: null for open gifts
|
|
"payment_method": "in_app_wallet",
|
|
"payment_details": {
|
|
"currency": "irl"
|
|
},
|
|
"message": "Enjoy your premium subscription!", // Optional
|
|
"coupon": "SAVE20", // Optional
|
|
"gift_duration_days": 30, // Optional: defaults to 30
|
|
"subscription_duration_days": 30 // Optional: defaults to 30
|
|
}
|
|
```
|
|
|
|
**Response**: `SnWalletGift` object
|
|
|
|
### 6. Redeem a Gift
|
|
|
|
Redeem a gift code to create a subscription for yourself.
|
|
|
|
```http
|
|
POST /api/gifts/redeem
|
|
Authorization: Bearer <token>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"gift_code": "ABCD1234EFGH"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"gift": { ... },
|
|
"subscription": { ... }
|
|
}
|
|
```
|
|
|
|
### 7. Mark Gift as Sent
|
|
|
|
Mark a gift as sent (ready for redemption).
|
|
|
|
```http
|
|
POST /api/gifts/{giftId}/send
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Parameters**:
|
|
- `giftId`: GUID of the gift to mark as sent
|
|
|
|
### 8. Cancel a Gift
|
|
|
|
Cancel a gift before it has been redeemed.
|
|
|
|
```http
|
|
POST /api/gifts/{giftId}/cancel
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Parameters**:
|
|
- `giftId`: GUID of the gift to cancel
|
|
|
|
## Usage Examples
|
|
|
|
### Client Implementation
|
|
|
|
Here are examples showing how to integrate gift subscriptions into your client application.
|
|
|
|
#### Example 1: Purchase a Gift for a Specific User
|
|
|
|
```javascript
|
|
async function purchaseGiftForFriend(subscriptionId, friendId, message) {
|
|
const response = await fetch('/api/gifts/purchase', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
subscription_identifier: subscriptionId,
|
|
recipient_id: friendId,
|
|
payment_method: 'in_app_wallet',
|
|
payment_details: { currency: 'irl' },
|
|
message: message
|
|
})
|
|
});
|
|
|
|
const gift = await response.json();
|
|
return gift.gift_code; // Share this code with the friend
|
|
}
|
|
```
|
|
|
|
#### Example 2: Create an Open Gift
|
|
|
|
```javascript
|
|
async function createOpenGift(subscriptionId) {
|
|
const response = await fetch('/api/gifts/purchase', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
subscription_identifier: subscriptionId,
|
|
payment_method: 'in_app_wallet',
|
|
payment_details: { currency: 'irl' },
|
|
message: 'Redeem this anywhere!'
|
|
// No recipient_id makes it an open gift
|
|
})
|
|
});
|
|
|
|
const gift = await response.json();
|
|
// Mark as sent to make it redeemable
|
|
await markGiftAsSent(gift.id);
|
|
return gift;
|
|
}
|
|
```
|
|
|
|
#### Example 3: Redeem a Gift Code
|
|
|
|
```javascript
|
|
async function redeemGiftCode(giftCode) {
|
|
// First, check if the gift can be redeemed
|
|
const checkResponse = await fetch(`/api/gifts/check/${giftCode}`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
const checkResult = await checkResponse.json();
|
|
|
|
if (!checkResult.canRedeem) {
|
|
throw new Error(checkResult.error);
|
|
}
|
|
|
|
// If valid, redeem it
|
|
const redeemResponse = await fetch('/api/gifts/redeem', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
gift_code: giftCode
|
|
})
|
|
});
|
|
|
|
const result = await redeemResponse.json();
|
|
return result.subscription; // The newly created subscription
|
|
}
|
|
```
|
|
|
|
#### Example 4: Display User's Gift History
|
|
|
|
```javascript
|
|
async function getGiftHistory() {
|
|
// Get gifts I sent
|
|
const sentResponse = await fetch('/api/gifts/sent', {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
const sentGifts = await sentResponse.json();
|
|
|
|
// Get gifts I received
|
|
const receivedResponse = await fetch('/api/gifts/received', {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
const receivedGifts = await receivedResponse.json();
|
|
|
|
return { sent: sentGifts, received: receivedGifts };
|
|
}
|
|
```
|
|
|
|
## Gift Status Lifecycle
|
|
|
|
Gifts follow this status lifecycle:
|
|
|
|
1. **Created**: Initially purchased, can be cancelled or marked as sent
|
|
- **Note**: Gifts in "Created" status are not visible to users and are automatically cleaned up after 24 hours if unpaid
|
|
2. **Sent**: Made available for redemption, can be cancelled
|
|
3. **Redeemed**: Successfully redeemed, creates a subscription
|
|
4. **Cancelled**: Permanently cancelled, refund may be processed
|
|
5. **Expired**: Expired without redemption
|
|
|
|
## Automatic Maintenance
|
|
|
|
The system includes automatic cleanup to maintain data integrity:
|
|
|
|
- **Unpaid Gift Cleanup**: Gifts that remain in "Created" status (unpaid) for more than 24 hours are automatically removed from the database
|
|
- **User Visibility**: Only gifts that have been successfully paid and sent are visible in user gift lists
|
|
- **Background Processing**: Cleanup runs hourly via scheduled jobs
|
|
|
|
This ensures a clean user experience while preventing accumulation of abandoned gift purchases.
|
|
|
|
## Validation Rules
|
|
|
|
### Purchase Validation
|
|
- Subscription must exist and be valid
|
|
- If coupon provided, it must be valid and applicable
|
|
- Recipient account must exist (if specified)
|
|
- User must meet level requirements for the subscription
|
|
|
|
### Redemption Validation
|
|
- Gift code must exist
|
|
- Gift must be in "Sent" status
|
|
- Gift must not be expired
|
|
- User must meet level requirements
|
|
- User must not already have an active subscription of the same type
|
|
- For targeted gifts, user must be the specified recipient
|
|
|
|
## Pricing & Payments
|
|
|
|
Gifts use the same pricing system as regular subscriptions:
|
|
|
|
- Base price from subscription template
|
|
- Coupon discounts applied
|
|
- Currency conversion as needed
|
|
- Payment processing through existing payment methods
|
|
|
|
## Notification Events
|
|
|
|
The system sends push notifications for:
|
|
|
|
- **gifts.redeemed**: When someone redeems your gift
|
|
- **gifts.claimed**: When the recipient redeems your targeted gift
|
|
|
|
Notifications include gift and subscription details for rich UI updates.
|
|
|
|
## Error Handling
|
|
|
|
Common error responses:
|
|
|
|
- `400 Bad Request`: Invalid parameters, validation failures
|
|
- `401 Unauthorized`: Missing or invalid authentication
|
|
- `403 Forbidden`: Insufficient permissions
|
|
- `404 Not Found`: Gift or subscription not found
|
|
- `409 Conflict`: Business logic violations (duplicate subscriptions, etc.)
|
|
|
|
## Integration Notes
|
|
|
|
### Database Schema
|
|
The feature adds a `wallet_gifts` table with relationships to:
|
|
- `accounts` (gifter, recipient, redeemer)
|
|
- `wallet_subscriptions` (created subscription)
|
|
- `wallet_coupons` (applied discounts)
|
|
|
|
### Backwards Compatibility
|
|
- No changes to existing subscription endpoints
|
|
- New gift-related endpoints are additive
|
|
- Existing payment flows remain unchanged
|
|
|
|
### Performance Considerations
|
|
- Gift codes are indexed for fast lookups
|
|
- Status filters optimize database queries
|
|
- Caching integrated with existing subscription caching
|
|
|
|
## Support
|
|
|
|
For implementation questions or issues, refer to the DysonNetwork API documentation or contact the development team.
|