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
@@ -280,41 +280,84 @@
     }
 }
 
-impl ChronikElectrumRPCBlockchainEndpoint {
-    async fn transaction_get(&self, params: Value) -> Result<Value, RPCError> {
-        let txid_hex: Value;
-        let verbose: Value;
-        match params {
-            Value::Array(arr) => {
-                txid_hex = arr
-                    .first()
-                    .ok_or(RPCError::InvalidParams(
-                        "Missing mandatory 'txid' parameter",
-                    ))?
-                    .clone();
-                verbose = match arr.get(1) {
-                    Some(val) => val.clone(),
-                    None => Value::Bool(false),
-                };
+macro_rules! get_positional_param {
+    ($arr:expr, $index:expr, $name:expr) => {{
+        $arr.get($index)
+            .ok_or(RPCError::InvalidParams(concat!(
+                "Missing mandatory '",
+                $name,
+                "' parameter"
+            )))?
+            .clone()
+    }};
+}
+
+macro_rules! get_optional_positional_param {
+    ($arr:expr, $index:expr, $default:expr) => {{
+        match $arr.get($index) {
+            Some(val) => val.clone(),
+            None => $default,
+        }
+    }};
+}
+
+macro_rules! get_named_param {
+    ($obj:expr, $key:expr) => {{
+        match $obj.get($key) {
+            Some(value) => Ok(value.clone()),
+            None => Err(RPCError::InvalidParams(concat!(
+                "Missing mandatory '",
+                $key,
+                "' parameter"
+            ))),
+        }?
+    }};
+}
+
+macro_rules! get_optional_named_param {
+    ($obj:expr, $key:expr, $default:expr) => {{
+        match $obj.get($key) {
+            Some(value) => value.clone(),
+            None => $default,
+        }
+    }};
+}
+
+macro_rules! get_param {
+    ($params:expr, $index:expr, $key:expr) => {{
+        match $params {
+            Value::Array(ref arr) => {
+                Ok(get_positional_param!(arr, $index, $key))
             }
-            Value::Object(obj) => {
-                txid_hex = match obj.get("txid") {
-                    Some(txid) => Ok(txid.clone()),
-                    None => Err(RPCError::InvalidParams(
-                        "Missing mandatory 'txid' parameter",
-                    )),
-                }?;
-                verbose = match obj.get("verbose") {
-                    Some(verbose) => verbose.clone(),
-                    None => Value::Bool(false),
-                };
+            Value::Object(ref obj) => Ok(get_named_param!(obj, $key)),
+            _ => Err(RPCError::InvalidParams(
+                "'params' must be an array or an object",
+            )),
+        }
+    }};
+}
+
+macro_rules! get_optional_param {
+    ($params:expr, $index:expr, $key:expr, $default:expr) => {{
+        match $params {
+            Value::Array(ref arr) => {
+                Ok(get_optional_positional_param!(arr, $index, $default))
             }
-            _ => {
-                return Err(RPCError::InvalidParams(
-                    "'params' must be an array or an object",
-                ))
+            Value::Object(ref obj) => {
+                Ok(get_optional_named_param!(obj, $key, $default))
             }
-        };
+            _ => Err(RPCError::InvalidParams(
+                "'params' must be an array or an object",
+            )),
+        }
+    }};
+}
+
+impl ChronikElectrumRPCBlockchainEndpoint {
+    async fn transaction_get(&self, params: Value) -> Result<Value, RPCError> {
+        let txid_hex = get_param!(params, 0, "txid")?;
+        let verbose =
+            get_optional_param!(params, 1, "verbose", Value::Bool(false))?;
         let txid_hex = match txid_hex {
             Value::String(s) => Ok(s),
             _ => Err(RPCError::InvalidParams(