Top up an eSIM
Add a topup package to an eSIM of your agency and debit your agency balance (live only).
/api/v1/esims/topupsCall GET / first and send one of its package_id values: a package that was not returned for this eSIM is refused. email and phone are required and kept on the booking; the email is not sent to the supplier on a topup. The ICCID must be an eSIM that your agency ordered.
The same rules as for an order apply: JSON body, server-side prices, no idempotency key, duplicate_request while the same topup is running or (live) when a topup of the same ICCID was confirmed in the last 60 seconds. If the supplier refuses the topup nothing is debited and a failed booking is saved. The sandbox debits nothing, returns a balance of 0.0, and adds the balanceDebited, transactionCreated and payoutCreated flags.
The booking of a topup is listed by GET /, not by GET /.
curl https://api.fx-port.com/api/v1/esims/topups \
-H "Authorization: Bearer fxp_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"package_id": "france-in-7days-1gb-topup",
"iccid": "8900000540463077957",
"first_name": "John",
"last_name": "Smith",
"email": "[email protected]",
"phone": "+15555550123"
}'{
"environment": "sandbox",
"success": true,
"data": {
"topup": {
"code": "20261101-106853",
"order_id": "20261101-106853",
"package_id": "france-in-7days-1gb-topup",
"package": "KPN France Data only-1 GB - 7 days",
"data": "1 GB",
"validity": 7,
"price": 468.84,
"currency": "DZD",
"total_price": 468.84,
"retail_price": 468.84,
"agency_currency": "DZD",
"supplier_currency": "USD",
"exchange_rate": 250
},
"iccid": "8900000540463077957",
"balance": {
"previous": 0,
"current": 0,
"currency": "DZD"
}
},
"booking_id": "FX-1793546625391",
"message": "eSIM topup completed successfully",
"balanceDebited": false,
"balance_debited": false,
"transactionCreated": false,
"transaction_created": false,
"payoutCreated": false,
"payout_created": false
}Request
Body
Required, JSON.
package_idstringrequiredThe id of a topup package returned for this ICCID by the topup packages endpoint (its package_id).
At most 128 characters.
iccidstringrequiredThe ICCID of the eSIM to top up: 18 to 22 digits, which may be written in groups of spaces or hyphens (8944 4654 0000 0123 456). It must be an eSIM that your agency ordered.
emailstringrequiredThe traveler's email address. Kept on the booking: it is not sent to the supplier on a topup.
At most 254 characters.
phonestringrequiredThe traveler's phone number: at least 3 digits. Kept on the booking.
At most 32 characters.
first_namestringThe traveler's first name. Any characters are accepted.
At most 100 characters.
last_namestringThe traveler's last name. Any characters are accepted.
At most 100 characters.
agent_idstring (uuid)The id of the user of your agency who places the topup. Optional. A user of another agency is refused.
user_idstring (uuid)deprecatedLegacy name, still accepted. Use agent_id instead.
Previous name of agent_id.
customer_emailstringdeprecatedLegacy name, still accepted. Use email instead.
The name the booking rows use for email. Still accepted.
customer_phonestringdeprecatedLegacy name, still accepted. Use phone instead.
The name the booking rows use for phone. Still accepted.
customer_first_namestringdeprecatedLegacy name, still accepted. Use first_name instead.
The name the booking rows use for first_name. Still accepted.
customer_last_namestringdeprecatedLegacy name, still accepted. Use last_name instead.
The name the booking rows use for last_name. Still accepted.
Response
200The topup was applied. The response has status 200, not 201.
successbooleantrue when the topup was applied.
dataobjectThe topup, the ICCID and the balance change.
ShowHide 3 attributes
topupobjectThe topup, with the amounts in your agency currency.
ShowHide 13 attributes
codestringdeprecatedLegacy name, still accepted. Use order_id instead.
The supplier's order code of the topup. Booking rows call it order_id. The older name of order_id: same value, use order_id.
order_idstringThe supplier's order code of the topup. Booking rows call it order_id. The snake_case twin of code, with the same value: use this name.
package_idstringThe topup package that was bought.
packagestringName of the topup package.
datastringData allowance added, as text.
validityintegerValidity of the topup in days.
pricenumberWhat the traveler pays, in your agency currency. Equal to total_price here (in the catalog, price is a different amount: see the pricing guide).
currencystringCurrency of the amounts: the settlement currency of your agency.
total_pricenumberThe price to charge the traveler, in your agency currency. Your commission is total_price minus the amount debited from your balance.
retail_pricenumberThe price to charge the traveler, in your agency currency. Your commission is total_price minus the amount debited from your balance. Another name of total_price, with the same value.
agency_currencystringSame as currency.
supplier_currencystringCurrency the supplier prices the package in.
exchange_ratenumberRate used to convert supplier_currency to your agency currency.
iccidstringThe ICCID that was topped up.
balanceobjectThe agency balance around the topup.
ShowHide 3 attributes
previousnumberAgency balance in this currency before the topup. Always 0.0 in the sandbox.
currentnumberAgency balance after the topup. Always 0.0 in the sandbox.
currencystringCurrency of the balance.
booking_idstringThe FX-Port booking reference of the topup, FX- followed by a number.
messagestringA confirmation sentence.
balanceDebitedbooleandeprecatedLegacy name, still accepted. Use balance_debited instead.
Sandbox only, always false: no balance was debited. The older name of balance_debited: same value, use balance_debited.
balance_debitedbooleanSandbox only, always false: no balance was debited. The snake_case twin of balanceDebited, with the same value: use this name.
transactionCreatedbooleandeprecatedLegacy name, still accepted. Use transaction_created instead.
Sandbox only, always false: no balance transaction was created. The older name of transaction_created: same value, use transaction_created.
transaction_createdbooleanSandbox only, always false: no balance transaction was created. The snake_case twin of transactionCreated, with the same value: use this name.
payoutCreatedbooleandeprecatedLegacy name, still accepted. Use payout_created instead.
Sandbox only, always false: no supplier payout was created. The older name of payout_created: same value, use payout_created.
payout_createdbooleanSandbox only, always false: no supplier payout was created. The snake_case twin of payoutCreated, with the same value: use this name.
Errors
| Status | Code | Example message |
|---|---|---|
| 400 | missing_field | package_id and iccid are required |
| 400 | invalid_iccid | iccid must be 18-22 digits (received '123'). |
| 402 | insufficient_balance | Agency balance is insufficient. Available: 300.0 DZD, Required: 418.6 DZD. |
| 403 | read_write_permission_required | This endpoint requires an API key with read_write permission. |
| 404 | iccid_not_found | No eSIM with this ICCID was found for your account. |
| 404 | not_found | Package no-such-topup not found or has no valid price |
| 409 | duplicate_request | A duplicate topup was detected for this eSIM. If intentional, please wait 60 seconds before retrying. |
| 429 | rate_limit_exceeded | Too many requests hit the API too quickly. Please retry your request after the time specified in the `ratelimit-reset` header. |
| 429 | concurrency_limit_exceeded | Too many requests of this kind are already running for this API key; wait for one to finish and retry. |
| 503 | service_unavailable | Airalo token unavailable |
The shape of the error body depends on the endpoint. See Errors for every shape and code.