WebSocket API: Receiving stale/old LTT data for active instruments(PHP)

API/WebSocket Issue
Hello Upstox Developer Team,

We are using the WebSocket feed for real-time data, specifically subscribing to instruments like NSE_FO|62401. However, despite trades actively happening on these instruments (confirmed via the terminal), we are receiving LTT values from previous days.

Example:

  • Instrument: NSE_FO|62401
  • Received LTP: 153.9
  • Received LTT: 2025-06-20 15:29:59
  • Received At: 2025-06-23 11:05:18
  • Difference: ~243318 seconds

This stale LTT is causing us to skip live ticks. Even after reconnecting and resubscribing, the issue persists.

Please confirm if this is a known delay, and advise how we can ensure real-time ticks are received properly.

Thanks,

Hi @HritikRD
We have checked and confirmed that this issue is occurring with the V2 WebSocket, which is now deprecated and will soon be discontinued.

Please switch to the V3 WebSocket. For more details, refer to this article: New Market Feeder V3.
Thanks!

@Ketan
Please check the Github Code,
are you saying API version is need to update??

function fetchMarketUpdates()
{
$apiVersion = ‘2.0’;
$accessToken = ‘ACCESS_TOKEN’;

// Configure with your access token
$configuration = Configuration::getDefaultConfiguration();
$configuration->setAccessToken($accessToken);

// Get the authorized URL for the WebSocket connection
$response = getMarketDataFeedAuthorize($apiVersion, $configuration);

$connection = connect($response['data']['authorized_redirect_uri']);

echo "Connection successful!\n";

// Message payload to send to the server
$data = [
    "guid" => "someguid",
    "method" => "sub",
    "data" => [
        "mode" => "full",
        "instrumentKeys" => ["NSE_INDEX|Nifty Bank", "NSE_INDEX|Nifty 50"]
    ]
];

// Send the data as binary
$binaryData = json_encode($data);

$connection->sendBinary($binaryData);

foreach ($connection as $message) {
    $payload = $message->buffer();

    if ($payload === '100') {
        $connection->close();
        break;
    }

    if (!empty($payload)) {
        $decodedData = decodeProtobuf($payload);
        // Convert the decoded data to JSON and print it
        var_dump($decodedData->serializeToJsonString());
    }
}

}

I have few more question on API v2.
As we are creating access-token using api version v2 will that Affect while creating Authorization Url?
wss://wsfeeder-api.upstox.com/market-data-feeder/v2/upstox-developer-api/feeds?requestId=e60e481b-ac3d-432b-8e00-aedd59fa7454&code=xHCw0-0d1495b3-b084-49dc-94bb-d9f9093da484

Awaiting for your reply.

@Ketan Awaiting for your Response

Hi @HritikRD, Updating the API version to 3.0 alone won’t resolve the issue — you need to generate a V3 Feeder authorize URL.

Kindly refer to the sample websocket example for further guidance.

Thanks

@HritikRD
Changing the API version won’t help—you need to change the function you’re calling. Please use getMarketDataFeedAuthorizeV3 instead of getMarketDataFeedAuthorize.

If you’re using an older version of the PHP SDK, this function may not be available. You can switch to the latest version, which is 1.17.

Thanks!

@Ketan

Currently The websocket is providing old prices.

