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.