Skip to content
RustPluginGenerator

OnTakeCurrencyItem

OnTakeCurrencyItem is called on a vending machine right after a purchase removes the currency item from the buyer and before the game moves that item into the machine's inventory. Returning a non-null value stops the default handling of the currency item.

Signature
object OnTakeCurrencyItem(VendingMachine vendingMachine, Item takenCurrencyItem)

Parameters

Hook parameters
ParameterTypeDescription
vendingMachineVendingMachineThe vending machine that is receiving the currency item. For the player-driven machine it is a VendingMachine; for NPC/map shops the same hook fires with an NPCVendingMachine, so a narrower parameter type filters out the other case.
takenCurrencyItemItemThe item stack the buyer used to pay (for example scrap or a custom currency item). It is the single Item instance the game is about to move into the machine's inventory.

Return value

Returning null lets the game continue: the currency item is moved into the machine's inventory (or dropped if that fails, or removed for NPC machines). Returning any non-null value stops that default handling, so the paid item is neither stored nor dropped by the game and your plugin becomes responsible for it.

How it works

The hook fires inside VendingMachine.TakeCurrencyItem, which the game calls as part of the buying flow once the buyer's payment has been taken out of their inventory. The original method tries to move the paid item into the machine's own container; if that fails it drops the item at the machine's drop position. The exact same hook also fires from NPCVendingMachine.TakeCurrencyItem for map/NPC shops, where the default path always moves the item into the inventory, removes it from the container and deletes it.

Use vendingMachine to identify the shop (position, owner, net ID) and takenCurrencyItem to inspect what was paid: info.shortname, amount, skin. Declaring the first parameter as VendingMachine makes Oxide skip the call for NPC shops, and declaring NPCVendingMachine does the reverse. This is useful for currency logging, per-shop tax, or refund logic. It only covers the payment item, not the item being sold or the transaction outcome — those belong to CanBuyItem, OnBuyVendingItem and OnGiveSoldItem.

Other signatures

Oxide also calls OnTakeCurrencyItem from other places in the game with these parameter types. Declare the overload you need, or several:

  • object OnTakeCurrencyItem(NPCVendingMachine nPCVendingMachine, Item takenCurrencyItem)

Example plugin: Log machine sales and give a scrap rebate

VendingCurrencyTax.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("VendingCurrencyTax", "RustPluginGenerator", "1.0.0")]
    [Description("Logs scrap payments to vending machines and pays a configurable rebate to the buyer.")]
    public class VendingCurrencyTax : RustPlugin
    {
        private const string PermUse = "vendingcurrencytax.use";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Currency shortname to watch")]
            public string CurrencyShortname = "scrap";

            [JsonProperty("Rebate percentage of paid amount")]
            public int RebatePercent = 10;

            [JsonProperty("Log payments to server console")]
            public bool LogToConsole = true;
        }

        protected override void LoadDefaultConfig() => config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null) throw new Exception();
            }
            catch
            {
                PrintWarning("Configuration file is invalid, using defaults");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Rebate"] = "You received {0} {1} back from your purchase.",
                ["ConsoleLog"] = "{0} paid {1} {2} to machine at {3}",
                ["NotAllowed"] = "This machine does not accept {0}."
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) =>
            string.Format(lang.GetMessage(key, this, userId), args);

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
        }

        private object OnTakeCurrencyItem(VendingMachine vendingMachine, Item takenCurrencyItem)
        {
            if (vendingMachine == null || takenCurrencyItem == null || takenCurrencyItem.info == null)
                return null;

            if (takenCurrencyItem.info.shortname != config.CurrencyShortname)
                return null;

            BasePlayer buyer = takenCurrencyItem.GetOwnerPlayer();
            if (buyer == null || !buyer.IsConnected)
                return null;

            if (config.LogToConsole)
            {
                Puts(Msg("ConsoleLog", null, buyer.displayName, takenCurrencyItem.amount,
                    config.CurrencyShortname, vendingMachine.transform.position.ToString("F0")));
            }

            if (!permission.UserHasPermission(buyer.UserIDString, PermUse))
                return null;

            int rebate = takenCurrencyItem.amount * Mathf.Clamp(config.RebatePercent, 0, 100) / 100;
            if (rebate <= 0)
                return null;

            Item refund = ItemManager.CreateByName(config.CurrencyShortname, rebate, 0);
            if (refund == null)
                return null;

            if (!buyer.inventory.GiveItem(refund))
                refund.Drop(buyer.transform.position, Vector3.zero);

            buyer.ChatMessage(Msg("Rebate", buyer.UserIDString, rebate, config.CurrencyShortname));
            return null;
        }
    }
}

The plugin watches every payment received by admin-owned or owned vending machines. In OnTakeCurrencyItem it reads the paid item's shortname and amount, ignores anything that is not scrap, and sends a short log line to the admin console channel. It also pays back a configurable percentage of the paid scrap as a rebate directly to the buyer's inventory. The buyer is resolved from the currency item's owner while it still has one. Everything is driven by config and lang messages, and the hook returns null so the vanillapayment handling keeps working unchanged.

Common use cases

  • Track shop income

    Read takenCurrencyItem.amount and write a running total per machine into a data file so admins can see which vending machines actually earn scrap.

  • Custom currency rebates

    Give part of the paid scrap or a custom currency item back to the buyer via GiveItem after the purchase, without touching the sale itself.

  • Currency whitelist per shop

    Return a non-null value and drop or delete the paid item when its shortname is not on an allowed list for that machine, effectively refusing the payment type.

Pitfalls

  • Two machine types share the hook

    The same hook fires for NPCVendingMachine. If you declare VendingMachine you will simply not be called for NPC shops; if you want both, use the base type or handle each signature separately.

  • The paid item may have no owner

    takenCurrencyItem.GetOwnerPlayer() relies on parent still pointing at the buyer's container. Null-check it and fall back gracefully instead of assuming a player is present.

  • Blocking does not refund the buyer

    Returning non-null stops the game from storing the item, but nothing is returned to the buyer automatically. Move the item back yourself or it is lost.

Build a plugin with OnTakeCurrencyItem

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Track shop income using the OnTakeCurrencyItem hook, with a config file and a permission
Generate this plugin

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.

Build a plugin with OnTakeCurrencyItem

Generate