> For the complete documentation index, see [llms.txt](https://edseries-plugins.gitbook.io/p/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://edseries-plugins.gitbook.io/p/edcrates/features/api.md).

# Developer API

Registering custom reward actions and economies, reading and giving keys, events.

Depend on the API artifact (provided scope; the plugin ships the same classes at runtime) and add `softdepend: [EdCrates]` to your plugin.yml.

```xml
<dependency>
    <groupId>es.edwardbelt</groupId>
    <artifactId>edcrates-api</artifactId>
    <version>1.0</version>
    <scope>provided</scope>
</dependency>
```

The API is interfaces and events only (`es.edwardbelt.edcrates.api.*`): `EdCratesAPI`, `action.ActionHandler` / `Action` / `ActionContext`, `crate.CrateView` / `RewardView` / `OpenResultView`, `economy.EconomyProvider`, `gui.CustomGuiItem` / `GuiContext` / `GuiView` / `PagedSource`, and the events.

```java
EdCratesAPI api = EdCratesAPI.get(); // or Bukkit.getServicesManager().load(EdCratesAPI.class)
```

## Custom reward actions

```java
api.registerAction("givedrill", (context, action) -> {
    // context.count()  how many times the reward came up in this open
    // action.firstWord()  "9x9" from 'givedrill:9x9 2'
    // action.scaled(context.count(), action.secondNumber())  2 x count
    long total = action.scaled(context.count(), action.secondNumber()).longValue();
    myPlugin.giveDrills(context.player(), action.firstWord(), total);
});
```

Now any crate can use `'givedrill:9x9 2'`. Handlers run on the main thread with the collapsed count, so a 100,000-key open calls yours once per reward. Wrap with `ActionHandler.async(...)` if everything it touches is thread-safe; it will then run on the roll thread. Register on your own `onEnable`; registrations survive `/edcrates reload`.

## Custom economies

```java
api.registerEconomy(new EconomyProvider() {
    public String id() { return "myeco"; }
    public boolean has(String currency) { return currency.equals("gems"); }
    public Collection<String> currencies() { return List.of("gems"); }
    public BigDecimal get(UUID p, String c) { ... }
    public void add(UUID p, String c, BigDecimal amount, boolean boosted) { ... }
    public void remove(UUID p, String c, BigDecimal amount) { ... }
});
```

`'currency:gems 100'` and `'myeco-currency:gems 100'` then pay into it.

## Custom GUI items and pagination sources

```java
api.registerCustomItem("my-shop", new CustomGuiItem() {
    public ItemStack render(GuiContext ctx) { return ctx.build(ctx.placeholders()); }
    public void click(GuiContext ctx, ClickType click) { myShop.open(ctx.player()); }
});
api.registerPagedSource("my-list", gui -> new PagedSource.Page(Map.of(), entries));
api.openGui(player, "my-menu", Map.of("shop", "keys"));
```

Any GUI file can then use `custom-item: {type: my-shop}` or `pagination: {source: my-list}`.

## Keys and opening

`getKeys`, `giveKeys`, `takeKeys`, `setKeys`, `allKeys` (offline UUIDs work), `opened`, `open(player, crate, amount, animate)`, `simulate(crate, keys)`, `keyItem`, `crateItem`, `openSelector`, `openPreview`, `animationsEnabled` / `setAnimationsEnabled`.

## Events

| Event                          | When                                                   |
| ------------------------------ | ------------------------------------------------------ |
| `CrateOpenEvent` (cancellable) | Before keys are taken. Change `amount` or `animate`.   |
| `CrateOpenedEvent`             | After every reward was applied, with the `OpenResult`. |
| `KeysChangeEvent`              | A balance changed (may fire async).                    |
