Flexible position details, including the portion not yet accruing
x-on-behalf-of required
GET /v1/earn/positions returns only total principal. This endpoint adds pending_principal, the portion that has not begun accruing interest.
It answers one of the most common support questions: “I deposited yesterday; why is there no return today?” Without it, you can only say the system is calculating.
It is calculated live from the step table, not a stored column. pending_value_at is the earliest pending accrual-start time; an empty string means all principal is accruing.
⚠ pending_principal is a subset already included in principal, not an additional amount.
⚠ Flexible redemption is LIFO, consuming non-accruing principal first. This number therefore also identifies the amount redeemable now without losing any accrued interest.
pending_interest is accrued but unpaid; paid_interest has already reached available balance.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Required | Position ID, with or without erp_. |
Request Headers
| Field | Type | Required | Description |
|---|---|---|---|
x-on-behalf-of |
string | Required |
Response
{
"id": "erp_7c1e",
"product_id": "ern_8c1d",
"asset": "USDT",
"ledger_scale": 6,
"display_scale": 2,
"apr": "3.50%",
"settle_cycle": "daily",
"principal": "1500.000000",
"pending_principal": "500.000000",
"pending_value_at": "2026-08-15T00:00:00.000Z",
"pending_interest": "0.410958",
"paid_interest": "12.300000",
"status": "active",
"opened_at": "2026-07-01T08:12:00.000Z"
}not_found: position nonexistent or not owned by this member/merchantcurl -X GET 'https://api.zinfra.vip/v1/earn/positions/{id}' \
-H 'x-auth-token: Bearer $TOKEN' \
-H 'x-on-behalf-of: $MEMBER_ID'const res = await fetch("https://api.zinfra.vip/v1/earn/positions/{id}", {
method: "GET",
headers: {
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
},
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();import requests
res = requests.get(
"https://api.zinfra.vip/v1/earn/positions/{id}",
headers={
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
},
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()req, _ := http.NewRequest("GET", "https://api.zinfra.vip/v1/earn/positions/{id}",
nil)
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
res, err := http.DefaultClient.Do(req)
// Decode amount fields as string, not float64.HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.zinfra.vip/v1/earn/positions/{id}"))
.header("x-auth-token", "Bearer $TOKEN")
.header("x-on-behalf-of", "$MEMBER_ID")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
// Use String / BigDecimal for amounts, not double.$ch = curl_init('https://api.zinfra.vip/v1/earn/positions/{id}');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'x-auth-token: Bearer $TOKEN',
'x-on-behalf-of: $MEMBER_ID',
],
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
{
"id": "erp_7c1e",
"product_id": "ern_8c1d",
"asset": "USDT",
"ledger_scale": 6,
"display_scale": 2,
"apr": "3.50%",
"settle_cycle": "daily",
"principal": "1500.000000",
"pending_principal": "500.000000",
"pending_value_at": "2026-08-15T00:00:00.000Z",
"pending_interest": "0.410958",
"paid_interest": "12.300000",
"status": "active",
"opened_at": "2026-07-01T08:12:00.000Z"
}