I work on the order routing of an SMM panel. A customer orders, say, 5,000 Telegram post views; we pass the order to an upstream provider over the standard SMM API v2 (action=add), then poll action=status every couple of minutes until the order settles.
During a test with real orders, one order showed 100% delivered about a second after it was sent. On the next poll it showed 0%. Nothing had been delivered either time.
What the API actually returned
These are the first two status replies to that order, exactly as they arrived (only the provider's order id is replaced):
+10s {"charge":"0","order":"1234567","remains":0,"start_count":0,"status":"In progress"}
+30s {"charge":"0.0125","order":"1234567","remains":"5000","start_count":"0","status":"In progress"}
The first reply is a placeholder. The provider had not registered the order yet and answered with zeros. Read literally, though, it says three things:
-
remains: 0: nothing is left, so everything was delivered; -
start_count: 0: the counter started from zero; -
charge: "0": the order cost nothing.
None of that is true, and twenty seconds later the same provider said so. We saw the same shape from two different upstream providers and on two different service types, so this is not one provider's bug. It is simply what these APIs do while an order is still being registered. Note also that remains arrives as an integer in one reply and as a string in the next.
The naive code
$delivered = $order['quantity'] - (int)$reply['remains'];
$cost = (float)$reply['charge'];
It is the obvious way to write it, and the placeholder breaks it in three ways.
1. The customer sees progress jump. 100% one second after ordering, then back to 0%. To a customer that looks broken.
2. A fallback chain silently stops. Some of our services are routed through several providers in sequence: if provider A delivers only part of an order, the rest goes to provider B. "How much is still owed" is quantity - delivered, and with the placeholder that is zero. So the router decides the order is complete and never opens the second leg. Nothing throws and nothing logs an error; the order simply ends up short.
3. Your margin is wrong. We compute cost from the charge the provider returns, not from a price list, because a price list goes stale and a cancel costs nothing. A placeholder "0" reads as "this order was free".
The rules that fixed it
-
Only
Completedmay claim full delivery.In progresswithremains: 0proves nothing. -
Pendingmeans zero delivered, whateverremainssays. - While an order is live, progress never goes backwards. A later reply cannot un-deliver what an earlier, real reply reported.
-
A final status lifts those guards.
Completed,Partial,CanceledandRefundedare the provider's last word, and the refund is calculated from them, so they are taken as they come. -
Store one number. Keep
deliveredand deriveremainsfrom it, so the two can never disagree. - Never replace a real
start_countwith0. -
Believe a
chargeonly when it is above zero or the status is final. Keep "the provider has not told us yet" (null) separate from "the provider told us it was free" ("0"). A canceled order really does cost 0.
The code
<?php
const FINAL_STATUSES = ['Completed', 'Partial', 'Canceled', 'Refunded'];
function apply_status(array $leg, array $reply): array
{
$status = (string)($reply['status'] ?? $leg['status']);
$final = in_array($status, FINAL_STATUSES, true);
$qty = (int)$leg['quantity'];
$remains = isset($reply['remains']) && is_numeric($reply['remains'])
? max(0, min($qty, (int)$reply['remains']))
: $qty;
if ($status === 'Pending') {
$delivered = 0; // nothing has started
} elseif ($status === 'Completed') {
$delivered = $qty; // the only status allowed to claim everything
} else {
$delivered = $qty - $remains;
if (!$final && $delivered >= $qty) {
$delivered = (int)$leg['delivered']; // "In progress" + remains 0 = placeholder
}
}
if (!$final) {
$delivered = max($delivered, (int)$leg['delivered']); // never run backwards while live
}
$start = $leg['start_count'];
if (isset($reply['start_count']) && is_numeric($reply['start_count'])) {
$s = (int)$reply['start_count'];
if ($s > 0 || $start === null) $start = $s; // never replace a real count with 0
}
$charge = $leg['charge']; // null = the provider has not said yet
if (isset($reply['charge']) && is_numeric($reply['charge'])) {
if ((float)$reply['charge'] > 0 || $final) {
$charge = (string)$reply['charge']; // "0" mid-flight is a placeholder; on a cancel it is real
}
}
return [
'quantity' => $qty,
'status' => $status,
'delivered' => $delivered,
'remains' => $qty - $delivered, // derived, so the two can never disagree
'start_count' => $start,
'charge' => $charge,
];
}
$leg is whatever you already know about the order: its quantity, last status, delivered count, start count and charge. The function never trusts a single reply on its own; it merges the reply into that state.
Test it with the replies you actually recorded
The cheapest test you can write for this is a replay. Save the raw replies your providers really send, in order, and assert what your code makes of each one:
$leg = ['quantity' => 5000, 'status' => 'Pending', 'delivered' => 0,
'start_count' => null, 'charge' => null];
$replies = [
['charge' => '0', 'remains' => 0, 'start_count' => 0, 'status' => 'In progress'],
['charge' => '0.0125', 'remains' => '5000', 'start_count' => '0', 'status' => 'In progress'],
['charge' => '0.0125', 'remains' => '0', 'start_count' => '812', 'status' => 'Completed'],
];
foreach ($replies as $reply) {
$leg = apply_status($leg, $reply);
echo "{$leg['delivered']} delivered, charge ", var_export($leg['charge'], true), "\n";
}
// 0 delivered, charge NULL <- the placeholder changes nothing
// 0 delivered, charge '0.0125'
// 5000 delivered, charge '0.0125'
The first two replies are the recorded ones; the third is an illustrative final reply. With the naive code, the first line would have read "5000 delivered, charge 0".
Add a canceled order (remains equal to the quantity, charge "0") and a Partial that the provider re-prices downward, and you have covered every case that bit us.
Checklist
- Treat the first status reply after
addas possibly fake. - Let only a final status claim completion or a final price.
- Never let live progress run backwards.
- Keep
null("not told yet") and0("told: free") apart. - Parse numbers defensively: the same field arrives as an int and as a string.
- Replay real recorded replies in your tests, not hand-written ideal ones.
Disclosure: I run TGLUX, a Telegram SMM provider, and these rules came out of building its order routing. The status format above is the standard SMM API v2 one; our reference for it is at https://smmtglux.com/api-docs.
Top comments (0)