Skip to content

Top up an eSIM

POST
/esims/topup
curl --request POST \
--url 'https://api.roamex.com/v1/esims/topup?lang=nl' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: topup-2026-10-22-0001' \
--data '{ "esimId": "00000000-0000-4000-8000-0000000000c1", "packageId": "pkg_EXAMPLE.TOKEN.VALUE" }'

Adds a top-up package to an existing eSIM and pays from your balance. The traveller keeps the same eSIM. packageId must be an id from /esims/topup-options.

lang
string
default: en

Language of plan and destination names in the response: en, nl, es, de, it, fr, pl, pt, tr, el, cs or ro. Any other value, or none, gives English. It never changes which items are returned or any figure.

Example

nl
Idempotency-Key
string

Makes retries safe. The key is combined with your account, the eSIM and the package. A repeat is answered with a 409 and is not charged again: DUPLICATE_REQUEST once the top-up was applied, ORDER_IN_PROGRESS while it is open, ORDER_TERMINAL when it failed. Without this header, a repeat of the same top-up within 60 seconds, or while the first is still open, is answered the same way.

Example

topup-2026-10-22-0001
Media typeapplication/json
object
esimId
required
string format: uuid
packageId
required

A package id from /esims/topup-options.

string
/^pkg_/

Example

{
"esimId": "00000000-0000-4000-8000-0000000000c1",
"packageId": "pkg_EXAMPLE.TOKEN.VALUE"
}

The top-up was applied.

Media typeapplication/json
object
success
required
boolean
topup
required
object
package
required
object
id
required

A fresh package token. It is not the same string you sent.

string
name
required
string
data
required
object
bytes
required

0 when unknown.

integer
formatted
required

Two decimals in GB, whole numbers in MB and KB, 0 B when unknown.

string
validity
required
object
days
required
integer | null
unit
required
string
cost
required

What your balance was charged.

object
amount
required

Euro cents.

integer
currency
required
string
Allowed values: EUR
formatted
required
string
newBalance
required
object
amount
required

Euro cents.

integer
currency
required
string
Allowed values: EUR
formatted
required
string

Example

{
"success": true,
"topup": {
"package": {
"id": "pkg_EXAMPLE.TOKEN.OTHER",
"name": "Japan · 1 GB · 7 days",
"data": {
"bytes": 1073741824,
"formatted": "1.00 GB"
},
"validity": {
"days": 7,
"unit": "DAY"
}
},
"cost": {
"amount": 450,
"currency": "EUR",
"formatted": "€4.50"
}
},
"newBalance": {
"amount": 23650,
"currency": "EUR",
"formatted": "€236.50"
}
}
X-RateLimit-Limit
integer

Calls allowed per minute for this endpoint group.

X-RateLimit-Remaining
integer

Calls left in the current minute.

X-RateLimit-Reset
integer

When the current window ends, in Unix seconds.

  • INVALID_JSON: the body is missing or not a JSON object.
  • MISSING_ESIM_ID: esimId is missing or not a string.
  • MISSING_PACKAGE_ID: packageId is missing or not a string.
  • INVALID_PACKAGE_ID: packageId is not a token from /esims/topup-options, or it was altered.
  • ESIM_CANCELLED: the eSIM is cancelled.
  • ESIM_NOT_READY: the eSIM is not provisioned yet.
  • NO_TOPUP_OPTIONS: top-ups are not available for this eSIM.
  • INVALID_PACKAGE: the package is not available for this eSIM.
  • UNSUPPORTED_PACKAGE: the package is a day-pass extension, which the API does not sell.
  • INSUFFICIENT_BALANCE: your balance does not cover the top-up. Nothing was charged.
  • TOPUP_FAILED: the top-up was refused and no data was added.
Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}

AUTH_ERROR: the key is missing, malformed, unknown or revoked. The message says which, for example Missing Authorization header, Invalid Authorization header format. Use: Bearer <api_key>, Invalid API key format or Invalid API key.

Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false,
"error": {
"code": "AUTH_ERROR",
"message": "Invalid API key"
}
}
  • DESTINATION_NOT_ALLOWED: the eSIM’s destination is not on your account’s list of allowed destinations.
  • SPEND_CAP_EXCEEDED: the top-up would take you over your account’s monthly spend limit.
  • TRIAL_RESTRICTED: trial accounts cannot top up.
  • AUTH_ERROR: the account is suspended or not approved.
Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}
  • ESIM_NOT_FOUND: no eSIM with this id belongs to your account.
  • NOT_FOUND: the API is switched off on the platform.
Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}
  • ESIM_EXPIRED: the eSIM’s validity has ended.
  • TOPUP_LIMIT_REACHED: the eSIM already has 9 top-ups, the most it accepts. Order a new eSIM instead.
  • ORDER_IN_PROGRESS: an identical top-up, or an earlier top-up on this eSIM, has not finished. /esims/details shows the data grow when it lands, and the esim.topped_up event arrives by webhook and in /events/recent.
  • DUPLICATE_REQUEST: this top-up was already submitted.
  • ORDER_TERMINAL: the earlier identical request failed and applied no data.
Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}

PAYLOAD_TOO_LARGE: the Content-Length header is over 100 KB.

Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}

RATE_LIMITED: the account’s per-minute budget for this endpoint group is used up, or too many refused keys came from this IP address. Wait the Retry-After seconds.

Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Please wait 42 seconds before retrying."
}
}
X-RateLimit-Limit
integer

Calls allowed per minute for this endpoint group.

X-RateLimit-Remaining
integer

Calls left in the current minute.

X-RateLimit-Reset
integer

When the current window ends, in Unix seconds.

Retry-After
integer

Seconds to wait before retrying.

  • TOPUP_FAILED: the top-up could not be processed, or it may have been applied but not recorded. The message says which. Check the eSIM with /esims/details before retrying.
  • INTERNAL_ERROR, or AUTH_ERROR with status 500: see the shared errors.
Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}
  • TOPUP_OUTCOME_UNKNOWN: the top-up was sent but no answer came back. Your balance stays charged while the eSIM is checked, and the charge is returned if the data did not arrive.
Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}

Transient. Your balance is not charged for these.

  • PURCHASES_PAUSED: purchases are paused. Retry after the Retry-After seconds.
  • TOPUP_OPTIONS_UNAVAILABLE: the top-up options could not be loaded.
  • PRICING_UNAVAILABLE: your account pricing could not be confirmed.
Media typeapplication/json
object
success
required
boolean
error
required
object
code
required

Machine-readable. Branch on this.

string
message
required

A sentence for people. It can change.

string

Example

{
"success": false
}
Retry-After
integer

Seconds to wait. Sent with PURCHASES_PAUSED (300).