Preview documentation
This page has not completed release review. Its SDK or protocol version is not yet a confirmed public release.
GameLink WebSocket Purchase Transactions¶
GameLink separates purchase-update subscriptions from transaction-management requests. The exact targets are twitchPurchaseBits and transaction.
Release status
This page is pinned to untagged public commit 16c6b97; publication remains blocked until a versioned GameLink contract is available.
See GameLink WebSocket Protocol for the common envelope, broadcasts and subscriptions for subscription conventions, and Process GameLink transactions for an end-to-end fulfillment workflow.
Canonical names¶
| Operation | Action | Target |
|---|---|---|
| Subscribe or unsubscribe by SKU | subscribe or unsubscribe |
twitchPurchaseBits |
| Receive a purchase update | update |
twitchPurchaseBits or transaction |
| Get outstanding transactions | get |
transaction |
| Refund a transaction | refund |
transaction |
| Validate a transaction | validate |
transaction |
transaction_complete, transaction_completed, and twitchBitsPurchase are not the request target constants emitted by this commit's purchase schema.
Subscribe to purchases¶
Subscribe to one SKU:
{
"action": "subscribe",
"params": {
"request_id": 50,
"target": "twitchPurchaseBits"
},
"data": {
"sku": "my-sku"
}
}
Use "sku": "*" to subscribe to all purchases. Unsubscribe with the same target and SKU selector plus action: "unsubscribe".
The SDK tracks individual SKU subscriptions, but its transaction callback receives every delivered transaction. Filter data.sku in the callback when a handler is SKU-specific.
Purchase update¶
{
"meta": {
"request_id": 65535,
"action": "update",
"target": "twitchPurchaseBits",
"timestamp": 1590011391849
},
"data": {
"id": "external-transaction-id",
"muxy_id": "muxy-transaction-id",
"sku": "my-sku",
"displayName": "Product Display Name",
"userId": "123456789",
"username": "viewer_name",
"cost": 50,
"currency": "bits",
"timestamp": 1590011391849,
"additional": {
"source": "extension"
}
}
}
| Field | Meaning in the pinned schema |
|---|---|
id |
External, service-dependent transaction ID. |
muxy_id |
Muxy transaction ID used by later operations. |
sku |
Purchased product SKU. |
displayName |
Human-readable product display name. |
userId, username |
Purchaser identifiers. Treat display names as untrusted text. |
cost, currency |
Purchase amount and currency. |
timestamp |
Purchase time as a Unix timestamp in milliseconds. |
additional |
Arbitrary JSON attached to the receipt. |
Get outstanding transactions¶
Request one SKU or use * for all SKUs:
{
"action": "get",
"params": {
"request_id": 51,
"target": "transaction"
},
"data": {
"sku": "*"
}
}
{
"meta": {
"request_id": 51,
"action": "get",
"target": "transaction",
"timestamp": 1590011392000
},
"data": {
"transactions": [
{
"id": "external-transaction-id",
"muxy_id": "muxy-transaction-id",
"sku": "my-sku",
"displayName": "Product Display Name",
"userId": "123456789",
"username": "viewer_name",
"cost": 50,
"currency": "bits",
"timestamp": 1590011391849,
"additional": {}
}
]
}
}
The SDK documentation says the server returns at most 10 unvalidated transactions, ordered from least recent to most recent.
Validate a transaction¶
Validate only after the entitlement is durably granted or recorded.
{
"action": "validate",
"params": {
"request_id": 52,
"target": "transaction"
},
"data": {
"transaction_id": "muxy-transaction-id",
"details": "Granted cosmetic item 123"
}
}
Refund a transaction¶
Refund by transaction ID and user ID:
{
"action": "refund",
"params": {
"request_id": 53,
"target": "transaction"
},
"data": {
"transaction_id": "muxy-transaction-id",
"user_id": "123456789"
}
}
The schema also supports refunding by replacing transaction_id with sku while retaining user_id.
Transaction ingestion boundary¶
These WebSocket messages begin after a purchase has entered GameLink. The pinned repository's integration fixture posts a Twitch receipt to bits/transactions as transactionReceipt plus displayName; it does not post the raw Twitch callback object as the WebSocket documentation previously suggested. Treat the HTTP ingestion contract as separate from this WebSocket protocol and follow the reviewed transaction recipe.