Prepaid Reservations
Reservations enable real-time balance control by holding funds before consumption.
Reservation Flow
Reservation Status Lifecycle
OPEN → CONFIRMED (service consumed)
→ CANCELLED (user cancellation)
→ EXPIRED (auto-timeout)
API Endpoints
Reserve via CDR
POST /api/rest/billing/mediation/reserveCdr
Content-Type: text/plain
2024-01-15T10:30:00;SUB_001;5000;API_TOKENS;GPT-4
Response:
{
"reservationId": 12345,
"availableQuantity": 5000,
"amountWithTax": 10.00
}
Confirm Reservation
POST /api/rest/billing/mediation/confirmReservation
Content-Type: application/json
{
"reservationId": 12345
}
Response:
{
"status": "SUCCESS",
"message": "Reservation confirmed"
}
Cancel Reservation
POST /api/rest/billing/mediation/cancelReservation
Content-Type: application/json
{
"reservationId": 12345
}
Response:
{
"status": "SUCCESS",
"message": "Reservation cancelled, balance restored"
}
Auto-Expiration
Reservations automatically expire after a configurable timeout.
Configuration
Set at Provider level:
Provider.prepaidReservationExpirationDelayinMillisec = 300000 // 5 minutes
Timer Mechanism
// On reservation creation, a timer is scheduled
Timer timer = timerService.createSingleActionTimer(
provider.getPrepaidReservationExpirationDelayinMillisec(),
timerConfig);
// When timer fires
@Timeout
void reservationExpired(Timer timer) {
Reservation reservation = findById(reservationId);
if (reservation.getStatus() != CONFIRMED) {
cancelPrepaidReservation(reservation); // Auto-cancel
}
}
Counter Integration
Counter Deduction on Reserve
When a reservation is created:
- Counter is immediately decremented
- Deducted value stored in
reservation.counterPeriodValues - If reservation is cancelled, counter is restored
// Store counter values for later restoration
if (reservation != null) {
reservation.getCounterPeriodValues().put(
counterPeriodId,
deltaValue);
}
Counter Restoration on Cancel
// Restore all counter values
for (Entry<Long, BigDecimal> periodInfo :
reservation.getCounterPeriodValues().entrySet()) {
counterInstanceService.incrementCounterValue(
periodInfo.getKey(),
periodInfo.getValue());
}
Wallet Reservation API
For offer-based reservations (not CDR-based):
Create Reservation
POST /api/rest/billing/wallet/reservation
Content-Type: application/json
{
"sellerCode": "MAIN_SELLER",
"offerCode": "BASIC_OFFER",
"userAccountCode": "UA_001",
"subscriptionDate": "2024-01-15",
"creditLimit": 100.00
}
Update Reservation
PUT /api/rest/billing/wallet/reservation
Content-Type: application/json
{
"reservationId": 12345,
"creditLimit": 150.00
}
Cancel Reservation
DELETE /api/rest/billing/wallet/reservation/12345
Confirm Reservation
POST /api/rest/billing/wallet/reservation/confirm
Content-Type: application/json
{
"reservationId": 12345
}
Error Handling
Insufficient Balance
{
"status": "FAIL",
"errorCode": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance: required $15.00, available $10.50"
}
Reservation Not Found
{
"status": "FAIL",
"errorCode": "ENTITY_NOT_FOUND",
"message": "Reservation 12345 not found"
}
Reservation Already Confirmed
{
"status": "FAIL",
"errorCode": "INVALID_STATE",
"message": "Reservation 12345 is already confirmed"
}