Each timestamp Massive returns marks a different moment in the trade's journey, so picking the wrong one shifts your whole series by a measurable amount rather than breaking anything visibly. Which field carries which moment, and what unit it is in, both depend on how you are reading the data, so the table below is per feed rather than universal.
Applies to
- Plans: a Stocks subscription. Other asset classes follow the same pattern with fewer fields.
- Endpoints: /v3/trades/{ticker}, /v3/quotes/{ticker} and the flat-file trade and quote datasets; the T and Q channels on the /stocks WebSocket cluster.
- Asset classes: US stocks. Options and futures use nanosecond timestamps on REST too.
What each timestamp measures
Each timestamp measures a different moment in the trade's journey, and the gaps between them are somebody else's processing rather than ours:
| Field on REST | Field on the WebSocket | What it measures |
|---|---|---|
| participant_timestamp | pt | When the exchange or reporting facility generated the event |
| sip_timestamp | t | When the SIP received it from the exchange |
| trf_timestamp | trft | When the Trade Reporting Facility received it, on off-exchange prints |
pt is always at or before t, because the SIP receives an event after the exchange produces it. So the difference between them is the SIP's own latency, which sits upstream of Massive entirely.
Precision differs by feed
Precision differs by feed, and this is the part that produces wrong answers. REST and the flat files use nanoseconds; the WebSocket uses milliseconds:
REST sip_timestamp 1788566398110367271 nanoseconds since the epoch
WS t 1788566398110 milliseconds since the epoch
Dividing by the wrong power of ten either drops your event onto 1 January 1970 or throws it tens of thousands of years into the future, which is usually obvious. What is not obvious is mixing the two feeds in one series, so normalize to a single unit as soon as you parse.
How to see all three on one trade
Ask for a trade that went through a reporting facility, because an exchange print carries only two of the three:
curl -X GET "https://api.massive.com/v3/trades/AAPL?timestamp.gte=1789042200000000000&limit=1&order=asc&sort=timestamp&apiKey=YOUR_API_KEY"
Response
{
"results": [
{
"conditions": [12, 37],
"exchange": 4,
"participant_timestamp": 1789042201676773107,
"trf_timestamp": 1789042201685083268,
"sip_timestamp": 1789042201685102864,
"trf_id": 202,
"price": 317.6537,
"size": 0,
"decimal_size": "0.000001",
"tape": 3
}
],
"status": "OK"
}
Read them in that order and the journey is visible: the venue stamped it, the reporting facility received it 8.31 milliseconds later, and the SIP 19.6 microseconds after that. The two gaps are three orders of magnitude apart, which is the point: the reporting hop is where the time goes, not the consolidation. A trade printed on an exchange rather than through a facility has no trf_timestamp at all, so treat the field as optional rather than absent-means-broken.
How to convert one
Every language has this built in. There is no need for a converter website:
from datetime import datetime, timezone
ns = 1788566398110367271
print(datetime.fromtimestamp(ns / 1_000_000_000, timezone.utc))
Keep the value as an integer for storage and comparison, and convert only for display. Converting to a local time zone early is how a trade ends up on the wrong session.
If you see an error
A timestamp that decodes to 1970 means you read a millisecond value as if it were nanoseconds: the WebSocket's 1788566398110 divided by 1e9 is 1,788 seconds after the epoch. A timestamp far in the future is the opposite mistake, a nanosecond value read as milliseconds or as seconds.
A trade that appears to be in the wrong session is usually a local time-zone conversion. All Massive timestamps are UTC; the US equities session is 09:30 to 16:00 Eastern, which is 14:30 to 21:00 UTC outside daylight saving and 13:30 to 20:00 UTC inside it.
trf_timestamp of 0, or the field being absent, means the trade was executed on an exchange rather than reported through a facility. That is normal.

