Skip to content

Commit 5de3d4d

Browse files
Documentation - Tebex Module (#199)
* Prepare tebex module for release * Add Tebex Module documentation * Fix import order * minor changes * Add TebexEmbeddedCheckoutSupport#UNSUPPORTED --------- Co-authored-by: Trentin <[email protected]>
1 parent 4a3a44b commit 5de3d4d

File tree

4 files changed

+180
-6
lines changed

4 files changed

+180
-6
lines changed

bukkit-example/src/main/java/com/lunarclient/apollo/example/api/examples/TebexApiExample.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,27 @@ public class TebexApiExample extends TebexExample {
3838
@Override
3939
public void displayTebexEmbeddedCheckoutExample(Player viewer, String basketIdent, String locale) {
4040
Optional<ApolloPlayer> apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId());
41-
apolloPlayerOpt.ifPresent(apolloPlayer -> {
42-
if (apolloPlayer.getTebexEmbeddedCheckoutSupport() == TebexEmbeddedCheckoutSupport.UNSUPPORTED) {
43-
return;
44-
}
4541

46-
this.tebexModule.displayTebexEmbeddedCheckout(apolloPlayer, basketIdent, locale);
47-
});
42+
if (!apolloPlayerOpt.isPresent()) {
43+
viewer.sendMessage("Complete your purchase at https://pay.tebex.io/" + basketIdent);
44+
return;
45+
}
46+
47+
ApolloPlayer apolloPlayer = apolloPlayerOpt.get();
48+
TebexEmbeddedCheckoutSupport embeddedCheckoutSupport = apolloPlayer.getTebexEmbeddedCheckoutSupport();
49+
50+
if (embeddedCheckoutSupport == TebexEmbeddedCheckoutSupport.UNSUPPORTED) {
51+
viewer.sendMessage("Complete your purchase at https://pay.tebex.io/" + basketIdent);
52+
return;
53+
}
54+
55+
this.tebexModule.displayTebexEmbeddedCheckout(apolloPlayerOpt.get(), basketIdent, locale);
56+
57+
if (embeddedCheckoutSupport == TebexEmbeddedCheckoutSupport.OVERLAY) {
58+
viewer.sendMessage("Opening checkout as game overlay!");
59+
} else {
60+
viewer.sendMessage("Opening checkout in an external window!");
61+
}
4862
}
4963

5064
}

