diff --git a/node/rpc/src/zgs/api.rs b/node/rpc/src/zgs/api.rs
index 32dcfb4..fafd92d 100644
--- a/node/rpc/src/zgs/api.rs
+++ b/node/rpc/src/zgs/api.rs
@@ -65,6 +65,9 @@ pub trait Rpc {
     #[method(name = "getFileInfo")]
     async fn get_file_info(&self, data_root: DataRoot) -> RpcResult<Option<FileInfo>>;
 
+    #[method(name = "getFirstAvailabelFileInfo")]
+    async fn get_first_available_file_info(&self, data_root: DataRoot) -> RpcResult<Option<FileInfo>>;
+
     #[method(name = "getFileInfoByTxSeq")]
     async fn get_file_info_by_tx_seq(&self, tx_seq: u64) -> RpcResult<Option<FileInfo>>;
 
diff --git a/node/rpc/src/zgs/impl.rs b/node/rpc/src/zgs/impl.rs
index 190aa53..be8b297 100644
--- a/node/rpc/src/zgs/impl.rs
+++ b/node/rpc/src/zgs/impl.rs
@@ -171,6 +171,17 @@ impl RpcServer for RpcServerImpl {
         Ok(Some(self.get_file_info_by_tx(tx).await?))
     }
 
+    async fn get_first_available_file_info(&self, data_root: DataRoot) -> RpcResult<Option<FileInfo>> {
+        debug!(%data_root, "zgs_getFirstAvailableFileInfo");
+
+        let tx = match self.ctx.log_store.get_first_available_tx_by_data_root(&data_root).await? {
+            Some(tx) => tx,
+            None => return Ok(None),
+        };
+
+        Ok(Some(self.get_file_info_by_tx(tx).await?))
+    }
+
     async fn get_file_info_by_tx_seq(&self, tx_seq: u64) -> RpcResult<Option<FileInfo>> {
         debug!(%tx_seq, "zgs_getFileInfoByTxSeq");
 
diff --git a/node/storage-async/src/lib.rs b/node/storage-async/src/lib.rs
index b564f42..ce0dd64 100644
--- a/node/storage-async/src/lib.rs
+++ b/node/storage-async/src/lib.rs
@@ -71,6 +71,12 @@ impl Store {
             .await
     }
 
+    pub async fn get_first_available_tx_by_data_root(&self, data_root: &DataRoot) -> Result<Option<Transaction>> {
+        let root = *data_root;
+        self.spawn(move |store| store.get_first_available_tx_by_data_root(&root))
+            .await
+    }
+
     pub async fn get_config_decoded<K: AsRef<[u8]> + Send + Sync, T: Decode + Send + 'static>(
         &self,
         key: &K,
diff --git a/node/storage/src/log_store/log_manager.rs b/node/storage/src/log_store/log_manager.rs
index 6a024e2..aa548fe 100644
--- a/node/storage/src/log_store/log_manager.rs
+++ b/node/storage/src/log_store/log_manager.rs
@@ -548,6 +548,18 @@ impl LogStoreRead for LogManager {
         Ok(seq_list.first().cloned())
     }
 
+    fn get_available_tx_seq_by_data_root(&self, data_root: &DataRoot) -> crate::error::Result<Option<u64>> {
+        let seq_list = self.tx_store.get_tx_seq_list_by_data_root(data_root)?;
+        for tx_seq in &seq_list {
+            if self.tx_store.check_tx_completed(*tx_seq)? && !self.tx_store.check_tx_pruned(*tx_seq)? {
+                // Return the first finalized and unpruned tx if possible. This means the tx data can be downloaded
+                return Ok(Some(*tx_seq));
+            }
+        }
+        // No tx is finalized and unpruned, return None
+        Ok(None)
+    }
+
     fn get_chunk_with_proof_by_tx_and_index(
         &self,
         tx_seq: u64,
diff --git a/node/storage/src/log_store/mod.rs b/node/storage/src/log_store/mod.rs
index fc2f82f..0fc9370 100644
--- a/node/storage/src/log_store/mod.rs
+++ b/node/storage/src/log_store/mod.rs
@@ -35,6 +35,8 @@ pub trait LogStoreRead: LogStoreChunkRead {
     /// Otherwise, return the first finalized tx.
     fn get_tx_seq_by_data_root(&self, data_root: &DataRoot) -> Result<Option<u64>>;
 
+    fn get_available_tx_seq_by_data_root(&self, data_root: &DataRoot) -> Result<Option<u64>>;
+
     /// If all txs are not finalized, return the first one.
     /// Otherwise, return the first finalized tx.
     fn get_tx_by_data_root(&self, data_root: &DataRoot) -> Result<Option<Transaction>> {
@@ -44,6 +46,13 @@ pub trait LogStoreRead: LogStoreChunkRead {
         }
     }
 
+    fn get_first_available_tx_by_data_root(&self, data_root: &DataRoot) -> Result<Option<Transaction>> {
+        match self.get_available_tx_seq_by_data_root(data_root)? {
+            Some(seq) => self.get_tx_by_seq_number(seq),
+            None => Ok(None),
+        }
+    }
+
     fn get_chunk_with_proof_by_tx_and_index(
         &self,
         tx_seq: u64,