When transfers are complete, or we detect a failure, then the API fires events that can be captured by your implementation.
You should review the article related to events below.
https://www.sshtools.com/app/manpage/en/article/404545/Capturing-Server-Events
With the entire event list being found on the Java docs at http://maverick-legacy-server-javadocs.s3-website-eu-west-1.amazonaws.com/com/maverick/sshd/events/SSHDEventCodes.html
You will be looking for EVENT_SFTP_FILE_UPLOAD_COMPLETE and EVENT_SFTP_FILE_DOWNLOAD_COMPLETE events which are fired SFTP transfers. There are also EVENT_SCP_FILE_UPLOAD_COMPLETE and EVENT_SCP_FILE_DOWNLOAD_COMPLETE events for SCP.
It is important to note that SFTP is not transactional, so this may not give you 100% accuracy but unfortunately there is no mechanism within the protocol for the client to tell the server if the upload/download has failed. So we rely exclusively on the exchange between both sides adhering to the SFTP protocol, for example, if a client fails to send an SSH_FXP_CLOSE message when uploading a file and instead the connection is disconnected by either side then we would consider that a failed upload. Similarly, if the client is downloading a file and a disconnect happens before we send SSH_FX_EOF status to indicate it has read the entire file we would also consider it a failed download.
There are also some special events for the case where we detect certain scenarios, for example, a file is opened/created but no data transferred then a EVENT_SFTP_FILE_TOUCHED event is generated. Where we have detected both read and writes within the same file session we generate a EVENT_SFTP_FILE_ACCESS event. This is possible because the SFTP protocol provides a random access file system and thus file transfers do not need to be linear.