If the definition of an upsert is a mix of new records with existing records (to update).
Refering to: https://restfulapi.net/rest-put-vs-post/
PUT needs to be idempotent. This means if you PUT the same payload a second time the system state should not be changed.
If the intended payload is a mix of new and existing and the expected behavior would be to create more new records the second time around then it would seem 'upsert' would line up more closely with POST.
We strive to create mistake tolerant APIs. If you cannot make the PUT idempotent and they must use it they could corrupt the system. On the other hand POST is not expected to be idempotent, so if you sent update-only data (over and over) in the payload (even though this technically violates the idempotency rule for POST because it did not change the state of the system by adding records on subsequent calls) the system would (probably) not be corrupted.
- The spec says PUT "can" add new items and "must" be idempotent
- It says POST "must" add new items and is not idempotent
If you really want to implement an upsert neither is perfect, but if mistakes cause corruption on PUT the API is to blame (its supposed to be idempotent) whereas corruption on POST is "I told you so".
I also like to think about what the API consumer will be looking for. Commonly a UI dev working on a new screen will be looking to add the records the user has added in the UI. He'll be looking for a POST first, then discover that it also handles the PUT side of the equation.
So, neither, but if you have to choose, choose POST.