On POSIX/Linux, AFAIK the only "real" low-level async I/O API that exists is IO uring (you put work in the ring and it completes at some point in the future). All other APIs are basically variations on the I/O multiplexing model (poll() / epoll() / select()).
There is O_NONBLOCK, but all that does IIUC (correct me if I'm wrong) is to make sure that I/O calls return EAGAIN when too much work is posted at once to do it without blocking, and you need to poll() it again