Skip to main content

Package Events

Subscribe to real-time events emitted by specific Sui Move packages. Perfect for building reactive applications that respond instantly to on-chain activity without polling.

Overview​

Package events are custom events emitted by Sui Move smart contracts. When a contract executes — whether it's minting an NFT, processing a swap, or updating game state — it can emit events that describe what happened.

Surflux's Package Events stream lets you subscribe to these events in real-time via Server-Sent Events (SSE). Instead of polling the blockchain or running your own indexer, you get instant notifications delivered directly to your application.

Use Cases​

DeFi Protocols

  • Listen for swap completions, liquidity additions, or liquidation events
  • Build real-time price feeds from DEX activity
  • Trigger alerts when specific trading conditions are met

NFT Platforms

  • Track minting events as they happen
  • Monitor marketplace sales and listings
  • Build live activity feeds for collections

Gaming & Metaverse

  • React to in-game events (battles, achievements, item transfers)
  • Update UI instantly when game state changes
  • Build live leaderboards and event logs

Automation & Bots

  • Trigger workflows based on smart contract events
  • Automate responses to protocol state changes
  • Build MEV or arbitrage bots

How to Subscribe​

Endpoint​

GET /events?api-key={your_api_key}&last-id={resumption_id}

Base URL (Mainnet): https://flux.surflux.dev

Base URL (Testnet): https://testnet-flux.surflux.dev

Parameters​

ParameterRequiredDescription
api-keyYesYour Surflux API key for authentication
last-idNoResume stream from a specific event ID (see below)

Stream Resumption with last-id​

The last-id parameter lets you control where the stream starts:

ValueBehavior
0 (default)Start from the beginning (server buffer limits apply)
$Only receive new events from now onwards
{event-id}Resume from after this specific event ID

Important: Your client should persist the event ID from each received event. If the connection drops, use the last received ID to resume without missing events.

Connection Limits​

Only one client per API key can be connected at a time. If you need multiple simultaneous connections, contact support for additional API keys.

Event Structure​

Package Event Format​

{
"type": "package_event",
"timestamp_ms": 1688769149870,
"checkpoint_id": 7090583,
"tx_hash": "BCnkYBU5RAwU2qS9fBuyFxFzACzX2MGKxUyKGnd8pRiV",
"data": {
"event_index": 1,
"sender": "0x443f35e4d8e7f0f9e590e92569cf08b49bc24b63a92dc80b5d5510e753aad2e8",
"event_type": "0x2::display::VersionUpdated<0x58156e414780a5a237db71afb0d852674eff8cd98f9572104cb79afeb4ad1e9d::suinet::SUITOMAINNET>",
"contents": {
"field": "field on your event",
"anotherField": "another field on your event"
}
}
}

Field Descriptions​

FieldTypeDescription
typestringAlways "package_event" for package events
timestamp_msnumberUnix timestamp in milliseconds when the event occurred
checkpoint_idnumberSui checkpoint number
tx_hashstringTransaction digest that emitted this event
data.event_indexnumberIndex of this event within the transaction
data.senderstringAddress that initiated the transaction
data.event_typestringFull type path of the emitted event
data.contentsobjectEvent payload (structure defined by the Move contract)

Code Examples​

JavaScript / TypeScript​

const apiKey = "your_api_key_here";
const eventSource = new EventSource(
`https://flux.surflux.dev/events?api-key=${apiKey}&last-id=$`
);

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === "package_event") {
console.log("Package event received:", data.data.event_type);
console.log("Event contents:", data.data.contents);

// Persist event.lastEventId for resumption
localStorage.setItem("lastEventId", event.lastEventId);
}
};

eventSource.onerror = (error) => {
console.error("Connection error:", error);
eventSource.close();

// Reconnect with last received event ID
const lastId = localStorage.getItem("lastEventId");
// ... reconnect logic
};

Filtering Specific Events​

To subscribe to specific package events, you'll need to filter on the client side:

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === "package_event") {
const eventType = data.data.event_type;

// Filter for specific package events
if (eventType.includes("0x123abc::nft::MintEvent")) {
console.log("NFT minted:", data.data.contents);
// Handle mint event
}

if (eventType.includes("0x456def::dex::SwapEvent")) {
console.log("Swap executed:", data.data.contents);
// Handle swap event
}
}
};

Best Practices​

  • Persist Event IDs — Always save the lastEventId from received events. Use it to resume the stream if your connection drops, ensuring you don't miss any events.
  • Handle Reconnections — Implement automatic reconnection logic with exponential backoff. SSE connections can drop due to network issues or server restarts.
  • Filter on the Client — The SSE stream includes all package events and object changes. Filter by event_type on the client side to process only the events you care about.
  • Process Events Idempotently — You may receive duplicate events during reconnection. Design your event handlers to be idempotent.
  • Monitor Connection Health — Set up heartbeat monitoring to detect stale connections and reconnect proactively.