An "idempotency key" can also just be a resource URL. If you use an idempotent HTTP verb this works wonders and is also more RESTful:
PUT example.com/orders/abc123/charged
The first PUT starts charging. If the client disconnects and retries while the original charge process is already running on the server, the server can just await this already running process. And if the order is already charged, the server can just return the outcome of the charge.
As long as there is a unique URL for every state a resource such as an order can be in, you can uniquely identify every action on it on the server-side and re-attach to running processes.
Using unique URLs for each state is the main idea behind REST (REpresentational State Transfer). REST namely means just this: representing server states as resources (URLs).
PUT example.com/orders/abc123/charged
The first PUT starts charging. If the client disconnects and retries while the original charge process is already running on the server, the server can just await this already running process. And if the order is already charged, the server can just return the outcome of the charge.
As long as there is a unique URL for every state a resource such as an order can be in, you can uniquely identify every action on it on the server-side and re-attach to running processes.
Using unique URLs for each state is the main idea behind REST (REpresentational State Transfer). REST namely means just this: representing server states as resources (URLs).