Balance Query
Check your account balance.
Endpoint
GET /api/v1/business/balance
AI prompt — Balance Query
Paste into ChatGPT, Claude, Cursor, Copilot or any coding agent to generate this part of your integration. Built-in recommendation: Keep a local balance mirror from order responses; call at checkout (60 s cache) and from an hourly alert job — never poll.
Show prompt text (47 lines)
# eSIMfly Business API — Balance Query (GET /balance) — prompt for AI coding assistants
TASK: implement a balance check for the eSIMfly Business API and wire it into the app the way
described under INTEGRATION PATTERN. Do not poll this endpoint.
COMMON RULES (apply to every eSIMfly request)
- Base URL: https://esimfly.net/api/v1/business
- Headers on every call: RT-AccessCode (esf_...), RT-RequestID (fresh UUID v4 per request; reuse -> 400 DUPLICATE_REQUEST),
RT-Timestamp (ms since epoch; >5 min old -> 401 INVALID_TIMESTAMP),
RT-Signature = UPPERCASE hex HMAC-SHA256(secretKey, timestamp + requestId + accessCode + rawBody).
rawBody = "" for GET; for POST/PUT sign the exact body string you send, with Content-Type: application/json.
- Keep access code + secret key server-side in env vars. Never ship them to a browser or mobile app.
- Responses: { success: true, ... } or { success: false, error|message, code }. Branch on `success` and `code`.
- Rate limits are per API key, shown in the business dashboard (typically 100/minute, 1,000/hour, 10,000/day) -> RATE_LIMIT_EXCEEDED. Pace bulk work at <= 1 req/s.
- Read `currency` from responses (USD | IQD | EUR for enterprise). Never hard-code it. IQD amounts are integers.
- Package codes are opaque strings: store and send back verbatim, never parse or prefix them.
- Node.js/TypeScript: use the official SDK instead of raw HTTP — `npm install @esimfly/sdk`
(https://github.com/eSimfly-Official/esimfly-sdk-nodejs); it implements these rules. Other languages: implement the contract below.
- Full multi-endpoint prompt: https://docs.esimfly.net/llm/esimfly-api-full-prompt.txt
ENDPOINT
GET https://esimfly.net/api/v1/business/balance (no query params, no body)
RESPONSE 200
{ "success": true, "data": { "balance": 1500.00, "currency": "USD" } }
Enterprise accounts additionally return:
{ "source": "enterprise", "account": "Acme Telecom Ltd", "live": true, "as_of": "2026-09-12T08:24:36.107Z" }
and currency "EUR". Detect enterprise with data.source === "enterprise".
ERRORS: 401 INVALID_API_KEY / INVALID_SIGNATURE / HMAC_REQUIRED, 400 INVALID_REQUEST_ID / DUPLICATE_REQUEST /
INVALID_TIMESTAMP, 403 INVALID_USER, 500 "Failed to fetch balance".
INTEGRATION PATTERN (request budget: a handful of calls per day)
1. Keep a local balance mirror (table or cache key). Every Create Order and Topup Order response
contains `newBalance` — update the mirror from that; it is free.
2. Call GET /balance only:
- at checkout, to show "available funds" — cache the result for 60 seconds;
- from an hourly low-balance job that alerts you when balance < your threshold;
- after a manual top-up of your eSIMfly account, to refresh the mirror.
3. Never call it before every order to "pre-check" funds: the order endpoint itself returns
INSUFFICIENT_BALANCE with currentBalance / requiredBalance / needToLoad when funds are short.
4. Never call it in a loop, on every page view, or in a per-minute cron.
5. Format amounts using the returned `currency`; IQD has no decimals.
DELIVERABLE: a getBalance() function in the shared eSIMfly client, a cached wrapper (60 s TTL),
and the hourly low-balance alert job.
Authentication
This endpoint requires HMAC authentication. See Authentication for details.
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
| RT-AccessCode | String | Yes | Your API access code |
| RT-RequestID | String | Yes | Unique request ID (UUID v4) |
| RT-Timestamp | String | Yes | Request timestamp in milliseconds |
| RT-Signature | String | Yes | HMAC-SHA256 signature |
Response
Success Response (200 OK)
USD User Example:
{
"success": true,
"data": {
"balance": 1500.00,
"currency": "USD"
}
}
IQD User Example:
{
"success": true,
"data": {
"balance": 1980000,
"currency": "IQD"
}
}
Enterprise Account Example:
If your account is linked to an enterprise account, this endpoint returns your enterprise balance — the balance held on the network for your account — rather than a prepaid wallet. Orders and usage are billed against that balance.
{
"success": true,
"data": {
"balance": 4250.00,
"currency": "EUR",
"source": "enterprise",
"account": "Acme Telecom Ltd",
"live": true,
"as_of": "2026-09-12T08:24:36.107Z"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | Boolean | Request success status |
| data.balance | Number | Current account balance in the account's currency |
| data.currency | String | Currency code. USD or IQD for standard accounts, EUR for enterprise accounts |
| data.source | String | Only present for enterprise accounts, where it is "enterprise". Absent otherwise — use it to tell the two apart |
| data.account | String | Enterprise accounts only: the company name the balance belongs to |
| data.live | Boolean | Enterprise accounts only: true when read from the network just now, false when a recent cached value was used |
| data.as_of | String | Enterprise accounts only: ISO 8601 timestamp of the balance reading |
currency is not limited to USD and IQD. An enterprise account reports EUR.
Read the field rather than assuming which of the two it will be.
Examples
Node.js
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
async function checkBalance() {
const accessCode = 'esf_your_access_code';
const secretKey = 'sk_your_secret_key';
// Generate HMAC headers
const timestamp = Date.now().toString();
const requestId = uuidv4();
const signData = timestamp + requestId + accessCode;
const signature = crypto.createHmac('sha256', secretKey)
.update(signData)
.digest('hex')
.toUpperCase();
const response = await fetch('https://esimfly.net/api/v1/business/balance', {
headers: {
'RT-AccessCode': accessCode,
'RT-RequestID': requestId,
'RT-Timestamp': timestamp,
'RT-Signature': signature
}
});
const data = await response.json();
console.log('Current balance:', data.data.balance, data.data.currency);
}
Python
import hashlib
import hmac
import time
import uuid
import requests
def check_balance():
access_code = 'esf_your_access_code'
secret_key = 'sk_your_secret_key'
# Generate HMAC headers
timestamp = str(int(time.time() * 1000))
request_id = str(uuid.uuid4())
sign_data = timestamp + request_id + access_code
signature = hmac.new(
secret_key.encode('utf-8'),
sign_data.encode('utf-8'),
hashlib.sha256
).hexdigest().upper()
headers = {
'RT-AccessCode': access_code,
'RT-RequestID': request_id,
'RT-Timestamp': timestamp,
'RT-Signature': signature
}
response = requests.get(
'https://esimfly.net/api/v1/business/balance',
headers=headers
)
data = response.json()
print(f"Current balance: {data['data']['balance']} {data['data']['currency']}")
PHP
function checkBalance() {
$accessCode = 'esf_your_access_code';
$secretKey = 'sk_your_secret_key';
// Generate HMAC headers
$timestamp = (string)(time() * 1000);
$requestId = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(random_bytes(16)), 4));
$signData = $timestamp . $requestId . $accessCode;
$signature = strtoupper(hash_hmac('sha256', $signData, $secretKey));
$headers = [
'RT-AccessCode: ' . $accessCode,
'RT-RequestID: ' . $requestId,
'RT-Timestamp: ' . $timestamp,
'RT-Signature: ' . $signature
];
$ch = curl_init('https://esimfly.net/api/v1/business/balance');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
echo "Current balance: " . $data['data']['balance'] . " " . $data['data']['currency'];
}
Error Responses
400 Bad Request
Invalid request ID format:
{
"success": false,
"error": "Invalid or missing RT-RequestID header. Must be a valid UUID v4.",
"code": "INVALID_REQUEST_ID"
}
Duplicate request ID (replay attack prevention):
{
"success": false,
"error": "Request ID has already been used",
"code": "DUPLICATE_REQUEST"
}
401 Unauthorized
Missing authentication:
{
"success": false,
"error": "Authentication required",
"message": "Please provide either Bearer token or complete HMAC signature authentication"
}
Invalid API key:
{
"success": false,
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}
Invalid HMAC signature:
{
"success": false,
"error": "Invalid HMAC signature",
"code": "INVALID_SIGNATURE"
}
Incomplete HMAC authentication:
{
"success": false,
"error": "HMAC signature authentication required",
"message": "Missing required headers: RT-Signature, RT-Timestamp, and RT-RequestID are mandatory when using RT-AccessCode",
"code": "HMAC_REQUIRED"
}
Token expired (JWT auth):
{
"success": false,
"message": "Token not found or expired"
}
Invalid token (JWT auth):
{
"success": false,
"message": "Invalid token"
}
403 Forbidden
Not a business account:
{
"success": false,
"error": "Invalid user or not a business account",
"code": "INVALID_USER"
}
404 Not Found
User not found:
{
"success": false,
"error": "User not found"
}
500 Internal Server Error
{
"success": false,
"error": "Failed to fetch balance"
}
Rate Limiting
This endpoint is subject to the standard rate limit of 1000 requests per hour. Rate limit information is included in response headers:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Time when the limit resets
Notes
- Balance is returned in the account currency (
USD,IQD, orEURfor enterprise accounts) - Currency preference can be set in the business dashboard settings
- This endpoint returns real-time balance information from the multi-currency wallet system
- Use this endpoint to verify funds before placing orders
- IQD balances are shown as whole numbers (no decimals)
- USD balances are shown with 2 decimal places