Yeah, its technically impossible but practically doable.

Have a table, with id and status and do a "poor man's transaction"

1. Receive refund message
2. Write "id, refund-started, date"
4. If insertion fails due to unique constraint - throw error get human to look
5. Call payment gateway API to issue refund
3. update "id, refund-paid, date"

Second audit job

1. loop through all "refund-started" date < some time ago where would expect completion to have happened
2. Raise problem with human to check if the refund completed or not.