> ## Documentation Index
> Fetch the complete documentation index at: https://andcze.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Plugin fulfilment

> The Socket.IO contract, atomic claim, and crash-safe fulfilment acknowledgement.

The official plugin uses the Socket.IO `/plugin` namespace on the public app/API origin. The game server always initiates the connection and exposes no inbound port.

<Warning>
  The legacy REST polling endpoints `GET /orders/plugin/.../pending` and `POST /orders/plugin/.../complete` have been retired. They could not provide a safe atomic claim across multiple instances or protect the ambiguous crash window. Use the current plugin and protocol below.
</Warning>

## Authentication

The namespace handshake sends:

```json theme={null}
{ "apiKey": "isk_<64 hex characters>", "serverId": "<24 hex characters>" }
```

The backend accepts only an active `plugin` key with `orders:write`. The key is shop-bound, `serverId` must belong to that shop, and the key owner must still have shop access. Any invalid connection gets the same `unauthorized` error without revealing which check failed.

## Protocol v1 events

| Direction    | Event             | Data / ACK                                                                         |
| ------------ | ----------------- | ---------------------------------------------------------------------------------- |
| plugin → app | `hello`           | `{ platform, version }`                                                            |
| app → plugin | `ready`           | `{ serverId, serverName }`                                                         |
| app → plugin | `order:deliver`   | `{ v: 1, id, player, status, commands[], requireOnline }`                          |
| plugin → app | `order:claim`     | `{ orderId }`; the winner's ACK carries a fresh command snapshot                   |
| plugin → app | `order:release`   | voluntarily returns a claim when a fresh delivery gate is not met                  |
| plugin → app | `order:verify`    | rechecks the current status of a delivery parked for a long time                   |
| plugin → app | `order:complete`  | `{ orderId }`; ACK permits deleting `AWAITING_ACK` locally                         |
| plugin → app | `order:uncertain` | reports recovered `EXECUTING`; response is `manual-review`, `retry`, or `complete` |
| plugin → app | `orders:pull`     | rate-limited request for a full outstanding-order replay                           |
| plugin → app | `players:update`  | `{ online, max, players?[] }`; values are filtered and capped server-side          |
| plugin → app | `ping:app`        | diagnostic ACK with application time                                               |

The backend replays all outstanding deliveries on every connection and pushes after payment or status changes. Duplicate `order:deliver` events are expected: execution authority comes from the atomic claim and local journal, not from merely receiving an event.

## Safety states

1. `paid` or `dispute` → `processing`: only one instance wins the conditional database transition.
2. The plugin writes and fsyncs `EXECUTING` **before** the first command.
3. After the final command it writes and fsyncs `AWAITING_ACK`.
4. `order:complete` changes the order to `completed`; only its ACK removes the local entry.
5. A restart with `AWAITING_ACK` retries only the ACK. A restart with `EXECUTING` never replays commands and starts manual review.

<Info>
  Do not delete the journal to “unstick” an order. Check the actual player/server state and resolve it in the panel. `retry` clears the server-side claim and allows a new push; `complete` accepts the delivery without replaying commands.
</Info>

## Command formatting

The API formats product commands before returning the claim winner's fresh snapshot:

| Placeholder           | Replaced with                                  |
| --------------------- | ---------------------------------------------- |
| `{PLAYER}` / `{NICK}` | the order's validated nickname                 |
| `{QUANTITY}`          | quantity                                       |
| `{PRODUCT}`           | product name                                   |
| `{QUANTITY*1.5:2}`    | an allowed math expression rounded to 2 places |

Math expressions use a restricted parser and are never evaluated as code. `quantityTiers`, the command variant, and package bonuses are resolved by the API. The plugin additionally rejects any command whose first word appears in `blockedCommands`.

If a product requires the player online, an instance executes only after seeing the exact nickname on an allowed server. A locally parked delivery is checked through `order:verify` so an order cancelled or refunded in the meantime cannot run from a stale event.
