> For the complete documentation index, see [llms.txt](https://guides.paynow.gg/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://guides.paynow.gg/integrations-and-commands/commands.md).

# Commands & Placeholders

A command is the line your game server runs when something happens to an order. It is how a purchase becomes an actual rank, kit or item. A product with no command takes the customer's money and delivers nothing.

*Set per product under **Deliverable Actions → Commands**, or for every product at once under* [*Global Commands*](/integrations-and-commands/global-commands.md)*.*

## How a command reaches your server

1. A customer buys something.
2. PayNow works out which commands apply: the product's own, plus any global commands for that stage.
3. PayNow substitutes the placeholders with real values from the order.
4. The command is sent to your linked [game server](/integrations-and-commands/game-servers.md), which runs it as console would.

Step 4 is the part that fails. If the server is not connected, commands queue rather than disappear, and run once it reconnects.

## Writing one

A command is your server's own console command, with placeholders where the player-specific parts go. You do not prefix it with a slash unless your server expects one from console.

{% tabs %}
{% tab title="Minecraft" %}
Grant a LuckPerms group to whoever the purchase is for:

```
lp user {customer.minecraft.uuid} parent add vip
```

Use the **UUID**, not the name. Names change; UUIDs don't. A player who changes their username after buying still keeps what they paid for.

Give an item and tell them it arrived:

```
give {customer.minecraft.name} diamond_pickaxe 1
tell {customer.minecraft.name} Thanks for buying {product.name}!
```

{% endtab %}

{% tab title="Rust / Steam" %}
Add the buyer to an Oxide group:

```
oxide.usergroup add {customer.steam.id} vip
```

Grant a permission directly:

```
oxide.grant user {customer.steam.id} kits.vip
```

Steam IDs are stable, so there is no equivalent of the Minecraft name-change problem.
{% endtab %}
{% endtabs %}

The exact syntax comes from your server and its plugins, not from PayNow. If the command works when you type it into your server console, it will work here.

### One command per line

Each command goes in its own row with its own stage. Don't chain several into one line and hope the server splits them.

## Stages

The stage decides when the command runs.

| Stage                | Runs when                                                               |
| -------------------- | ----------------------------------------------------------------------- |
| **On Purchase**      | The order completes.                                                    |
| **On Renew**         | A subscription renews.                                                  |
| **On Expire**        | A subscription or timed product expires, **or you revoke it manually**. |
| **On Refund**        | You refund the order.                                                   |
| **On Chargeback**    | The customer disputes the charge with their bank.                       |
| **On Trial Started** | A [trial](/orders-and-subscriptions/trials.md) begins.                  |
| **On Trial Expired** | A trial ends without converting.                                        |

{% hint style="danger" %}
**On Purchase does not fire when a trial starts, and it does not fire on renewal.** A product with only an On Purchase command delivers nothing during a trial, and a subscription that grants a temporary perk will not re-grant it when the customer renews.

Pair every grant with its matching removal. A rank given On Purchase and never removed On Refund or On Chargeback is a rank you gave away for free.
{% endhint %}

### Revoking runs On Expire

There is no separate revoke stage. When you revoke a product from a customer's inventory, PayNow runs the **On Expire** commands, the same ones an actual expiry would run.

Put your removal command on On Expire and it covers both. Put it only on On Refund and a revoked customer keeps whatever you gave them, because a revoke is not a refund.

## Execute when online

A checkbox on each command. The dashboard describes it as: *if the player is offline, the command executes when the player joins the server.*

Turn it on for anything that needs a connected player: a chat message, a spawned item, a temporary effect. Leave it off for permission and rank changes, which most plugins apply fine against an offline player.

It matters most on removals. A revoke that waits for the player to come back is a revoke that may never happen, and the customer who charged back keeps their rank indefinitely.

## Game servers to execute on

Also per command. Left empty, the command runs on *all game servers selected on the product*. Select one or more and that choice **overrides** the product's servers.

On a single-server store, leave it empty. On a multi-server store, leaving it empty is usually still what you want, because the product already knows which server it was bought for.

## Placeholders

You don't have to memorise these. The command editor has an **Available variables** link that opens the whole list, and each entry copies to your clipboard when you click it.

<figure><img src="/files/41OhlCCgk5oGONTJDfG8" alt="The Available command variables tooltip listing every placeholder with a copy icon and a description, above the Available variables link that opens it."><figcaption><p>Click any placeholder in the tooltip to copy it.</p></figcaption></figure>

The full set:

### Who the purchase is for

`{customer.*}` is the **recipient**. This is the one you want in almost every command.

| Placeholder                   | Value                      |
| ----------------------------- | -------------------------- |
| `{customer.id}`               | Recipient's PayNow ID      |
| `{customer.name}`             | Recipient's name           |
| `{customer.steam.id}`         | Recipient's Steam ID       |
| `{customer.steam.name}`       | Recipient's Steam name     |
| `{customer.steam.avatar}`     | Recipient's Steam avatar   |
| `{customer.minecraft.uuid}`   | Recipient's Minecraft UUID |
| `{customer.minecraft.name}`   | Recipient's Minecraft name |
| `{customer.minecraft.avatar}` | Recipient's Minecraft skin |

### Who paid

`{order.customer.*}` is the **buyer**. On an ordinary purchase these are the same person as above. On a gift they are not.

| Placeholder                         | Value                                   |
| ----------------------------------- | --------------------------------------- |
| `{order.customer.id}`               | Buyer's PayNow ID                       |
| `{order.customer.name}`             | Buyer's name                            |
| `{order.customer.steam.id}`         | Buyer's Steam ID                        |
| `{order.customer.steam.name}`       | Buyer's Steam name                      |
| `{order.customer.steam.avatar}`     | Buyer's Steam avatar                    |
| `{order.customer.minecraft.uuid}`   | Buyer's Minecraft UUID                  |
| `{order.customer.minecraft.name}`   | Buyer's Minecraft name                  |
| `{order.customer.minecraft.avatar}` | Buyer's Minecraft avatar                |
| `{order.gifted_by_customer_id}`     | ID of the customer who gifted this item |

{% hint style="warning" %}
**Using `{order.customer.*}` to deliver a product breaks gifting.** Someone buys a rank for a friend, and the rank lands on the person who paid. Reach for `{order.customer.*}` only when you genuinely mean the payer, such as thanking them in chat.
{% endhint %}

### Product

| Placeholder            | Value                                                             |
| ---------------------- | ----------------------------------------------------------------- |
| `{product.id}`         | ID of this product                                                |
| `{product.name}`       | Name of this product                                              |
| `{product.slug}`       | Slug of this product                                              |
| `{product.version_id}` | ID of the product version                                         |
| `{product.price}`      | Base price **in the lowest denomination**, so $14.99 gives `1499` |

### Order

| Placeholder         | Value                            |
| ------------------- | -------------------------------- |
| `{order.id}`        | ID of the order                  |
| `{order.pretty_id}` | The short order ID customers see |
| `{order.line_id}`   | ID of this line of the order     |
| `{checkout.id}`     | ID of the checkout session       |
| `{store.id}`        | ID of your store                 |
| `{order.currency}`  | Currency of the order            |

### Amounts

These are **per order line**, not per order. A customer who buys three things gets three separate command runs, each with its own line amounts.

| Placeholder                          | Value                              |
| ------------------------------------ | ---------------------------------- |
| `{order.line.subtotal_amount}`       | Subtotal for this line             |
| `{order.line.discount_amount}`       | Discount applied to this line      |
| `{order.line.giftcard_usage_amount}` | Gift card amount used on this line |
| `{order.line.tax_amount}`            | Tax on this line                   |
| `{order.line.total_amount}`          | Total for this line                |

## Custom variables in commands

A [custom variable](/integrations-and-commands/custom-variables.md) asks the customer something at checkout and drops their answer into the command. Reference it by its **Identifier**, in braces like any other placeholder.

A variable with the identifier `kit` becomes `{kit}`:

```
givekit {customer.minecraft.name} {kit}
```

The customer picks their kit at checkout, and the command that runs carries their choice.

## Checking a command actually ran

Open the order and read its [timeline](/orders-and-subscriptions/orders.md). It records command execution alongside creation and completion, which splits any "I paid and got nothing" report in two:

* **No execution logged.** A PayNow-side delivery problem. Check the command is attached to the right stage, and that the [game server](/integrations-and-commands/game-servers.md) is connected.
* **Execution logged.** A game-side problem. Check the plugin, the permission node, and whether the player was online if you ticked **Execute when online**.

If the command was wrong and you have since fixed it, [resend it](/integrations-and-commands/resending-commands.md) rather than asking the customer to buy again.
