I recently had to deal with a similar issue, mobile app that had to connect to an API, but the phone would not have internet access over 80% of the time and once internet access becomes available, it needs to sync.
I built a queue on top of local-storage, just like in Kafka, you have one field that is simply a pointer to where in the queue you are and then the everything else is queue data with a number showing its position.
So a queue would look something like (localstorage needs a key-value pair):
pos=387
q387 => {jsondata}
q388 => {jsondata}
q389 => {jsondata}
As soon as an internet connection is established, pos would be checked, that would return 387, I'd lookup q387 and sync that command with the server, increment pos to 388 and delete q387. By including a GUID + date inside each entity generated in the UI, I can see if a create entity was already synced or not, if it was, I just ignore it and jump to the next one.
If you create an entity and no internet connection is available, keep the create command in the queue, if you update that entity, you can merge the update into the create and merge any subsequent updates with the create action until the create + updates could be synced, but this is the more complicated route to go.
If the create synced and a version number was returned, somebody else updates that created entity, you update it again and your version is different, you have a conflict and dialog should popup allowing you to merge your changes with the changes that was made to the entity by someone else (similar to git - accept theirs, accept mine, merge line by line)