Working with Events
In the blockchain ecosystem, "events" are the on-chain log entries emitted by extrinsics — they're how the chain reports what actually happened: token transfers, collection creation, marketplace listing IDs, balance changes, and so on. Monitoring them is essential for any application that needs to react to state changes — for example, unlocking an in-game item the moment the user receives the corresponding NFT.
How events are exposed
Once a transaction has been included in a block, the platform exposes the extrinsic that carried it — and every event that extrinsic emitted — through the extrinsic field on the Transaction type:
{
extrinsic { # null until the transaction is included in a block
id # "blockNumber-extrinsicIndex", e.g. "11955161-2"
hash # the extrinsic hash
success # whether the extrinsic succeeded on-chain
events {
id # the event ID
name # human-readable name, e.g. "MultiTokens Collection Created"
collectionId # the related collection ID, when the event concerns one
tokenId # the related token ID (canonical "collectionId-tokenId" form)
data # trimmed JSON payload with the event's key values
}
}
}
A few things to know about the fields:
nameis the pallet and event name with spaces —MultiTokens Collection Created,MultiTokens Minted,Marketplace Listing Created,Balances Transfer, and so on. Note that on-chain event names are conventionally written in dotted form (MultiTokens.CollectionCreated), including elsewhere in these docs — the platform'snamefield is the same event with the words spaced out, so match against the spaced form when filtering.collectionId/tokenIdare filled in when the event relates to a specific collection or token, so you can match events to your assets without parsingdata.datacarries the event's key values as JSON — the IDs your application usually needs. For example,MultiTokens Collection Createdcarries{"collectionId": "124587"},MultiTokens Mintedcarries{"amount": "1"}, andMarketplace Listing Createdcarries the full listing (id,price,amount,type). Events whose meaning is fully captured by the other fields have an emptydatapayload.- The platform surfaces the events relevant to the action itself; low-level bookkeeping events (fee payments and similar) are not included.
Reading a transaction's events
The flow after submitting any CreateTransaction mutation is:
- Wait for the transaction to reach
FINALIZED— either pollGetTransaction(uuid:), or subscribe to theTransactionStateChangedWebSocket event to be notified the moment the state changes. While the transaction is stillPENDINGor awaiting inclusion in a block,extrinsicisnull. - Check
extrinsic.successto confirm the on-chain outcome (a failed extrinsic emits no events). - Read
extrinsic.eventsand pick out the ones you care about byname.
- GraphQL
- cURL
- Javascript
- Node.js
- Python
query GetTransactionEvents($uuid: String!) {
GetTransaction(
network: CANARY
chain: MATRIX
uuid: $uuid
) {
state
extrinsic {
hash
success
events {
id
name
collectionId
tokenId
data
}
}
}
}
Variables:
{
"uuid": "06303d39-6ba9-4c81-8500-55bcca9e9512"
}
curl --location 'https://platform.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_API_TOKEN>' \
-d '{"query":"query GetTransactionEvents($uuid: String!) { GetTransaction(network: CANARY, chain: MATRIX, uuid: $uuid) { state extrinsic { hash success events { id name collectionId tokenId data } } } }","variables":{"uuid":"06303d39-6ba9-4c81-8500-55bcca9e9512"}}'
fetch('https://platform.enjin.io/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer <YOUR_API_TOKEN>'
},
body: JSON.stringify({
query: `
query GetTransactionEvents($uuid: String!) {
GetTransaction(network: CANARY, chain: MATRIX, uuid: $uuid) {
state
extrinsic {
hash
success
events {
id
name
collectionId
tokenId
data
}
}
}
}
`,
variables: { uuid: '06303d39-6ba9-4c81-8500-55bcca9e9512' }
}),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');
axios.post('https://platform.enjin.io/graphql', {
query: `
query GetTransactionEvents($uuid: String!) {
GetTransaction(network: CANARY, chain: MATRIX, uuid: $uuid) {
state
extrinsic {
hash
success
events {
id
name
collectionId
tokenId
data
}
}
}
}
`,
variables: { uuid: '06303d39-6ba9-4c81-8500-55bcca9e9512' }
}, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer <YOUR_API_TOKEN>'
}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
import requests
query = '''
query GetTransactionEvents($uuid: String!) {
GetTransaction(network: CANARY, chain: MATRIX, uuid: $uuid) {
state
extrinsic {
hash
success
events {
id
name
collectionId
tokenId
data
}
}
}
}
'''
variables = {'uuid': '06303d39-6ba9-4c81-8500-55bcca9e9512'}
response = requests.post(
'https://platform.enjin.io/graphql',
json={'query': query, 'variables': variables},
headers={
'Content-Type': 'application/json',
'Authorization': 'Bearer <YOUR_API_TOKEN>'
}
)
print(response.json())
Example: picking up a new collection ID
Some values only exist once the chain executes the transaction — the collectionId assigned by createCollection is the classic case. Events are how you read them.
Submitting the collection creation returns a transaction in PENDING state, with no extrinsic yet:
{
"data": {
"CreateTransaction": {
"uuid": "06303d39-6ba9-4c81-8500-55bcca9e9512",
"action": "MultiTokens.create_collection",
"state": "PENDING",
"extrinsic": null
}
}
}
Polling GetTransactionEvents (the query above) with that uuid eventually returns FINALIZED, and the new collection's ID appears in the MultiTokens Collection Created event — both on the event itself and in its data payload:
{
"data": {
"GetTransaction": {
"state": "FINALIZED",
"extrinsic": {
"hash": "0xb3a2a733cf24df07fbbbffdf4447959ce66fd78ed46bc78e10c4991004b43b3b",
"success": true,
"events": [
{
"id": "1234567-2",
"name": "MultiTokens Attribute Set",
"collectionId": "124587",
"tokenId": null,
"data": []
},
{
"id": "1234567-3",
"name": "MultiTokens Collection Created",
"collectionId": "124587",
"tokenId": null,
"data": {
"collectionId": "124587"
}
}
]
}
}
}
}
The same pattern applies to every chain-assigned value: the token ID in MultiTokens Token Created after a mint into a new token, the listing in Marketplace Listing Created after createListing, the group ID after createTokenGroup, and so on.
Transfer-style events (MultiTokens Transferred, MultiTokens Minted, Balances Transfer) carry the related collectionId / tokenId, which is usually all you need to react in-game — e.g. unlocking the item that corresponds to the token the player just received.
Other ways to look events up
Events hang off the extrinsic, so any query that returns an Extrinsic returns them too:
GetExtrinsic(hash:)— when you have an extrinsic hash rather than a platform transactionuuid.GetBlock/GetBlocks— read every extrinsic (and its events) in a given block.
You can also follow your transactions in the Platform UI: the Transactions page shows each transaction's state and extrinsic hash as it moves on-chain.
The platform pushes TransactionStateChanged and other events to your application over WebSocket in real time, removing the need to poll — see WebSocket Events for the full reference.