I'm afraid the answers so far haven't been as clear as they should. You want (), and no one at all will be surprised by this use of ().
() is the type that says the value should contain no information. There is one possible value; and since all values of () are the same, there's no information contained in the choice of value. It is completely standard to use () for situations exactly like this, where a type was designed with the possibility of some information being communicated, but in this case there's really nothing to say. Your situation is exactly analogous to common uses, like IO () as the type for IO actions with no result.
So where does Void fit in? Void is a type that cannot occur at all! There are NO possible values for Void. The result is that there are no possible values for Foo Void e. And therefore, if you define Batch i e using Void, the only values of Batch i e are those that have an empty list, so Batch i e is isomorphic to Int. This is NOT what you want.
(The above is ignoring bottoms. It's true that you can create other possible values of Foo Void e by using undefined as a value for Void. This isn't a road you want to go down.)