πŸͺ™ Wallet System API

Complete API documentation for the points-based wallet system with P2P trading, escrow, and charity donations.

πŸ“‹ Overview

System architecture and key concepts

Points System

  • 1 Knot = 100 Points (display unit)
  • 1 OMR = 100 Points (currency conversion for top-ups)
  • Top-Up Commission: 3% added to the base amount (buyer pays base + 3%)
  • Price Guard: P2P trades limited to 950-1000 baisas per Knot
  • Annual Mint Limit: 1,000,000 points per merchant

Authentication

All endpoints require JWT Bearer token unless marked as Public

Authorization: Bearer <jwt_token>

Base URL

/wallet

πŸ’° Balance & Transactions

View wallet balance and transaction history

GET /wallet/balance Auth Required

Get current user's wallet balance

Response

{
  "points": 50000,
  "knots": 50,
  "frozenPoints": 5000,
  "frozenKnots": 5,
  "availablePoints": 45000,
  "availableKnots": 45
}
GET /wallet/balance/:userId Auth Required

Get another user's wallet balance (public info)

GET /wallet/transactions Auth Required

Get current user's transaction history

Query ParamTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)

πŸ’³ Top-Up (Buy Points)

Purchase points using Thawani payment gateway (default)

POST /wallet/topup Auth Required

Initiate a top-up to buy points (default gateway: Thawani). To force EdfaPay, pass gateway=edfapay.

Request Body

FieldTypeDescription
pointsnumberPoints to purchase (min: 1000)
gatewayenumPayment gateway (default: thawani). Allowed: thawani, edfapay.
termUrl3dsstring3DS return URL for your app
currencystringCurrency code (default: OMR)
payerFirstNamestringPayer's first name
payerLastNamestringPayer's last name
payerEmailstringPayer's email
payerPhonestringPayer's phone
payerAddressstringPayer's address
payerCitystringPayer's city
payerCountrystringCountry code (default: OM)
payerZipstringPostal code
payerIpstringPayer's IP address

Response

{
  "topUpId": "uuid",
  "redirectUrl": "https://checkout.thawani.om/pay/...",
  "pointsToCredit": 5000,
  "amountInCurrency": 51.50,
  "currency": "OMR"
}

amountInCurrency: Stored/returned in OMR major units (2 decimals) and includes the 3% commission.

ℹ️ Flow Redirect user to redirectUrl. After payment, Thawani calls the webhook to credit points. (EdfaPay callbacks remain supported for legacy flows.)
GET /wallet/topups Auth Required

Get user's top-up history

↔️ Transfer Points

Send points to other users

POST /wallet/transfer Auth Required

Transfer points to another user

FieldTypeDescription
toUserIduuidRecipient user ID
amountnumberPoints to transfer (min: 1)
descriptionstringTransfer note/memo
⚠️ Important Transfer is instant and irreversible. Ensure recipient ID is correct.

πŸ”’ Escrow (Order Checkout)

Pay for orders with points using escrow protection. Carriers can set custom shipping/escrow durations.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Create Order│───▢│Carrier Sets │───▢│ Checkout with Points│───▢│ Seller Ships│───▢│Carrier Confirms β”‚ β”‚ PENDING β”‚ β”‚ Escrow Hours β”‚ β”‚ AWAITING_FULFILLMENTβ”‚ β”‚ SHIPPED β”‚ β”‚Delivery (Shipments) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ (1-168 hours) β”‚ β”‚ (Points in Escrow) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ (optional) β”‚ β”‚ β”‚ Releases escrow β”‚ Timeout (carrier-set or 12h default) β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Order COMPLETED β”‚ β”‚ Auto-Refund β”‚ β”‚ Points to Sellerβ”‚ β”‚ CANCELLED β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ (Points to Buyer) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
PATCH /orders/:orderId/escrow-hours Auth Required Carrier Only

Set custom escrow/shipping duration for an order (must be called before checkout)

FieldTypeDescription
hoursnumberEscrow duration in hours (1-168, i.e., 1 hour to 7 days)
🚚 Carrier Feature Only users with isCarrier: true can set escrow hours. This allows carriers to set realistic shipping timeframes based on distance and logistics.
POST /orders/:orderId/checkout/points Auth Required

Pay for an order with points (creates escrow)

βœ… Buyer Protection Points are held in escrow for the carrier-set duration (or 12 hours default). If seller doesn't fulfill, points are automatically refunded.
POST /orders/:orderId/confirm-delivery Auth Required

Confirm delivery (buyer only). For points-based orders, delivery confirmation must be done by the assigned carrier via /shipments/:shipmentId/confirm-delivery

