Usually a merchant will generate a (psuedo)random 32-byte value and hash it. This becomes the payment_hash which identifies the payment in the network and is transferred to the purchaser in an invoice. When the user makes the payment, they send this payment_hash with an onion packet, as a conditional payment which will complete if the preimage of the hash is provided. Each hop will forward this payment hash, until the destination must reveal its preimage to the penultimate hop in order to complete the transfer of funds. The hops will then transfer the preimage backwards through the route until it reaches the purchaser, and serves as proof that the payment suceeded, under the assumption that nobody other than the merchant could know the preimage. This prevents reuse of a payment_hash because an intermediate hop may have knowledge of a preimage which has been used already.
The HTLCs are exactly the same with spontanious payments, the difference is that the purchaser creates the payment preimage and payment_hash. The payment_hash is transferred as usual, but the preimage is encrypted inside the onion routed packet in a way that only the merchant can decrypt it.
The onion packet has 12 bytes of padding at each hop which can be utilized to send additional data, but also, the onion packet can have "virtual hops" after the destination hop of the payment, which the merchant can decrypt. These virtual hops can contain 32 bytes of data because the usual amount, SCID and cltv fields can be repurposed to hold additional data, since you're not forwarding any payment beyond the destination. A couple of bytes are used as flags to indicate the type of data, and the aggregation of the extra data in the virtual hops is known as the Extra Onion Blob (EOB).
The entire onion packet remains the same size, so the amount of additional data which can be transferred with the payment is still limited, with the more hops required for actual payment, the fewer virtual hops. A spontanious payment requires at least 2 virtual hops because there are flags and a 32 byte primage to encode into the EOB.