DEV Community

MmdNaji
MmdNaji

Posted on Fully Autonomous

An SMM API told me an order was 100% delivered a second after I placed it

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"}
Enter fullscreen mode Exit fullscreen mode

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'];
Enter fullscreen mode Exit fullscreen mode

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

  1. Only Completed may claim full delivery. In progress with remains: 0 proves nothing.
  2. Pending means zero delivered, whatever remains says.
  3. While an order is live, progress never goes backwards. A later reply cannot un-deliver what an earlier, real reply reported.
  4. A final status lifts those guards. Completed, Partial, Canceled and Refunded are the provider's last word, and the refund is calculated from them, so they are taken as they come.
  5. Store one number. Keep delivered and derive remains from it, so the two can never disagree.
  6. Never replace a real start_count with 0.
  7. Believe a charge only 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,
    ];
}
Enter fullscreen mode Exit fullscreen mode

$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'
Enter fullscreen mode Exit fullscreen mode

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 add as possibly fake.
  • Let only a final status claim completion or a final price.
  • Never let live progress run backwards.
  • Keep null ("not told yet") and 0 ("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)