POST /shipments/:shipmentId/confirm-pickup Auth Required Admin or Carrier

Carrier confirms pickup from merchant/company (must be the assigned carrier unless admin)

POST /shipments/:shipmentId/confirm-delivery Auth Required Admin or Carrier

Carrier confirms delivery to customer. For points-based orders, this releases escrow and completes the order

POST /orders/:orderId/ship Auth Required

Mark order as shipped (seller only)

POST /orders/:orderId/cancel Auth Required

Cancel order and refund escrow (buyer or seller)

FieldTypeDescription
reasonstringCancellation reason

🀝 P2P Trading

Buy and sell points with other users (price guard: 950-1000 baisas/Knot)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Seller Creates │───▢│ Buyer Requests │───▢│ Seller Approves│───▢│ Buyer Completesβ”‚ β”‚ OPEN β”‚ β”‚ PENDING β”‚ β”‚ APPROVED β”‚ β”‚ COMPLETED β”‚ β”‚ β”‚ β”‚ β”‚ β”‚(Points Frozen) β”‚ β”‚(Points Transfer) β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ Cancel β”‚ Cancel (unfreeze) β–Ό β–Ό CANCELLED CANCELLED
GET /wallet/trades/marketplace Auth Required

List all open trade offers

GET /wallet/trades/my Auth Required

List user's trades

Query ParamTypeDescription
rolestringFilter: seller | buyer | all
statusstringFilter: open | pending | approved | completed | cancelled
POST /wallet/trades Auth Required

Create a trade offer (sell points)

FieldTypeDescription
pointsAmountnumberPoints to sell (min: 1000)
pricePerKnotnumberPrice in baisas (950-1000)
expiresInHoursnumberOffer expiry (default: 24)
⚠️ Price Guard Price must be between 950-1000 baisas per Knot to prevent extreme pricing.
POST /wallet/trades/:tradeId/request Auth Required

Request to buy from a trade offer

POST /wallet/trades/:tradeId/approve Auth Required

Seller approves buyer's request (freezes seller's points)

POST /wallet/trades/:tradeId/complete Auth Required

Buyer completes trade (after external payment)

POST /wallet/trades/:tradeId/cancel Auth Required

Cancel trade (unfreezes points if approved)

🏭 Admin Point Minting

Admins can mint new points directly for users

POST /wallet/admin/users/mint Admin Only

Mint points directly for a user

FieldTypeDescription
userIdUUIDTarget user's ID
pointsnumberPoints to mint (min: 1)
reasonstringReason for minting

Response

{
  "success": true,
  "message": "Minted 1000 points for user",
  "transaction": { "id": "...", "amount": "1000", ... },
  "newBalance": "5000"
}
⚠️ Admin Only Only admins can mint points. All minting actions are logged in the audit trail and the user receives an email notification.

πŸŽ—οΈ Charity & Donations

Create charity profiles and accept point donations

GET /wallet/charities Auth Required

List verified charities

GET /wallet/charities/slug/:slug Public

Get charity by slug (for donation pages/QR codes)

GET /wallet/charities/:charityId Auth Required

Get charity details

GET /wallet/charities/:charityId/donations Auth Required

Get charity's donation history

POST /wallet/charities Auth Required

Register a new charity profile

FieldTypeDescription
namestringCharity name
slugstringUnique URL-friendly identifier
descriptionstringCharity description
websiteUrlstringWebsite URL
registrationNumberstringOfficial registration number
ℹ️ Verification New charities start as PENDING and must be verified by an admin before accepting donations.
POST /wallet/charities/:charityId/update Auth Required

Update charity profile (owner only)

POST /wallet/donate Auth Required

Donate points to a charity

FieldTypeDescription
charityIduuidCharity ID
amountnumberPoints to donate (min: 100)
messagestringDonation message
POST /wallet/donate/slug Auth Required

Donate by charity slug (for QR code donations)

FieldTypeDescription
charitySlugstringCharity slug
amountnumberPoints to donate
messagestringDonation message

🏦 Withdrawals

Convert points back to real money via bank transfer

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Requests │───▢│ Admin Reviews │───▢│ Admin Transfers│───▢│ Admin Resolves β”‚ β”‚ PENDING β”‚ β”‚ β”‚ β”‚ (Bank Payment) β”‚ β”‚ COMPLETED β”‚ β”‚(Points Frozen) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚(Receipt Upload)β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ User Cancel Reject (Refund) β–Ό β–Ό CANCELLED REJECTED (Points Restored) (Points Restored)
POST /wallet/withdrawals Auth Required

