diff --git a/src/lsps2/client.rs b/src/lsps2/client.rs
index d0729c4..ac79f99 100644
--- a/src/lsps2/client.rs
+++ b/src/lsps2/client.rs
@@ -13,7 +13,7 @@ use crate::events::{Event, EventQueue};
 use crate::lsps0::msgs::{ProtocolMessageHandler, RequestId, ResponseError};
 use crate::lsps2::event::LSPS2ClientEvent;
 use crate::message_queue::MessageQueue;
-use crate::prelude::{HashMap, String, ToString};
+use crate::prelude::{HashMap, HashSet, String};
 use crate::sync::{Arc, Mutex, RwLock};
 
 use lightning::ln::msgs::{ErrorAction, LightningError};
@@ -23,6 +23,7 @@ use lightning::util::logger::Level;
 
 use bitcoin::secp256k1::PublicKey;
 
+use core::default::Default;
 use core::ops::Deref;
 
 use crate::lsps2::msgs::{
@@ -32,7 +33,21 @@ use crate::lsps2::msgs::{
 
 /// Client-side configuration options for JIT channels.
 #[derive(Clone, Debug, Copy)]
-pub struct LSPS2ClientConfig {}
+pub struct LSPS2ClientConfig {
+	/// Trust the LSP to create a valid channel funding transaction and have it confirmed on-chain.
+	///
+	/// TODO: If set to `false`, we'll only release the pre-image after we see an on-chain
+	/// confirmation of the channel's funding transaction.
+	///
+	/// Defaults to `true`.
+	pub client_trusts_lsp: bool,
+}
+
+impl Default for LSPS2ClientConfig {
+	fn default() -> Self {
+		Self { client_trusts_lsp: true }
+	}
+}
 
 struct ChannelStateError(String);
 
@@ -42,44 +57,13 @@ impl From<ChannelStateError> for LightningError {
 	}
 }
 
-struct InboundJITChannelConfig {
-	pub user_id: u128,
-	pub payment_size_msat: Option<u64>,
-}
-
 #[derive(PartialEq, Debug)]
 enum InboundJITChannelState {
-	MenuRequested,
-	PendingMenuSelection,
 	BuyRequested,
 	PendingPayment { client_trusts_lsp: bool, intercept_scid: InterceptScid },
 }
 
 impl InboundJITChannelState {
-	fn info_received(&self) -> Result<Self, ChannelStateError> {
-		match self {
-			InboundJITChannelState::MenuRequested => {
-				Ok(InboundJITChannelState::PendingMenuSelection)
-			}
-			state => Err(ChannelStateError(format!(
-				"Received unexpected get_info response.  JIT Channel was in state: {:?}",
-				state
-			))),
-		}
-	}
-
-	fn opening_fee_params_selected(&self) -> Result<Self, ChannelStateError> {
-		match self {
-			InboundJITChannelState::PendingMenuSelection => {
-				Ok(InboundJITChannelState::BuyRequested)
-			}
-			state => Err(ChannelStateError(format!(
-				"Opening fee params selected when JIT Channel was in state: {:?}",
-				state
-			))),
-		}
-	}
-
 	fn invoice_params_received(
 		&self, client_trusts_lsp: bool, intercept_scid: InterceptScid,
 	) -> Result<Self, ChannelStateError> {
@@ -97,32 +81,13 @@ impl InboundJITChannelState {
 
 struct InboundJITChannel {
 	state: InboundJITChannelState,
-	config: InboundJITChannelConfig,
+	user_channel_id: u128,
+	payment_size_msat: Option<u64>,
 }
 
 impl InboundJITChannel {
-	fn new(user_id: u128, payment_size_msat: Option<u64>) -> Self {
-		Self {
-			config: InboundJITChannelConfig { user_id, payment_size_msat },
-			state: InboundJITChannelState::MenuRequested,
-		}
-	}
-
-	fn info_received(&mut self) -> Result<(), LightningError> {
-		self.state = self.state.info_received()?;
-		Ok(())
-	}
-
-	fn opening_fee_params_selected(&mut self) -> Result<(), LightningError> {
-		self.state = self.state.opening_fee_params_selected()?;
-
-		match self.state {
-			InboundJITChannelState::BuyRequested => Ok(()),
-			_ => Err(LightningError {
-				action: ErrorAction::IgnoreAndLog(Level::Error),
-				err: "impossible state transition".to_string(),
-			}),
-		}
+	fn new(user_channel_id: u128, payment_size_msat: Option<u64>) -> Self {
+		Self { user_channel_id, payment_size_msat, state: InboundJITChannelState::BuyRequested }
 	}
 
 	fn invoice_params_received(
@@ -135,26 +100,16 @@ impl InboundJITChannel {
 
 struct PeerState {
 	inbound_channels_by_id: HashMap<u128, InboundJITChannel>,
-	request_to_cid: HashMap<RequestId, u128>,
+	pending_get_info_requests: HashSet<RequestId>,
+	pending_buy_requests: HashMap<RequestId, u128>,
 }
 
 impl PeerState {
 	fn new() -> Self {
 		let inbound_channels_by_id = HashMap::new();
-		let request_to_cid = HashMap::new();
-		Self { inbound_channels_by_id, request_to_cid }
-	}
-
-	fn insert_inbound_channel(&mut self, jit_channel_id: u128, channel: InboundJITChannel) {
-		self.inbound_channels_by_id.insert(jit_channel_id, channel);
-	}
-
-	fn insert_request(&mut self, request_id: RequestId, jit_channel_id: u128) {
-		self.request_to_cid.insert(request_id, jit_channel_id);
-	}
-
-	fn remove_inbound_channel(&mut self, jit_channel_id: u128) {
-		self.inbound_channels_by_id.remove(&jit_channel_id);
+		let pending_get_info_requests = HashSet::new();
+		let pending_buy_requests = HashMap::new();
+		Self { inbound_channels_by_id, pending_get_info_requests, pending_buy_requests }
 	}
 }
 
@@ -167,7 +122,7 @@ where
 	pending_messages: Arc<MessageQueue>,
 	pending_events: Arc<EventQueue>,
 	per_peer_state: RwLock<HashMap<PublicKey, Mutex<PeerState>>>,
-	_config: LSPS2ClientConfig,
+	config: LSPS2ClientConfig,
 }
 
 impl<ES: Deref> LSPS2ClientHandler<ES>
@@ -184,38 +139,34 @@ where
 			pending_messages,
 			pending_events,
 			per_peer_state: RwLock::new(HashMap::new()),
-			_config: config,
+			config,
 		}
 	}
 
-	/// Initiate the creation of an invoice that when paid will open a channel
-	/// with enough inbound liquidity to be able to receive the payment.
+	/// Request the channel opening parameters from the LSP.
 	///
-	/// `counterparty_node_id` is the node_id of the LSP you would like to use.
+	/// This initiates the JIT-channel flow that, at the end of it, will have the LSP
+	/// open a channel with sufficient inbound liquidity to be able to receive the payment.
 	///
-	/// If `payment_size_msat` is [`Option::Some`] then the invoice will be for a fixed amount
-	/// and MPP can be used to pay it.
+	/// The user will receive the LSP's response via an [`OpeningParametersReady`] event.
 	///
-	/// If `payment_size_msat` is [`Option::None`] then the invoice can be for an arbitrary amount
-	/// but MPP can no longer be used to pay it.
+	/// `counterparty_node_id` is the `node_id` of the LSP you would like to use.
 	///
-	/// `token` is an optional String that will be provided to the LSP.
+	/// `token` is an optional `String` that will be provided to the LSP.
 	/// It can be used by the LSP as an API key, coupon code, or some other way to identify a user.
-	pub fn create_invoice(
-		&self, counterparty_node_id: PublicKey, payment_size_msat: Option<u64>,
-		token: Option<String>, user_channel_id: u128,
-	) {
-		let jit_channel_id = self.generate_jit_channel_id();
-		let channel = InboundJITChannel::new(user_channel_id, payment_size_msat);
-
-		let mut outer_state_lock = self.per_peer_state.write().unwrap();
-		let inner_state_lock =
-			outer_state_lock.entry(counterparty_node_id).or_insert(Mutex::new(PeerState::new()));
-		let mut peer_state_lock = inner_state_lock.lock().unwrap();
-		peer_state_lock.insert_inbound_channel(jit_channel_id, channel);
-
+	///
+	/// [`OpeningParametersReady`]: crate::lsps2::event::LSPS2ClientEvent::OpeningParametersReady
+	pub fn request_opening_params(&self, counterparty_node_id: PublicKey, token: Option<String>) {
 		let request_id = crate::utils::generate_request_id(&self.entropy_source);
-		peer_state_lock.insert_request(request_id.clone(), jit_channel_id);
+
+		{
+			let mut outer_state_lock = self.per_peer_state.write().unwrap();
+			let inner_state_lock = outer_state_lock
+				.entry(counterparty_node_id)
+				.or_insert(Mutex::new(PeerState::new()));
+			let mut peer_state_lock = inner_state_lock.lock().unwrap();
+			peer_state_lock.pending_get_info_requests.insert(request_id.clone());
+		}
 
 		self.pending_messages.enqueue(
 			&counterparty_node_id,
@@ -224,65 +175,58 @@ where
 		);
 	}
 
-	/// Used by client to confirm which channel parameters to use for the JIT Channel buy request.
+	/// Confirms a set of chosen channel opening parameters to use for the JIT channel and
+	/// requests the necessary invoice generation parameters from the LSP.
+	///
+	/// Should be called in response to receiving a [`OpeningParametersReady`] event.
+	///
+	/// The user will receive the LSP's response via an [`InvoiceParametersReady`] event.
+	///
+	/// The user needs to provide a locally unique `user_channel_id` which will be used for
+	/// tracking the channel state.
+	///
+	/// If `payment_size_msat` is [`Option::Some`] then the invoice will be for a fixed amount
+	/// and MPP can be used to pay it.
+	///
+	/// If `payment_size_msat` is [`Option::None`] then the invoice can be for an arbitrary amount
+	/// but MPP can no longer be used to pay it.
+	///
 	/// The client agrees to paying an opening fee equal to
 	/// `max(min_fee_msat, proportional*(payment_size_msat/1_000_000))`.
 	///
-	/// Should be called in response to receiving a [`LSPS2ClientEvent::GetInfoResponse`] event.
-	///
-	/// [`LSPS2ClientEvent::GetInfoResponse`]: crate::lsps2::event::LSPS2ClientEvent::GetInfoResponse
-	pub fn opening_fee_params_selected(
-		&self, counterparty_node_id: PublicKey, jit_channel_id: u128,
-		opening_fee_params: OpeningFeeParams,
+	/// [`OpeningParametersReady`]: crate::lsps2::event::LSPS2ClientEvent::OpeningParametersReady
+	/// [`InvoiceParametersReady`]: crate::lsps2::event::LSPS2ClientEvent::InvoiceParametersReady
+	pub fn select_opening_params(
+		&self, counterparty_node_id: PublicKey, user_channel_id: u128,
+		payment_size_msat: Option<u64>, opening_fee_params: OpeningFeeParams,
 	) -> Result<(), APIError> {
-		let outer_state_lock = self.per_peer_state.read().unwrap();
-		match outer_state_lock.get(&counterparty_node_id) {
-			Some(inner_state_lock) => {
-				let mut peer_state = inner_state_lock.lock().unwrap();
-				if let Some(jit_channel) =
-					peer_state.inbound_channels_by_id.get_mut(&jit_channel_id)
-				{
-					match jit_channel.opening_fee_params_selected() {
-						Ok(()) => (),
-						Err(e) => {
-							peer_state.remove_inbound_channel(jit_channel_id);
-							return Err(APIError::APIMisuseError { err: e.err });
-						}
-					};
-
-					let request_id = crate::utils::generate_request_id(&self.entropy_source);
-					let payment_size_msat = jit_channel.config.payment_size_msat;
-					peer_state.insert_request(request_id.clone(), jit_channel_id);
-
-					self.pending_messages.enqueue(
-						&counterparty_node_id,
-						LSPS2Message::Request(
-							request_id,
-							LSPS2Request::Buy(BuyRequest { opening_fee_params, payment_size_msat }),
-						)
-						.into(),
-					);
-				} else {
-					return Err(APIError::APIMisuseError {
-						err: format!("Channel with id {} not found", jit_channel_id),
-					});
-				}
-			}
-			None => {
-				return Err(APIError::APIMisuseError {
-					err: format!("No existing state with counterparty {}", counterparty_node_id),
-				})
-			}
+		let mut outer_state_lock = self.per_peer_state.write().unwrap();
+		let inner_state_lock =
+			outer_state_lock.entry(counterparty_node_id).or_insert(Mutex::new(PeerState::new()));
+		let mut peer_state_lock = inner_state_lock.lock().unwrap();
+
+		let jit_channel = InboundJITChannel::new(user_channel_id, payment_size_msat);
+		if peer_state_lock.inbound_channels_by_id.insert(user_channel_id, jit_channel).is_some() {
+			return Err(APIError::APIMisuseError {
+				err: format!(
+					"Failed due to duplicate user_channel_id. Please ensure its uniqueness!"
+				),
+			});
 		}
 
-		Ok(())
-	}
+		let request_id = crate::utils::generate_request_id(&self.entropy_source);
+		peer_state_lock.pending_buy_requests.insert(request_id.clone(), user_channel_id);
+
+		self.pending_messages.enqueue(
+			&counterparty_node_id,
+			LSPS2Message::Request(
+				request_id,
+				LSPS2Request::Buy(BuyRequest { opening_fee_params, payment_size_msat }),
+			)
+			.into(),
+		);
 
-	fn generate_jit_channel_id(&self) -> u128 {
-		let bytes = self.entropy_source.get_secure_random_bytes();
-		let mut id_bytes: [u8; 16] = [0; 16];
-		id_bytes.copy_from_slice(&bytes[0..16]);
-		u128::from_be_bytes(id_bytes)
+		Ok(())
 	}
 
 	fn handle_get_info_response(
@@ -293,39 +237,22 @@ where
 			Some(inner_state_lock) => {
 				let mut peer_state = inner_state_lock.lock().unwrap();
 
-				let jit_channel_id =
-					peer_state.request_to_cid.remove(&request_id).ok_or(LightningError {
+				if !peer_state.pending_get_info_requests.remove(&request_id) {
+					return Err(LightningError {
 						err: format!(
 							"Received get_info response for an unknown request: {:?}",
 							request_id
 						),
 						action: ErrorAction::IgnoreAndLog(Level::Info),
-					})?;
-
-				let jit_channel = peer_state
-					.inbound_channels_by_id
-					.get_mut(&jit_channel_id)
-					.ok_or(LightningError {
-						err: format!(
-							"Received get_info response for an unknown channel: {:?}",
-							jit_channel_id
-						),
-						action: ErrorAction::IgnoreAndLog(Level::Info),
-					})?;
-
-				if let Err(e) = jit_channel.info_received() {
-					peer_state.remove_inbound_channel(jit_channel_id);
-					return Err(e);
+					});
 				}
 
 				self.pending_events.enqueue(Event::LSPS2Client(
-					LSPS2ClientEvent::GetInfoResponse {
+					LSPS2ClientEvent::OpeningParametersReady {
 						counterparty_node_id: *counterparty_node_id,
 						opening_fee_params_menu: result.opening_fee_params_menu,
 						min_payment_size_msat: result.min_payment_size_msat,
 						max_payment_size_msat: result.max_payment_size_msat,
-						jit_channel_id,
-						user_channel_id: jit_channel.config.user_id,
 					},
 				));
 			}
@@ -351,24 +278,16 @@ where
 			Some(inner_state_lock) => {
 				let mut peer_state = inner_state_lock.lock().unwrap();
 
-				let jit_channel_id =
-					peer_state.request_to_cid.remove(&request_id).ok_or(LightningError {
+				if !peer_state.pending_get_info_requests.remove(&request_id) {
+					return Err(LightningError {
 						err: format!(
 							"Received get_info error for an unknown request: {:?}",
 							request_id
 						),
 						action: ErrorAction::IgnoreAndLog(Level::Info),
-					})?;
+					});
+				}
 
-				peer_state.inbound_channels_by_id.remove(&jit_channel_id).ok_or(
-					LightningError {
-						err: format!(
-							"Received get_info error for an unknown channel: {:?}",
-							jit_channel_id
-						),
-						action: ErrorAction::IgnoreAndLog(Level::Info),
-					},
-				)?;
 				Ok(())
 			}
 			None => {
@@ -385,8 +304,8 @@ where
 			Some(inner_state_lock) => {
 				let mut peer_state = inner_state_lock.lock().unwrap();
 
-				let jit_channel_id =
-					peer_state.request_to_cid.remove(&request_id).ok_or(LightningError {
+				let user_channel_id =
+					peer_state.pending_buy_requests.remove(&request_id).ok_or(LightningError {
 						err: format!(
 							"Received buy response for an unknown request: {:?}",
 							request_id
@@ -396,32 +315,43 @@ where
 
 				let jit_channel = peer_state
 					.inbound_channels_by_id
-					.get_mut(&jit_channel_id)
+					.get_mut(&user_channel_id)
 					.ok_or(LightningError {
 						err: format!(
 							"Received buy response for an unknown channel: {:?}",
-							jit_channel_id
+							user_channel_id
 						),
 						action: ErrorAction::IgnoreAndLog(Level::Info),
 					})?;
 
+				// Reject the buy response if we disallow client_trusts_lsp and the LSP requires
+				// it.
+				if !self.config.client_trusts_lsp && result.client_trusts_lsp {
+					peer_state.inbound_channels_by_id.remove(&user_channel_id);
+					return Err(LightningError {
+						err: format!(
+							"Aborting JIT channel flow as the LSP requires 'client_trusts_lsp' mode, which we disallow"
+						),
+						action: ErrorAction::IgnoreAndLog(Level::Info),
+					});
+				}
+
 				if let Err(e) = jit_channel.invoice_params_received(
 					result.client_trusts_lsp,
 					result.intercept_scid.clone(),
 				) {
-					peer_state.remove_inbound_channel(jit_channel_id);
+					peer_state.inbound_channels_by_id.remove(&user_channel_id);
 					return Err(e);
 				}
 
 				if let Ok(intercept_scid) = result.intercept_scid.to_scid() {
 					self.pending_events.enqueue(Event::LSPS2Client(
-						LSPS2ClientEvent::InvoiceGenerationReady {
+						LSPS2ClientEvent::InvoiceParametersReady {
 							counterparty_node_id: *counterparty_node_id,
 							intercept_scid,
 							cltv_expiry_delta: result.lsp_cltv_expiry_delta,
-							payment_size_msat: jit_channel.config.payment_size_msat,
-							client_trusts_lsp: result.client_trusts_lsp,
-							user_channel_id: jit_channel.config.user_id,
+							payment_size_msat: jit_channel.payment_size_msat,
+							user_channel_id: jit_channel.user_channel_id,
 						},
 					));
 				} else {
@@ -455,22 +385,21 @@ where
 			Some(inner_state_lock) => {
 				let mut peer_state = inner_state_lock.lock().unwrap();
 
-				let jit_channel_id =
-					peer_state.request_to_cid.remove(&request_id).ok_or(LightningError {
+				let user_channel_id =
+					peer_state.pending_buy_requests.remove(&request_id).ok_or(LightningError {
 						err: format!("Received buy error for an unknown request: {:?}", request_id),
 						action: ErrorAction::IgnoreAndLog(Level::Info),
 					})?;
 
-				let _jit_channel = peer_state
-					.inbound_channels_by_id
-					.remove(&jit_channel_id)
-					.ok_or(LightningError {
+				peer_state.inbound_channels_by_id.remove(&user_channel_id).ok_or(
+					LightningError {
 						err: format!(
 							"Received buy error for an unknown channel: {:?}",
-							jit_channel_id
+							user_channel_id
 						),
 						action: ErrorAction::IgnoreAndLog(Level::Info),
-					})?;
+					},
+				)?;
 				Ok(())
 			}
 			None => {
diff --git a/src/lsps2/event.rs b/src/lsps2/event.rs
index 101d80e..1d1922b 100644
--- a/src/lsps2/event.rs
+++ b/src/lsps2/event.rs
@@ -20,17 +20,11 @@ use bitcoin::secp256k1::PublicKey;
 pub enum LSPS2ClientEvent {
 	/// Information from the LSP about their current fee rates and channel parameters.
 	///
-	/// You must call [`LSPS2ClientHandler::opening_fee_params_selected`] with the fee parameter
+	/// You must call [`LSPS2ClientHandler::select_opening_params`] with the fee parameter
 	/// you want to use if you wish to proceed opening a channel.
 	///
-	/// [`LSPS2ClientHandler::opening_fee_params_selected`]: crate::lsps2::client::LSPS2ClientHandler::opening_fee_params_selected
-	GetInfoResponse {
-		/// This is a randomly generated identifier used to track the JIT channel state.
-		/// It is not related in anyway to the eventual lightning channel id.
-		/// It needs to be passed to [`LSPS2ClientHandler::opening_fee_params_selected`].
-		///
-		/// [`LSPS2ClientHandler::opening_fee_params_selected`]: crate::lsps2::client::LSPS2ClientHandler::opening_fee_params_selected
-		jit_channel_id: u128,
+	/// [`LSPS2ClientHandler::select_opening_params`]: crate::lsps2::client::LSPS2ClientHandler::select_opening_params
+	OpeningParametersReady {
 		/// The node id of the LSP that provided this response.
 		counterparty_node_id: PublicKey,
 		/// The menu of fee parameters the LSP is offering at this time.
@@ -40,16 +34,20 @@ pub enum LSPS2ClientEvent {
 		min_payment_size_msat: u64,
 		/// The max payment size allowed when opening the channel.
 		max_payment_size_msat: u64,
-		/// The user_channel_id value passed in to [`LSPS2ClientHandler::create_invoice`].
-		///
-		/// [`LSPS2ClientHandler::create_invoice`]: crate::lsps2::client::LSPS2ClientHandler::create_invoice
-		user_channel_id: u128,
 	},
-	/// Use the provided fields to generate an invoice and give to payer.
+	/// Provides the necessary information to generate a payable invoice that then may be given to
+	/// the payer.
 	///
-	/// When the invoice is paid the LSP will open a channel to you
-	/// with the previously agreed upon parameters.
-	InvoiceGenerationReady {
+	/// When the invoice is paid, the LSP will open a channel with the previously agreed upon
+	/// parameters to you.
+	InvoiceParametersReady {
+		/// A user-specified identifier used to track the channel open.
+		///
+		/// This is the same value as previously passed to
+		/// [`LSPS2ClientHandler::select_opening_params`].
+		///
+		/// [`LSPS2ClientHandler::select_opening_params`]: crate::lsps2::client::LSPS2ClientHandler::select_opening_params
+		user_channel_id: u128,
 		/// The node id of the LSP.
 		counterparty_node_id: PublicKey,
 		/// The intercept short channel id to use in the route hint.
@@ -58,12 +56,6 @@ pub enum LSPS2ClientEvent {
 		cltv_expiry_delta: u32,
 		/// The initial payment size you specified.
 		payment_size_msat: Option<u64>,
-		/// The trust model the LSP expects.
-		client_trusts_lsp: bool,
-		/// The `user_channel_id` value passed in to [`LSPS2ClientHandler::create_invoice`].
-		///
-		/// [`LSPS2ClientHandler::create_invoice`]: crate::lsps2::client::LSPS2ClientHandler::create_invoice
-		user_channel_id: u128,
 	},
 }