[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE919I01024: LTP=9.2, LTT=2025-06-25 12:34:17 (diff: 48s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE642Y01029: LTP=35.1, LTT=2025-06-25 12:33:35 (diff: 90s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE414D01027: LTP=294.7, LTT=2025-06-25 12:33:10 (diff: 115s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE634I01029: LTP=213.69, LTT=2025-06-25 12:34:08 (diff: 58s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INF204KC1022: LTP=130.87, LTT=2025-06-25 12:33:34 (diff: 91s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE350C01017: LTP=652.35, LTT=2025-06-25 12:33:32 (diff: 93s)

But the Prices of this stoks are higher and different , compared to current time i,e ,12.35 pm
It seems sometimes the Websocket is providing Old values.

How to tackle this.

The Short PHP Code i written
$apiVersion = ‘3.0’;
$accessToken = $bearerToken;

    // Configure with your access token
    $configuration = Configuration::getDefaultConfiguration();
    $configuration->setAccessToken($accessToken);

    // Get the authorized URL for the WebSocket connection
    $response = $this->getMarketDataFeedAuthorizeV3($apiVersion, $configuration);
    $connection = connect($response['data']['authorized_redirect_uri']);

    // Fetch buy/sell data of recommendations
    $getBuySellDataOfRecommendations = ManageRecommendation::select('id', 'instrument_key', 'recommendation_actions_xid')
        ->whereIn('recommendation_actions_xid', [1, 2, 3])
        ->where('product_type_xid', 1) //only for tradeoptions
        ->orderByDesc('id')
        ->get();

    // Create a mapping of instrument_key to recommendation_id
    $instrumentKeyMap = [];
    foreach ($getBuySellDataOfRecommendations as $recommendation) {
        if ($recommendation->schedule_date_time < $currentDateTime->format('Y-m-d H:i:s') || $recommendation->schedule_date_time == null) {

            $instrumentKeyMap[$recommendation->instrument_key] = $recommendation->id;
        }
    }

    // Extract instrument keys
    $instrumentKeys = array_keys($instrumentKeyMap);
    if (empty($instrumentKeys)) {
        Log::warning('No valid instrument keys found. Aborting WebSocket connection. In OPTIONS');
        return;
    }
    // Message payload to send to the server
    $data = [
        "guid" => uniqid('guid_', true),
        "method" => "sub",
        "data" => [
            "mode" => "full",
            "instrumentKeys" => $instrumentKeys
        ]
    ];

    // Send the data as binary
    $binaryData = json_encode($data);
    $connection->sendBinary($binaryData);
    // Define stop time (4:00 PM)
    // $stopTime = now()->setTime(19, 9);
    foreach ($connection as $message) {

        $payload = $message->buffer();
        usleep(2000000);

        if ($payload === '100') {
            $connection->close();
            break;
        }

        if (!empty($payload)) {
            $decodedData = $this->decodeProtobuf($payload);
            $jsonData = json_decode($decodedData->serializeToJsonString(), true);



            if (empty($jsonData['feeds'])) {
                Log::info('No feed data found in payload IN TRADE OPTION');
                continue;
            }

            //  Log::info("Trade Options running");
            foreach ($jsonData['feeds'] as $instrumentKey => $instrumentData) {

                // Get the recommendation ID using the instrument_key
                $recommendationId = $instrumentKeyMap[$instrumentKey] ?? null;

                if ($recommendationId && isset($instrumentData['ff']['marketFF']['ltpc']['ltp'])) {
                    $ltp = $instrumentData['ff']['marketFF']['ltpc']['ltp'];
                    $lttMs = $instrumentData['ff']['marketFF']['ltpc']['ltt'] ?? null;

                    // Convert LTT to Carbon instance
                    if ($lttMs) {
                        $lttTimestamp = (int) ($instrumentData['ff']['marketFF']['ltpc']['ltt'] ?? 0);
                        $lttCarbon = Carbon::createFromTimestampMs($lttTimestamp);
                        $now = now();
                        $diffInSeconds = $now->diffInSeconds($lttCarbon);

                        if ($diffInSeconds > 50) {
                            Log::info("SKIPPED stale tick for {$instrumentKey}: LTP={$ltp}, LTT={$lttCarbon} (diff: {$diffInSeconds}s)");
                            continue;
                        }

                    }

                    $lastTradedPrice = $ltp;

                    $range = $getBuySellDataOfRecommendationItem->buy_price;
                    // Log::info($recommendationId . '-' . $lastTradedPrice . '-' . $range);
                    Log::info("RECEIVED: {$recommendationId}-{$ltp}-{$range}-LTT={$lttCarbon->toDateTimeString()}");



                    // Check if lastTradedPrice falls within the range

                } else {
                    Log::error("LTP not found for Instrument Key: $instrumentKey (Recommendation ID: $recommendationId)");
                }
            }
        }
    }

Thanks,!!

@HritikRD
Currently, the V3 WebSocket does not provide a live feed. Instead, it delivers the previous minute’s data, and you are expected to construct the current feed using the LTP (Last Traded Price) updates received from the WebSocket.

To support a higher number of instrument subscriptions per connection, we’ve optimized the data payload by sending reduced data per instrument key. This ensures efficient usage of network bandwidth on both the client and server sides

We have forwarded this concern to the appropriate team.

Thank you!

1 Like

So , Is there any possiblity to ger realtime Data of Instrument key for websocket V3?

No bro, They will not implement it as they already had it and then replaced it with previous candle data.