Create a withdrawal request (convert points to bank transfer)

FieldTypeDescription
amountnumberPoints to withdraw (min: 1000)
bankNamestringBank name (max: 100)
accountNumberstringBank account number (max: 50)
accountHolderNamestringAccount holder name (max: 200)
ibanstringIBAN (max: 50)
reasonenumReason: selling_plastic | selling_metals | selling_paper | selling_glass | selling_electronics | selling_various_materials | transport_service | landfill_service | other
reasonNotesstringAdditional notes for reason (max: 1000, recommended if reason is "other")
attachmentUrlstringURL of supporting document or image
userNotestringNote to admin (max: 500)

Response

{
  "id": "uuid",
  "amount": "10000",
  "status": "pending",
  "bankName": "Bank Muscat",
  "accountNumber": "1234567890",
  "reason": "selling_various_materials",
  "attachmentUrl": "https://example.com/doc.pdf",
  "reasonNotes": null,
  "currencyAmount": "10000",
  "currency": "OMR"
}
⚠️ Points Frozen Requested points are frozen immediately and cannot be used until the request is resolved or cancelled.
GET /wallet/withdrawals Auth Required

Get user's withdrawal request history

Query ParamTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20)
GET /wallet/withdrawals/:requestId Auth Required

Get details of a specific withdrawal request

POST /wallet/withdrawals/:requestId/cancel Auth Required

Cancel a pending withdrawal request (restores frozen points)

ℹ️ Note Only PENDING requests can be cancelled. Points are immediately restored to available balance.

πŸ›‘οΈ Admin Endpoints

Administrative functions (requires admin privileges)

Dashboard

GET /wallet/admin/stats Admin Only

Get wallet system statistics

Response

{
  "totalCirculatingPoints": 50000000,
  "totalFrozenPoints": 1000000,
  "totalUsersWithWallet": 1250,
  "totalTopUpAmountInCurrency": 45000000,
  "currency": "OMR"
}

Platform Profit

GET /admin/profit/reports Admin Only

Get platform profit reports (weekly / monthly / yearly) aggregated by period and side (buyer/seller)

Query ParamTypeDescription
periodstringweekly | monthly | yearly
fromstringStart date (ISO), optional
tostringEnd date (ISO), optional

Example

GET /admin/profit/reports?period=monthly&from=2026-01-01&to=2026-12-31

Response

[
  {
    "period": "2026-01-01T00:00:00.000Z",
    "side": "buyer",
    "totalQuantity": 1500,
    "totalSar": 15,
    "totalPoints": 1500
  },
  {
    "period": "2026-01-01T00:00:00.000Z",
    "side": "seller",
    "totalQuantity": 1500,
    "totalSar": 15,
    "totalPoints": 1500
  }
]
GET /wallet/admin/dashboard Admin Only

Get full dashboard with wallet and audit stats

GET /wallet/admin/dashboard/detailed Admin Only

Get detailed dashboard with date range

Query ParamTypeDescription
startDateISO dateStart of period
endDateISO dateEnd of period

Mint Requests

GET /wallet/admin/mint-requests Admin Only

List all mint requests

Query ParamTypeDescription
statusstringFilter: pending | partially_approved | approved | rejected
POST /wallet/admin/mint-requests/:requestId/approve Admin Only

Approve a mint request (requires 2 different admins)

POST /wallet/admin/mint-requests/:requestId/reject Admin Only

Reject a mint request

FieldTypeDescription
reasonstringRejection reason

Charities

GET /wallet/admin/charities Admin Only

List all charities (including pending)

Query ParamTypeDescription
statusstringFilter: pending | verified | suspended
POST /wallet/admin/charities/:charityId/verify Admin Only

Verify a charity (enables donations)

Withdrawals

GET /wallet/admin/withdrawals Admin Only

List all withdrawal requests

Query ParamTypeDescription
statusstringFilter: pending | processing | completed | rejected | cancelled
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20)
GET /wallet/admin/withdrawals/pending-count Admin Only

Get count of pending withdrawal requests (for dashboard badge)

Response

5
POST /wallet/admin/withdrawals/:requestId/resolve Admin Only

Mark withdrawal as completed after bank transfer

FieldTypeDescription
receiptImageUrlstringURL of uploaded bank transfer receipt image
adminNotestringNote visible to user (max: 500)
referenceNumberstringBank transaction reference (max: 50)
βœ… Completion Flow 1. Admin transfers money to user's bank account
2. Admin uploads receipt image (to storage, get URL)
3. Admin calls this endpoint with receipt URL
4. User receives email notification with receipt
POST /wallet/admin/withdrawals/:requestId/reject Admin Only

