API ReferenceeSIM

Charges

Calculate the exact payable amount for an eSIM plan before placing the order

POST /api/v1/esim/charges

Resolves the matching variant for the given product_id + amount and returns the full price breakdown — same shape as the topup charges and voucher charges endpoints, so a single client implementation works across all three verticals.

eSIM orders are always one-at-a-time. There is no quantity in the request and no max_quantity in the response. eSIM plans are fixed-denomination, so amount must match one of the values exposed on /esim/products/:id/variants.

Cross-currency wallets are supported. Pass wallet_id to bill a specific wallet; when its currency differs from the variant's, Octopus Cards looks up an admin-managed forex rate and the response carries net_amount / handling_fee_amount / forex_rate / conversion_fee in the wallet currency. If wallet_id is omitted, Octopus Cards picks a wallet in the variant currency, falling back to your default-currency wallet.

Request

curl -X POST "https://api.octopuscards.io/api/v1/esim/charges" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": 712,
    "amount": 4.50
  }'

Request Parameters

KeyTypeRequiredDescription
product_idintegerYeseSIM product to price. Must be > 0.
amountnumberYesVariant price in the product's currency. Must match an amount value from /esim/products/:id/variants — eSIM plans are fixed-denomination.
wallet_idintegerNoWallet to bill. When supplied and its currency differs from the variant's, the response is FX-converted into the wallet currency. Omit to use the variant-currency wallet (or your default-currency wallet as fallback).

There is no quantity field — eSIM orders are always 1 per order.

Response

Same-currency wallet (no FX):

{
  "non_discounted_total": 4.50,
  "discount_amount": 0.225,
  "total_amount": 4.275,
  "discount": 5.0,
  "total_payable": 4.275,
  "charges_details": {
    "source_currency": "USD",
    "destination_currency": "USD"
  }
}

Cross-currency wallet (e.g. USD variant billed to an INR wallet):

{
  "non_discounted_total": 4.50,
  "discount_amount": 0.225,
  "total_amount": 4.275,
  "discount": 5.0,
  "net_amount": 357.0,
  "handling_fee_amount": 0.0,
  "total_payable": 357.0,
  "charges_details": {
    "source_currency": "USD",
    "destination_currency": "INR",
    "forex_rate": 83.51,
    "conversion_fee": 0.0
  }
}

Response Fields

KeyTypeDescription
non_discounted_totalnumberVariant amount before discount, in source_currency.
discount_amountnumberAbsolute discount applied, in source_currency.
total_amountnumberPost-discount net in source_currency (non_discounted_total − discount_amount).
discountnumberClient discount percentage (e.g. 5.0 means 5%). Configured per client/variant on client_esim_variants; defaults to 0 when no mapping exists.
net_amountnumber, omitemptyPresent only when source ≠ destination currency. total_amount × forex_rate — the post-FX amount before the conversion fee.
handling_fee_amountnumber, omitemptyPresent only when source ≠ destination currency. net_amount × conversion_fee%. Currently always 0 (placeholder).
total_payablenumberFinal amount you'll be charged in destination_currency. Equals total_amount when no FX, or net_amount + handling_fee_amount when cross-currency.
charges_details.source_currencystringISO 4217 currency of the variant.
charges_details.destination_currencystringISO 4217 currency you'll be billed in. Equals source_currency when no FX.
charges_details.forex_ratenumber, omitemptyAdmin-managed rate used for the conversion (source → destination). Present only when source ≠ destination.
charges_details.conversion_feenumber, omitemptyConversion-fee percentage applied on top of FX. Present only when source ≠ destination. Currently 0.

No max_quantity — eSIM orders are 1-at-a-time. Variant-routing internals are intentionally not surfaced.

Cross-currency FX requires an admin-managed rate in the forex_values table for the source → destination pair. If none exists, the request rejects with 400 "Exchange rate not available for the wallet currency".

Errors

400 Bad Requestproduct_id or amount missing or invalid.

{
  "error": {
    "name": "ValidationException",
    "code": "VALIDATION_FAILURE",
    "message": "Product ID is required"
  }
}

Other validation messages: "Amount is required".

On this page