diff --git a/Spigot-API-Patches/0123-InventoryCloseEvent-Reason-API.patch b/Spigot-API-Patches/0123-InventoryCloseEvent-Reason-API.patch
new file mode 100644
index 0000000000..d3e8be94ad
--- /dev/null
+++ b/Spigot-API-Patches/0123-InventoryCloseEvent-Reason-API.patch
@@ -0,0 +1,92 @@
+From eeec38e29cc2041734e18b87f80400f63fa7734c Mon Sep 17 00:00:00 2001
+From: Aikar <aikar@aikar.co>
+Date: Tue, 3 Jul 2018 21:52:52 -0400
+Subject: [PATCH] InventoryCloseEvent Reason API
+
+Allows you to determine why an inventory was closed, enabling plugin developers
+to "confirm" things based on if it was player triggered close or not.
+
+diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java
+index dd95773e..3924d00c 100644
+--- a/src/main/java/org/bukkit/entity/HumanEntity.java
++++ b/src/main/java/org/bukkit/entity/HumanEntity.java
+@@ -137,6 +137,13 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, Permissible, Inv
+      */
+     public void closeInventory();
+ 
++    // Paper start
++    /**
++     * Force-closes the currently open inventory view for this player, if any.
++     */
++    public void closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason);
++    // Paper end
++
+     /**
+      * Returns the ItemStack currently in your hand, can be empty.
+      *
+diff --git a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java
+index 19889b27..e6e45b93 100644
+--- a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java
++++ b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java
+@@ -11,8 +11,58 @@ import org.bukkit.inventory.InventoryView;
+ public class InventoryCloseEvent extends InventoryEvent {
+     private static final HandlerList handlers = new HandlerList();
+ 
++    // Paper start
++    private final Reason reason;
++    public Reason getReason() {
++        return reason;
++    }
++
++    public enum Reason {
++        /**
++         * Unknown reason
++         */
++        UNKNOWN,
++        /**
++         * Player is teleporting
++         */
++        TELEPORT,
++        /**
++         * Player is no longer permitted to use this inventory
++         */
++        CANT_USE,
++        /**
++         * The chunk the inventory was in was unloaded
++         */
++        UNLOADED,
++        /**
++         * Opening new inventory instead
++         */
++        OPEN_NEW,
++        /**
++         * Closed
++         */
++        PLAYER,
++        /**
++         * Closed due to disconnect
++         */
++        DISCONNECT,
++        /**
++         * The player died
++         */
++        DEATH,
++        /**
++         * Closed by Bukkit API
++         */
++        PLUGIN,
++    }
+     public InventoryCloseEvent(InventoryView transaction) {
++        this(transaction, Reason.UNKNOWN);
++    }
++
++    public InventoryCloseEvent(InventoryView transaction, Reason reason) {
+         super(transaction);
++        this.reason = reason;
++        // Paper end
+     }
+ 
+     /**
+-- 
+2.18.0
+
diff --git a/Spigot-Server-Patches/0322-InventoryCloseEvent-Reason-API.patch b/Spigot-Server-Patches/0322-InventoryCloseEvent-Reason-API.patch
new file mode 100644
index 0000000000..ef36008559
--- /dev/null
+++ b/Spigot-Server-Patches/0322-InventoryCloseEvent-Reason-API.patch
@@ -0,0 +1,189 @@
+From 579bde3a655017237446cb5e5589764243e25609 Mon Sep 17 00:00:00 2001
+From: Aikar <aikar@aikar.co>
+Date: Tue, 3 Jul 2018 21:56:23 -0400
+Subject: [PATCH] InventoryCloseEvent Reason API
+
+Allows you to determine why an inventory was closed, enabling plugin developers
+to "confirm" things based on if it was player triggered close or not.
+
+diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
+index 7cd537a59..ddd5ed57d 100644
+--- a/src/main/java/net/minecraft/server/Chunk.java
++++ b/src/main/java/net/minecraft/server/Chunk.java
+@@ -836,7 +836,7 @@ public class Chunk {
+                 {
+                     if ( h instanceof org.bukkit.craftbukkit.entity.CraftHumanEntity )
+                     {
+-                       ( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory();
++                       ( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
+                     }
+                 }
+             }
+@@ -861,7 +861,7 @@ public class Chunk {
+                     {
+                         if ( h instanceof org.bukkit.craftbukkit.entity.CraftHumanEntity )
+                         {
+-                           ( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory();
++                           ( (org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
+                         }
+                     }
+                 }
+diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java
+index 0b51903e2..aa0b27f0e 100644
+--- a/src/main/java/net/minecraft/server/EntityHuman.java
++++ b/src/main/java/net/minecraft/server/EntityHuman.java
+@@ -145,7 +145,7 @@ public abstract class EntityHuman extends EntityLiving {
+ 
+         super.B_();
+         if (!this.world.isClientSide && this.activeContainer != null && !this.activeContainer.canUse(this)) {
+-            this.closeInventory();
++            this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
+             this.activeContainer = this.defaultContainer;
+         }
+ 
+@@ -294,6 +294,13 @@ public abstract class EntityHuman extends EntityLiving {
+         return this.getHealth() <= 0.0F || this.isSleeping();
+     }
+ 
++    // Paper start - unused code, but to keep signatures aligned
++    public void closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
++        closeInventory();
++        this.activeContainer = this.defaultContainer;
++    }
++    // Paper end
++
+     public void closeInventory() {
+         this.activeContainer = this.defaultContainer;
+     }
+diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
+index cce3f98da..4ff505cfa 100644
+--- a/src/main/java/net/minecraft/server/EntityPlayer.java
++++ b/src/main/java/net/minecraft/server/EntityPlayer.java
+@@ -287,7 +287,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
+         }
+         // Paper end
+         if (!this.world.isClientSide && !this.activeContainer.canUse(this)) {
+-            this.closeInventory();
++            this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
+             this.activeContainer = this.defaultContainer;
+         }
+ 
+@@ -483,7 +483,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
+             this.inventory.clear();
+         }
+ 
+-        this.closeInventory();
++        this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DEATH); // Paper
+         this.setSpectatorTarget(this); // Remove spectated target
+         // CraftBukkit end
+ 
+@@ -837,7 +837,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
+             this.a((new ChatMessage("container.spectatorCantOpen", new Object[0])).setChatModifier((new ChatModifier()).setColor(EnumChatFormat.RED)), true);
+         } else {
+             if (this.activeContainer != this.defaultContainer) {
+-                this.closeInventory();
++                this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper
+             }
+ 
+             if (iinventory instanceof ITileInventory) {
+@@ -903,7 +903,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
+         }
+         // CraftBukkit end
+         if (this.activeContainer != this.defaultContainer) {
+-            this.closeInventory();
++            this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper
+         }
+ 
+         this.nextContainerCounter();
+@@ -968,7 +968,12 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
+     }
+ 
+     public void closeInventory() {
+-        CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit
++        // Paper start
++        closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNKNOWN);
++    }
++    public void closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
++        CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
++        // Paper end
+         this.playerConnection.sendPacket(new PacketPlayOutCloseWindow(this.activeContainer.windowId));
+         this.r();
+     }
+diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
+index a5faa6a0a..96d2dee65 100644
+--- a/src/main/java/net/minecraft/server/PlayerConnection.java
++++ b/src/main/java/net/minecraft/server/PlayerConnection.java
+@@ -1758,7 +1758,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
+         PlayerConnectionUtils.ensureMainThread(packetplayinclosewindow, this, this.player.x());
+ 
+         if (this.player.isFrozen()) return; // CraftBukkit
+-        CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit
++        CraftEventFactory.handleInventoryCloseEvent(this.player, org.bukkit.event.inventory.InventoryCloseEvent.Reason.PLAYER); // CraftBukkit // Paper
+ 
+         this.player.r();
+     }
+diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
+index b478f385a..eaaa54acd 100644
+--- a/src/main/java/net/minecraft/server/PlayerList.java
++++ b/src/main/java/net/minecraft/server/PlayerList.java
+@@ -423,7 +423,7 @@ public abstract class PlayerList {
+         entityplayer.b(StatisticList.f);
+ 
+         // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it
+-        org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(entityplayer);
++        org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(entityplayer, org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper
+ 
+         PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(entityplayer), "\u00A7e" + entityplayer.getName() + " left the game");
+         cserver.getPluginManager().callEvent(playerQuitEvent);
+diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+index d85b5defc..05ca403e8 100644
+--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+@@ -401,8 +401,13 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
+     }
+ 
+     public void closeInventory() {
+-        getHandle().closeInventory();
++        // Paper start
++        getHandle().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.PLUGIN);
+     }
++    public void closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
++        getHandle().closeInventory(reason);
++    }
++    // Paper end
+ 
+     public boolean isBlocking() {
+         return getHandle().isBlocking();
+diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+index fd47065c6..53f973615 100644
+--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+@@ -640,7 +640,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
+ 
+         // Close any foreign inventory
+         if (getHandle().activeContainer != getHandle().defaultContainer) {
+-            getHandle().closeInventory();
++            getHandle().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); // Paper
+         }
+ 
+         // Check if the fromWorld and toWorld are the same.
+diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+index 248873fb4..c6f447205 100644
+--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+@@ -927,8 +927,10 @@ public class CraftEventFactory {
+         return event;
+     }
+ 
+-    public static void handleInventoryCloseEvent(EntityHuman human) {
+-        InventoryCloseEvent event = new InventoryCloseEvent(human.activeContainer.getBukkitView());
++    // Paper start
++    public static void handleInventoryCloseEvent(EntityHuman human, org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
++        InventoryCloseEvent event = new InventoryCloseEvent(human.activeContainer.getBukkitView(), reason);
++        // Paper end
+         human.world.getServer().getPluginManager().callEvent(event);
+         human.activeContainer.transferTo(human.defaultContainer, human.getBukkitEntity());
+     }
+-- 
+2.18.0
+