bukkit-example/src/main/java/com/lunarclient/apollo/example/proto/listeners/ApolloPacketReceiveProtoListener.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.lunarclient.apollo.packetenrichment.v1.PlayerChatOpenMessage;
3535
import com.lunarclient.apollo.packetenrichment.v1.PlayerInfo;
3636
import com.lunarclient.apollo.packetenrichment.v1.PlayerUseItemMessage;
37+
import com.lunarclient.apollo.player.v1.EmbeddedCheckoutSupport;
3738
import com.lunarclient.apollo.player.v1.ModMessage;
3839
import com.lunarclient.apollo.player.v1.PlayerHandshakeMessage;
3940
import java.util.List;
@@ -76,6 +77,7 @@ private void onPlayerHandshake(PlayerHandshakeMessage message) {
7677
MinecraftVersion minecraftVersion = message.getMinecraftVersion();
7778

7879
LunarClientVersion lunarClientVersion = message.getLunarClientVersion();
80+
EmbeddedCheckoutSupport checkoutSupport = message.getEmbeddedCheckoutSupport();
7981
String gitBranch = lunarClientVersion.getGitBranch();
8082
String gitCommit = lunarClientVersion.getGitCommit();
8183
String semVer = lunarClientVersion.getSemver();

docs/developers/modules/_meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"staffmod": "Staff Mod",
2323
"stopwatch": "Stopwatch",
2424
"team": "Team",
25+
"tebex": "Tebex",
2526
"title": "Title",
2627
"tntcountdown": "TNT Countdown",
2728
"transfer": "Transfer",

docs/developers/modules/tebex.mdx

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import { Tab, Tabs } from 'nextra-theme-docs'
2+
import { Callout } from 'nextra-theme-docs'
3+
4+
# Tebex Module
5+
6+
## Overview
7+
8+
The Tebex module allows Lunar Client users to complete purchases directly within the game, providing a faster, more seamless checkout experience.
9+
10+
**Overlay Mode**
11+
12+
This mode displays the Tebex checkout flow as an overlay on the Minecraft window, similar to opening an inventory. It provides the most seamless experience and is the preferred method. Overlay mode is only available on **Windows**.
13+
14+
![Tebex Overlay Example](https://i.imgur.com/1grfRaX.png#center)
15+
16+
**Window Mode**
17+
18+
As a fallback, and for **macOS** and **Linux** users, a separate window opens to display the Tebex checkout flow. While not as seamless as overlay mode, this ensures compatibility across all operating systems.
19+
20+
![Tebex Window Example](https://i.imgur.com/68wBAYZ.png#center)
21+
22+
## Usage Guidelines
23+
24+
To ensure a smooth user experience, servers must only open checkout windows from user-initiated actions. Examples include, but aren't limited to:
25+
26+
**Allowed (User-Initiated Actions):**
27+
- Clicking a link in chat
28+
- Running a command
29+
- Clicking a button in a GUI
30+
31+
**Not Allowed (Automated/Intrusive Actions):**
32+
- Triggering on login
33+
- Automatically opening at set intervals (e.g., every 30 minutes)
34+
- Automatically opening during flash sales, events, or other promotions without user interaction
35+
36+
This feature is designed to enhance the user experience by providing a seamless checkout process, misuse of this module, such as creating a disruptive or intrusive purchase flow, will result in restricted access in the future.
37+
38+
## Integration
39+
40+
The only piece of information sent from the server to the client to trigger a checkout window is the **Tebex basket ident**. This unique identifier represents an in-progress basket and later converts into a **Tebex transaction ID (tbx-...)** upon purchase.
41+
42+
Optionally, a **locale** value can also be sent to specify the language and regional formatting used when rendering the checkout window (e.g., `en-US`). If no locale is provided, the default locale settings will be used.
43+
44+
If a player is not using Lunar Client, the same Tebex basket can be used on the web at: `https://pay.tebex.io/<basket>`
45+
46+
**Example flow**
47+
1. Create a basket using the Tebex Headless API.
48+
2. Add package(s) to basket with Tebex Headless API
49+
3. If the player is using Lunar Client: Send an Apollo packet to open the checkout modal.
50+
4. If the player is not using Lunar Client: Send a chat message with a Tebex payment link.
51+
52+
**Tebex Headless API**
53+
54+
Basket idents are created via the [Tebex Headless API](https://docs.tebex.io/developers/headless-api/overview). This API allows programmatic basket creation, package additions, coupon applications, and more. The [Lunar Client Store](https://store.lunarclient.com/) is built on this API, and it is enabled by default for all Tebex stores.
55+
56+
**Getting started with the Tebex Headless API**
57+
58+
🔗 [Documentation](https://docs.tebex.io/developers/headless-api/overview)<br/>
59+
🔗 [Java SDK](https://github.com/tebexio/TebexHeadless-OpenAPI/tree/main/sdks/java)<br/>
60+
61+
Most implementations of Embedded Checkout only require two API endpoints:
62+
1. Creating a basket
63+
2. Adding packages to a basket
64+
65+
For simplicity, you may opt to handle these requests manually rather than using the SDK.
66+
67+
**API Authentication**
68+
69+
You’ll need your **public token** and **private key** from: [Tebex API Keys](https://creator.tebex.io/developers/api-keys)
70+
71+
<Callout type="warning" emoji="⚠️">
72+
Never share these credentials with Lunar Client or external servers. They should only be used while communicating with Tebex Headless.
73+
</Callout>
74+
75+
### Sample Code
76+
Explore each integration by cycling through each tab to find the best fit for your requirements and needs.
77+
78+
<Tabs items={['Apollo API', 'apollo-protos library', 'Manual JSON Object Construction']}>
79+
80+
<Tab>
81+
82+
**Display Tebex Embedded Checkout**
83+
84+
```java
85+
public void displayTebexEmbeddedCheckoutExample(Player viewer, String basketIdent, String locale) {
86+
Optional<ApolloPlayer> apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId());
87+
88+
if (!apolloPlayerOpt.isPresent()) {
89+
viewer.sendMessage("Complete your purchase at https://pay.tebex.io/" + basketIdent);
90+
return;
91+
}
92+
93+
ApolloPlayer apolloPlayer = apolloPlayerOpt.get();
94+
TebexEmbeddedCheckoutSupport embeddedCheckoutSupport = apolloPlayer.getTebexEmbeddedCheckoutSupport();
95+
96+
if (embeddedCheckoutSupport == TebexEmbeddedCheckoutSupport.UNSUPPORTED) {
97+
viewer.sendMessage("Complete your purchase at https://pay.tebex.io/" + basketIdent);
98+
return;
99+
}
100+
101+
this.tebexModule.displayTebexEmbeddedCheckout(apolloPlayerOpt.get(), basketIdent, locale);
102+
103+
if (embeddedCheckoutSupport == TebexEmbeddedCheckoutSupport.OVERLAY) {
104+
viewer.sendMessage("Opening checkout as game overlay!");
105+
} else {
106+
viewer.sendMessage("Opening checkout in an external window!");
107+
}
108+
}
109+
```
110+
111+
</Tab>
112+
113+
<Tab>
114+
115+
**Display Tebex Embedded Checkout**
116+
117+
<Callout type="info">
118+
To detect embedded checkout support type visit [Apollo Serverbound packets](/apollo/developers/lightweight/protobuf/serverbound-packets)
119+
</Callout>
120+
121+
```java
122+
public void displayTebexEmbeddedCheckoutExample(Player viewer, String basketIdent, String locale) {
123+
OpenTebexEmbeddedCheckoutMessage.Builder builder = OpenTebexEmbeddedCheckoutMessage.newBuilder()
124+
.setBasketIdent(basketIdent);
125+
126+
if (locale != null) {
127+
builder.setLocale(locale);
128+
}
129+
130+
OpenTebexEmbeddedCheckoutMessage message = builder.build();
131+
ProtobufPacketUtil.sendPacket(viewer, message);
132+
}
133+
```
134+
135+
</Tab>
136+
137+
<Tab>
138+
139+
**Display Tebex Embedded Checkout**
140+
141+
```java
142+
public void displayTebexEmbeddedCheckoutExample(Player viewer, String basketIdent, String locale) {
143+
JsonObject message = new JsonObject();
144+
message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.tebex.v1.OpenTebexEmbeddedCheckoutMessage");
145+
message.addProperty("basket_ident", basketIdent);
146+
147+
if (locale != null) {
148+
message.addProperty("locale", locale);
149+
}
150+
151+
JsonPacketUtil.sendPacket(viewer, message);
152+
}
153+
```
154+
155+
</Tab>
156+
157+
</Tabs>

0 commit comments

Comments
 (0)