Charges
Calculate exact pricing for a product before placing an order
POST /api/v1/products/:id/charges
Calculate the exact cost of an order before placing it. Returns the breakdown including face value, discount, FX conversion (if applicable), and the final amount that will be deducted from your wallet.
Always call this endpoint before creating an order. It gives you the exact amount that will be charged, including any FX conversion fees. The response is cached for 5 minutes per unique combination of product, denomination, quantity, and wallet.
Request
curl -X POST "{{host}}/api/v1/products/123/charges" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"denomination": 50.00,
"quantity": 5,
"wallet_id": 1
}'package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type ChargesRequest struct {
Denomination float64 `json:"denomination"`
Quantity int `json:"quantity"`
WalletID *int `json:"wallet_id,omitempty"`
}
type ChargesDetails struct {
SourceCurrency string `json:"source_currency"`
DestinationCurrency string `json:"destination_currency"`
ForexRate *float64 `json:"forex_rate"`
ConversionFee *float64 `json:"conversion_fee"`
}
type ChargesResponse struct {
NonDiscountedTotal float64 `json:"non_discounted_total"`
DiscountAmount float64 `json:"discount_amount"`
TotalAmount float64 `json:"total_amount"`
Discount float64 `json:"discount"`
GSTAmount float64 `json:"gst_amount"`
TotalPayable float64 `json:"total_payable"`
MaxQuantity int `json:"max_quantity"`
NetAmount *float64 `json:"net_amount"`
HandlingFeeAmount *float64 `json:"handling_fee_amount"`
ChargesDetails ChargesDetails `json:"charges_details"`
}
func main() {
walletID := 1
body, _ := json.Marshal(ChargesRequest{
Denomination: 50.00,
Quantity: 5,
WalletID: &walletID,
})
req, _ := http.NewRequest("POST", "{{host}}/api/v1/products/123/charges", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var charges ChargesResponse
json.NewDecoder(resp.Body).Decode(&charges)
fmt.Printf("Subtotal: %.2f\n", charges.NonDiscountedTotal)
fmt.Printf("Discount: -%.2f (%.1f%%)\n", charges.DiscountAmount, charges.Discount)
fmt.Printf("Payable: %.2f\n", charges.TotalPayable)
}Request Parameters
| Key | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | Product ID (path parameter) |
denomination | number | Yes | Face value of the product. Must be between 0.01 and 1,000,000,000. Must fall within an available denomination range. |
quantity | integer | Yes | Number of vouchers. Must be at least 1 and not exceed your client's bulk limit. |
wallet_id | integer | No | Wallet to debit from. If omitted, the platform uses your wallet matching the product's currency. Required when paying with a different currency (triggers FX conversion). |
Response
{
"non_discounted_total": 250.00,
"discount_amount": 8.75,
"total_amount": 241.25,
"discount": 3.5,
"gst_amount": 0.00,
"total_payable": 241.25,
"max_quantity": 100,
"net_amount": 241.25,
"handling_fee_amount": 0.00,
"charges_details": {
"source_currency": "USD",
"destination_currency": "USD",
"forex_rate": null,
"conversion_fee": null
}
}With FX conversion (e.g. paying from EUR wallet for a USD product):
{
"non_discounted_total": 250.00,
"discount_amount": 8.75,
"total_amount": 241.25,
"discount": 3.5,
"gst_amount": 0.00,
"total_payable": 222.81,
"max_quantity": 100,
"net_amount": 222.81,
"handling_fee_amount": 0.50,
"charges_details": {
"source_currency": "EUR",
"destination_currency": "USD",
"forex_rate": 0.9210,
"conversion_fee": 0.50
}
}Response Fields
| Key | Type | Description |
|---|---|---|
non_discounted_total | number | Face value × quantity (before discount) |
discount_amount | number | Total discount applied |
total_amount | number | Amount after discount (before FX conversion) |
discount | number | Discount percentage applied |
gst_amount | number | Tax amount (if applicable) |
total_payable | number | Final amount deducted from your wallet (after FX + fees) |
max_quantity | integer | Maximum units you can order for this product |
net_amount | number or null | Net amount after all adjustments |
handling_fee_amount | number or null | Handling fee (if applicable) |
charges_details.source_currency | string | Your wallet's currency |
charges_details.destination_currency | string | The product's currency |
charges_details.forex_rate | number or null | FX rate applied (null if same currency) |
charges_details.conversion_fee | number or null | FX conversion fee (null if same currency) |
Pricing Calculation
non_discounted_total = denomination × quantity
discount_amount = non_discounted_total × (discount / 100)
total_amount = non_discounted_total − discount_amount
total_payable = (total_amount × forex_rate) + conversion_fee + handling_feeErrors
400 Bad Request — Product ID is not valid.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Invalid product ID"
}
}400 Bad Request — Denomination is outside the available range.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Denomination not available"
}
}Ensure the denomination falls within one of the product's available_denominations ranges.
400 Bad Request — Quantity exceeds your client's bulk limit.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Quantity exceeds maximum"
}
}Check the max_quantity field in the response to see your limit.
400 Bad Request — The specified wallet does not exist or you have no wallet in the product's currency.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Appropriate wallet not found"
}
}404 Not Found — Product does not exist or is blacklisted.
{
"error": {
"name": "NotFoundError",
"code": "NOT_FOUND",
"message": "Product not found"
}
}