diff --git a/chronik/chronik-http/src/electrum.rs b/chronik/chronik-http/src/electrum.rs
--- a/chronik/chronik-http/src/electrum.rs
+++ b/chronik/chronik-http/src/electrum.rs
@@ -4,9 +4,12 @@
 
 //! Module for [`ChronikElectrumServer`].
 
+use std::str::FromStr;
 use std::{net::SocketAddr, sync::Arc};
 
 use abc_rust_error::Result;
+use bitcoinsuite_core::tx::TxId;
+use chronik_util::log;
 use futures::future;
 use karyon_jsonrpc::{RPCError, RPCMethod, RPCService, Server};
 use karyon_net::{Addr, Endpoint};
@@ -34,8 +37,8 @@
 #[derive(Debug)]
 pub struct ChronikElectrumServer {
     hosts: Vec<SocketAddr>,
-    _indexer: ChronikIndexerRef,
-    _node: NodeRef,
+    indexer: ChronikIndexerRef,
+    node: NodeRef,
 }
 
 /// Errors for [`ChronikElectrumServer`].
@@ -52,14 +55,18 @@
 
 struct ChronikElectrumRPCServerEndpoint {}
 
+struct ChronikElectrumRPCBlockchainEndpoint {
+    indexer: ChronikIndexerRef,
+    node: NodeRef,
+}
+
 impl ChronikElectrumServer {
     /// Binds the Chronik server on the given hosts
     pub fn setup(params: ChronikElectrumServerParams) -> Result<Self> {
         Ok(ChronikElectrumServer {
             hosts: params.hosts,
-            // FIXME below params are unused but will be used in the future
-            _indexer: params.indexer,
-            _node: params.node,
+            indexer: params.indexer,
+            node: params.node,
         })
     }
 
@@ -68,12 +75,18 @@
         // The behavior is to bind the endpoint name to its method name like so:
         // endpoint.method as the name of the RPC
         let server_endpoint = Arc::new(ChronikElectrumRPCServerEndpoint {});
+        let blockchain_endpoint =
+            Arc::new(ChronikElectrumRPCBlockchainEndpoint {
+                indexer: self.indexer,
+                node: self.node,
+            });
+        let endpoints = (server_endpoint, blockchain_endpoint);
 
         let servers = self
             .hosts
             .into_iter()
-            .zip(std::iter::repeat(server_endpoint))
-            .map(|(host, server_endpoint)| {
+            .zip(std::iter::repeat(endpoints))
+            .map(|(host, endpoints)| {
                 Box::pin(async move {
                     // Don't use the karyon Endpoint parsing as it doesn't
                     // appear to support IPv6.
@@ -88,7 +101,8 @@
                         FailedBindingAddress(host, err.to_string())
                     })?;
                     let server = builder
-                        .service(server_endpoint)
+                        .service(endpoints.0)
+                        .service(endpoints.1)
                         .build()
                         .await
                         .map_err(|err| ServingFailed(err.to_string()))?;
@@ -127,3 +141,56 @@
         Ok(Value::Null)
     }
 }
+
+impl RPCService for ChronikElectrumRPCBlockchainEndpoint {
+    fn name(&self) -> String {
+        "blockchain".to_string()
+    }
+
+    fn get_method(&self, name: &str) -> Option<RPCMethod<'_>> {
+        match name {
+            "transaction.get" => Some(Box::new(move |params: Value| {
+                Box::pin(self.transaction_get(params))
+            })),
+            _ => None,
+        }
+    }
+}
+
+impl ChronikElectrumRPCBlockchainEndpoint {
+    async fn transaction_get(&self, params: Value) -> Result<Value, RPCError> {
+        let txid = match params {
+            Value::Array(arr) => arr
+                .get(0)
+                .ok_or(RPCError::InvalidParams("empty positional parameters"))
+                .cloned(),
+            Value::Object(obj) => match obj.get("txid") {
+                Some(txid) => Ok(txid.clone()),
+                None => Err(RPCError::InvalidParams(
+                    "missing txid in named parameters",
+                )),
+            },
+            _ => Err(RPCError::InvalidParams(
+                "params must be an array or an object",
+            )),
+        }?;
+        let txid = match txid {
+            Value::String(s) => Ok(s),
+            _ => Err(RPCError::InvalidParams(
+                "txid must be a hexadecimal string",
+            )),
+        }?;
+        let txid = TxId::from_str(&*txid)
+            .or(Err(RPCError::InvalidParams("failed to parse txid")))?;
+
+        log!("{txid}\n");
+        let indexer = self.indexer.read().await;
+        let raw_tx = indexer
+            .txs(&self.node)
+            .raw_tx_by_id(&txid)
+            .or(Err(RPCError::InvalidRequest("Unknown txid")))?;
+
+        log!("{raw_tx:?}\n");
+        Ok(Value::Null)
+    }
+}