Reject a withdrawal request (restores user's frozen points)

FieldTypeDescription
reasonstringRejection reason (max: 500)
⚠️ Points Restored Frozen points are automatically restored to user's available balance when rejected.

Audit Logs

GET /wallet/admin/audit Admin Only

Get audit logs with filtering

Query ParamTypeDescription
userIduuidFilter by user
actionstringFilter by action type
severitystringFilter: info | warning | critical
POST /wallet/admin/audit/search Admin Only

Advanced audit log search

GET /wallet/admin/audit/critical Admin Only

Get critical security events

GET /wallet/admin/audit/user/:userId Admin Only

Get all audit logs for a specific user

GET /wallet/admin/audit/stats Admin Only

Get audit statistics

User Management

GET /wallet/admin/users/:userId/wallet Admin Only

Get detailed user wallet info (balance, transactions, audit logs)

POST /wallet/admin/users/freeze Admin Only

Freeze points in user's wallet

FieldTypeDescription
userIduuidTarget user ID
pointsnumberPoints to freeze
reasonstringReason for freeze
POST /wallet/admin/users/unfreeze Admin Only

Unfreeze points in user's wallet

POST /wallet/admin/users/adjust Admin Only

Adjust user's balance (for corrections)

FieldTypeDescription
userIduuidTarget user ID
amountnumberAmount to adjust (can be negative)
reasonstringReason for adjustment

πŸ”” Webhooks

Payment gateway callback endpoints

POST /webhooks/wallet/edfapay Public

EdfaPay payment callback (called by EdfaPay servers)

ℹ️ Server-to-Server This endpoint is called by EdfaPay after payment processing. It automatically credits points on successful payments.
POST /webhooks/wallet/thawani Public

Thawani payment callback (called by Thawani servers)

ℹ️ Server-to-Server This endpoint is called by Thawani after payment processing. It automatically credits points on successful payments.
POST /webhooks/wallet/edfapay/3ds-return Public

EdfaPay 3DS return handler (user redirect after 3DS)

πŸ—„οΈ Database Entities

Core data models for the wallet system

Wallet

User's point balance and statistics

FieldTypeDescription
balancePointsbigintTotal points in wallet
frozenPointsbigintPoints held in escrow/trades
totalEarnedPointsbigintLifetime earned points
totalSpentPointsbigintLifetime spent points

WalletTransaction

Record of all point movements

FieldTypeDescription
typeenumTOPUP, TRANSFER, PURCHASE, PURCHASE_COMPLETE, REFUND, DONATION, MINT
statusenumPENDING, COMPLETED, FAILED, CANCELLED
amountbigintPoints transferred
senderUserSource user (null for system)
receiverUserDestination user

TopUp

Payment gateway top-up records

FieldTypeDescription
gatewayenumEDFAPAY, THAWANI, STRIPE
statusenumPENDING, COMPLETED, FAILED, EXPIRED
amountInCurrencybigintAmount in minor units (baisas)
pointsToCreditbigintPoints to add on success

Escrow

Buyer protection for order payments

FieldTypeDescription
statusenumHOLDING, RELEASED, REFUNDED
amountbigintFrozen points
expiresAttimestampAuto-refund deadline (carrier-set or 12h default)

Order (Escrow Fields)

Order entity fields related to escrow

FieldTypeDescription
escrowIduuidReference to escrow record (if paid with points)
escrowHoursint | nullCarrier-set escrow duration (1-168 hours, null = 12h default)

P2PTrade

Peer-to-peer point trading offers

FieldTypeDescription
statusenumOPEN, PENDING, APPROVED, COMPLETED, CANCELLED, EXPIRED
pointsAmountbigintPoints for sale
pricePerKnotintPrice in baisas (950-1000)
totalPricebigintTotal price in baisas

MintRequest

Merchant requests to mint new points

FieldTypeDescription
statusenumPENDING, PARTIALLY_APPROVED, APPROVED, REJECTED
requestedPointsbigintPoints to mint
justificationtextBusiness reason
approvedBy1/2UserTwo admins required
yearintFor annual limit tracking

Charity

Verified charity profiles for donations

FieldTypeDescription
statusenumPENDING, VERIFIED, SUSPENDED
slugstringURL-friendly unique ID
totalDonationsReceivedbigintCumulative donations
donorCountintNumber of donors

WithdrawalRequest

User requests to withdraw points to bank account

FieldTypeDescription
statusenumPENDING, PROCESSING, COMPLETED, REJECTED, CANCELLED
amountbigintPoints to withdraw
bankNamestringUser's bank name
accountNumberstringBank account number
accountHolderNamestringAccount holder name
ibanstringOptional IBAN
receiptImageUrltextAdmin's uploaded receipt
processedByUserAdmin who resolved
processedAttimestampWhen resolved
rejectionReasontextWhy rejected (if applicable)
currencyAmountbigintEquivalent in currency

WalletAuditLog

Audit trail for all wallet actions

FieldTypeDescription
actionenum40+ action types (topup, transfer, escrow, trade, mint, etc.)
severityenumINFO, WARNING, CRITICAL
pointsAmountbigintPoints involved
metadatajsonbAdditional context

πŸ“§ Email Notifications

Automatic email alerts for wallet events

Notification Events

All wallet actions trigger email notifications to relevant users

EventRecipientDescription
Top-Up InitiatedBuyerPayment process started
Top-Up CompletedBuyerPoints credited to wallet
Top-Up FailedBuyerPayment failed or expired
Transfer SentSenderPoints sent to another user
Transfer ReceivedReceiverPoints received from user
Escrow CreatedBuyerOrder payment held
Escrow ReleasedSellerPayment released after delivery
Escrow RefundedBuyerPayment refunded (cancel/timeout)
Trade CreatedSellerTrade offer listed
Trade RequestedSellerBuyer wants to purchase
Trade ApprovedBuyerSeller approved request
Trade CompletedBothPoints transferred
Trade CancelledBothTrade cancelled
Donation SentDonorThank you for donating
Donation ReceivedCharityNew donation alert
Mint ApprovedMerchantPoints minted to wallet
Mint RejectedMerchantRequest rejected with reason
Charity VerifiedOwnerCharity approved for donations
Withdrawal RequestedUserWithdrawal request submitted
Withdrawal Request (Admin)All AdminsNew withdrawal needs processing
Withdrawal CompletedUserBank transfer completed with receipt
Withdrawal RejectedUserRequest rejected, points restored
Security AlertUserSuspicious activity detected
πŸ“¬ Email Features
β€’ Beautiful responsive HTML templates
β€’ Color-coded amounts (green for credits, red for debits)
β€’ Transaction details and balances
β€’ Non-blocking async delivery
β€’ Branded headers with app name

πŸ“‹ Audit Logging

Comprehensive activity tracking for compliance and security

Audit Actions

All wallet operations are logged with full context

CategoryActions
Walletwallet_created
Top-Uptopup_initiated, topup_completed, topup_failed
Transfertransfer_sent, transfer_received
Escrowescrow_created, escrow_released, escrow_refunded, escrow_expired
P2P Tradetrade_created, trade_requested, trade_approved, trade_completed, trade_cancelled
Charitycharity_created, charity_verified, donation_sent, donation_received
Adminadmin_freeze, admin_unfreeze, admin_adjustment, admin_mint
Withdrawalwithdrawal_requested, withdrawal_completed, withdrawal_rejected, withdrawal_cancelled

Logged Information

  • User ID and action timestamp
  • Points amount and balance after
  • Related entity (topup, escrow, trade, etc.)
  • IP address and user agent
  • Admin who performed action (if applicable)
  • Custom metadata (JSON)
⚠️ Security Levels
β€’ INFO: Normal operations
β€’ WARNING: Minting, large transactions
β€’ CRITICAL: Admin actions, security events

βš™οΈ Configuration

Environment variables and system settings

Required Environment Variables

# SMTP Configuration (Email)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-username
SMTP_PASS=your-password
MAIL_FROM=Invare <support@invare.sa>

# App Settings
APP_NAME=Invare
SUPPORT_EMAIL=support@invare.sa

# EdfaPay Configuration
EDFAPAY_API_BASE=https://api.edfapay.com
EDFAPAY_MERCHANT_ID=your-merchant-id
EDFAPAY_PASSWORD=your-password
EDFAPAY_CURRENCY=OMR

System Constants

ConstantValueDescription
POINTS_PER_KNOT100Points per Knot (display unit)
DEFAULT_ESCROW_HOURS12Default hours before auto-refund (carrier can override per order)
ANNUAL_MINT_LIMIT1,000,000Max points per merchant/year
P2P_PRICE_MIN950Min baisas per Knot
P2P_PRICE_MAX1000Max baisas per Knot
MIN_DONATION100Minimum donation points

Scheduled Jobs

JobScheduleDescription
refundExpiredEscrowsEvery 5 minAuto-refund escrows past 12 hours
cleanupExpiredTopUpsDaily midnightMark pending top-ups as expired (24h)