> For the complete documentation index, see [llms.txt](https://docs.xandtech.fr/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xandtech.fr/home/xtimerewards/reference/developer-api.md).

# Developer API

XTimeRewards exposes a small public Java API (`XTimeRewardsAPI`) for other plugins to read playtime/rank data, and to register their own custom reward types usable directly in `milestones.yml`/`streaks.yml`/`leaderboard-rewards.yml`/`afk-mode-rewards.yml`.

## Getting an instance

Obtained via Bukkit's `ServicesManager` — no compile-time dependency on XTimeRewards' internal classes is required, just the small API package.

```java
RegisteredServiceProvider<XTimeRewardsAPI> registration =
        Bukkit.getServicesManager().getRegistration(XTimeRewardsAPI.class);
if (registration != null) {
    XTimeRewardsAPI api = registration.getProvider();
}
```

## Reference

```java
CompletableFuture<Long> getTotalPlaytime(UUID uuid);
CompletableFuture<Long> getPeriodPlaytime(UUID uuid, PeriodType period);
CompletableFuture<Integer> getRank(UUID uuid, PeriodType period);
CompletableFuture<List<TopEntry>> getTop(PeriodType period, int limit);

List<Milestone> getMilestones(PeriodType period);
CompletableFuture<Boolean> isMilestoneClaimed(UUID uuid, String milestoneId);

void registerRewardType(String type, RewardAction action);
```

| Method                                  | Notes                                                                                                                        |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `getTotalPlaytime(uuid)`                | Lifetime playtime, in seconds.                                                                                               |
| `getPeriodPlaytime(uuid, period)`       | Playtime for the current daily/weekly/monthly/yearly bucket (or lifetime, for `PeriodType.LIFETIME`).                        |
| `getRank(uuid, period)`                 | The player's current rank on that period's leaderboard.                                                                      |
| `getTop(period, limit)`                 | The top `limit` entries for that period — see `TopEntry` below.                                                              |
| `getMilestones(period)`                 | Every configured milestone for that period, as loaded from `milestones.yml`, regardless of any individual player's progress. |
| `isMilestoneClaimed(uuid, milestoneId)` | Whether that milestone has already been claimed for its current period key.                                                  |
| `registerRewardType(type, action)`      | Registers a custom reward action usable in any reward-bearing YAML file via `type: <your-type>` — see below.                 |

`PeriodType` is an enum: `DAILY`, `WEEKLY`, `MONTHLY`, `YEARLY`, `LIFETIME`. `TopEntry` is a simple record: `UUID uuid()`, `String name()`, `long seconds()`.

## Registering a custom reward type

```java
public interface RewardAction {
    void execute(Player player, RewardEntry entry, Milestone milestone);
}
```

`RewardEntry` mirrors the fields available on any reward-entry YAML block: `type()`, `value()`, `material()`, `amount()`, `name()`, `lore()` — read whichever ones make sense for your type. `milestone` is `null` when the action fires from a context that isn't milestone-based (a streak tier, a leaderboard reward, an AFK-mode reward).

```java
api.registerRewardType("my-plugin-kit", (player, entry, milestone) -> {
    // entry.value() might name a kit, entry.amount() a quantity, etc. — up to you.
    MyPlugin.getKitManager().giveKit(player, entry.value());
});
```

Once registered, any config file can use it:

```yaml
rewards:
  - type: my-plugin-kit
    value: "starter"
```

{% hint style="warning" %}
Register your reward type in your own plugin's `onEnable()`, **after** confirming XTimeRewards is present and its service is registered — registering too early (before XTimeRewards itself has finished enabling) will silently fail to find the service.
{% endhint %}

## Events

Two Bukkit events fire around the milestone lifecycle — listen to them the normal way (`@EventHandler`), no API instance needed:

| Event                         | Fires                                                                                                                                                                                                                                    |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PlayerMilestoneReachedEvent` | The moment a player crosses a milestone's required playtime and is eligible for it (permission check already passed) — regardless of whether it auto-claims or waits for `/xtimerewards claim`. Exposes `getPlayer()`, `getMilestone()`. |
| `PlayerMilestoneClaimedEvent` | Once a milestone's rewards have actually been granted (after the storage-level claim lock succeeded), whether that happened automatically or manually. Exposes `getPlayer()`, `getMilestone()`, `getPeriodKey()`.                        |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.xandtech.fr/home/xtimerewards/reference/developer-api.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
