diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index d7f48c17f8726793061b73b4ad25b2e4630df78c..bed09f135de322c2b6a5be51b5acdc67bc5f63bd 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -3568,6 +3568,7 @@ dependencies = [
  "pallet-society",
  "pallet-staking",
  "pallet-staking-reward-curve",
+ "pallet-staking-runtime-api",
  "pallet-state-trie-migration",
  "pallet-sudo",
  "pallet-timestamp",
@@ -6129,6 +6130,7 @@ dependencies = [
 name = "pallet-nomination-pools-runtime-api"
 version = "1.0.0-dev"
 dependencies = [
+ "pallet-nomination-pools",
  "parity-scale-codec",
  "sp-api",
  "sp-std",
@@ -6486,6 +6488,14 @@ dependencies = [
  "sp-arithmetic",
 ]
 
+[[package]]
+name = "pallet-staking-runtime-api"
+version = "4.0.0-dev"
+dependencies = [
+ "parity-scale-codec",
+ "sp-api",
+]
+
 [[package]]
 name = "pallet-state-trie-migration"
 version = "4.0.0-dev"
diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml
index aaa1c2a2111832e3d127370264837709da19d8af..a86ec3146832b472ebd59c1b7e840e5064d50ad6 100644
--- a/substrate/Cargo.toml
+++ b/substrate/Cargo.toml
@@ -141,6 +141,7 @@ members = [
 	"frame/staking",
 	"frame/staking/reward-curve",
 	"frame/staking/reward-fn",
+	"frame/staking/runtime-api",
 	"frame/state-trie-migration",
 	"frame/sudo",
 	"frame/root-offences",
diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml
index 1d2e6f057d51741a2d9efe189b806ca89c52a64c..e27e4f7f8a5451be0986b36fb1c4146ee9bea9b6 100644
--- a/substrate/bin/node/runtime/Cargo.toml
+++ b/substrate/bin/node/runtime/Cargo.toml
@@ -97,6 +97,7 @@ pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = ".
 pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true }
 pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" }
 pallet-staking-reward-curve = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/reward-curve" }
+pallet-staking-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/runtime-api" }
 pallet-state-trie-migration = { version = "4.0.0-dev", default-features = false, path = "../../../frame/state-trie-migration" }
 pallet-scheduler = { version = "4.0.0-dev", default-features = false, path = "../../../frame/scheduler" }
 pallet-society = { version = "4.0.0-dev", default-features = false, path = "../../../frame/society" }
@@ -175,6 +176,7 @@ std = [
 	"sp-runtime/std",
 	"sp-staking/std",
 	"pallet-staking/std",
+	"pallet-staking-runtime-api/std",
 	"pallet-state-trie-migration/std",
 	"sp-session/std",
 	"pallet-sudo/std",
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 2c7969ebcd6b9c014a9a561ac3920a1f2664750d..0b887ff7d7a9f421e336ab5a8285cb081943add5 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -1986,8 +1986,22 @@ impl_runtime_apis! {
 	}
 
 	impl pallet_nomination_pools_runtime_api::NominationPoolsApi<Block, AccountId, Balance> for Runtime {
-		fn pending_rewards(member_account: AccountId) -> Balance {
-			NominationPools::pending_rewards(member_account).unwrap_or_default()
+		fn pending_rewards(who: AccountId) -> Balance {
+			NominationPools::api_pending_rewards(who).unwrap_or_default()
+		}
+
+		fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance {
+			NominationPools::api_points_to_balance(pool_id, points)
+		}
+
+		fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance {
+			NominationPools::api_balance_to_points(pool_id, new_funds)
+		}
+	}
+
+	impl pallet_staking_runtime_api::StakingApi<Block, Balance> for Runtime {
+		fn nominations_quota(balance: Balance) -> u32 {
+			Staking::api_nominations_quota(balance)
 		}
 	}
 
diff --git a/substrate/frame/nomination-pools/runtime-api/Cargo.toml b/substrate/frame/nomination-pools/runtime-api/Cargo.toml
index d1e4fbb30df5216f2a5ba29488b9476fa8dc40ac..5e290232a115ed657830c2592a19d49b3216881a 100644
--- a/substrate/frame/nomination-pools/runtime-api/Cargo.toml
+++ b/substrate/frame/nomination-pools/runtime-api/Cargo.toml
@@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] }
 sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" }
 sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" }
+pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../" }
 
 [features]
 default = ["std"]
@@ -23,4 +24,5 @@ std = [
 	"codec/std",
 	"sp-api/std",
 	"sp-std/std",
+	"pallet-nomination-pools/std",
 ]
diff --git a/substrate/frame/nomination-pools/runtime-api/src/lib.rs b/substrate/frame/nomination-pools/runtime-api/src/lib.rs
index aa3ca57ca5b8bf1ac7b5ed8a0214aa9014553d52..94573bfdb2e339219200e29214a0da9cabe17202 100644
--- a/substrate/frame/nomination-pools/runtime-api/src/lib.rs
+++ b/substrate/frame/nomination-pools/runtime-api/src/lib.rs
@@ -21,13 +21,22 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use codec::Codec;
+use pallet_nomination_pools::PoolId;
 
 sp_api::decl_runtime_apis! {
 	/// Runtime api for accessing information about nomination pools.
 	pub trait NominationPoolsApi<AccountId, Balance>
-		where AccountId: Codec, Balance: Codec
+		where
+			AccountId: Codec,
+			Balance: Codec,
 	{
 		/// Returns the pending rewards for the member that the AccountId was given for.
-		fn pending_rewards(member: AccountId) -> Balance;
+		fn pending_rewards(who: AccountId) -> Balance;
+
+		/// Returns the equivalent balance of `points` for a given pool.
+		fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance;
+
+		/// Returns the equivalent points of `new_funds` for a given pool.
+		fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance;
 	}
 }
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 3cb8abedda2fb4caeb382fd84e1c2a6f4dff9169..9c52cf71c6b30b3856dd992258e80d2a4b00c49f 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -2142,24 +2142,6 @@ pub mod pallet {
 }
 
 impl<T: Config> Pallet<T> {
-	/// Returns the pending rewards for the specified `member_account`.
-	///
-	/// In the case of error, `None` is returned.
-	pub fn pending_rewards(member_account: T::AccountId) -> Option<BalanceOf<T>> {
-		if let Some(pool_member) = PoolMembers::<T>::get(member_account) {
-			if let Some((reward_pool, bonded_pool)) = RewardPools::<T>::get(pool_member.pool_id)
-				.zip(BondedPools::<T>::get(pool_member.pool_id))
-			{
-				let current_reward_counter = reward_pool
-					.current_reward_counter(pool_member.pool_id, bonded_pool.points)
-					.ok()?;
-				return pool_member.pending_rewards(current_reward_counter).ok()
-			}
-		}
-
-		None
-	}
-
 	/// The amount of bond that MUST REMAIN IN BONDED in ALL POOLS.
 	///
 	/// It is the responsibility of the depositor to put these funds into the pool initially. Upon
@@ -2579,6 +2561,50 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
+impl<T: Config> Pallet<T> {
+	/// Returns the pending rewards for the specified `who` account.
+	///
+	/// In the case of error, `None` is returned. Used by runtime API.
+	pub fn api_pending_rewards(who: T::AccountId) -> Option<BalanceOf<T>> {
+		if let Some(pool_member) = PoolMembers::<T>::get(who) {
+			if let Some((reward_pool, bonded_pool)) = RewardPools::<T>::get(pool_member.pool_id)
+				.zip(BondedPools::<T>::get(pool_member.pool_id))
+			{
+				let current_reward_counter = reward_pool
+					.current_reward_counter(pool_member.pool_id, bonded_pool.points)
+					.ok()?;
+				return pool_member.pending_rewards(current_reward_counter).ok()
+			}
+		}
+
+		None
+	}
+
+	/// Returns the points to balance conversion for a specified pool.
+	///
+	/// If the pool ID does not exist, it returns 0 ratio points to balance. Used by runtime API.
+	pub fn api_points_to_balance(pool_id: PoolId, points: BalanceOf<T>) -> BalanceOf<T> {
+		if let Some(pool) = BondedPool::<T>::get(pool_id) {
+			pool.points_to_balance(points)
+		} else {
+			Zero::zero()
+		}
+	}
+
+	/// Returns the equivalent `new_funds` balance to point conversion for a specified pool.
+	///
+	/// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API.
+	pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf<T>) -> BalanceOf<T> {
+		if let Some(pool) = BondedPool::<T>::get(pool_id) {
+			let bonded_balance =
+				T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero());
+			Pallet::<T>::balance_to_point(bonded_balance, pool.points, new_funds)
+		} else {
+			Zero::zero()
+		}
+	}
+}
+
 impl<T: Config> OnStakerSlash<T::AccountId, BalanceOf<T>> for Pallet<T> {
 	fn on_slash(
 		pool_account: &T::AccountId,
diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs
index 7d5d418bbf2c86046ed2d17641441bfa344c3d92..be52996a587f7ab321384e5d75d314b9ac574bac 100644
--- a/substrate/frame/nomination-pools/src/tests.rs
+++ b/substrate/frame/nomination-pools/src/tests.rs
@@ -195,6 +195,46 @@ mod bonded_pool {
 		})
 	}
 
+	#[test]
+	fn api_points_to_balance_works() {
+		ExtBuilder::default().build_and_execute(|| {
+			assert!(BondedPool::<Runtime>::get(1).is_some());
+			assert_eq!(Pallet::<Runtime>::api_points_to_balance(1, 10), 10);
+
+			// slash half of the pool's balance. expected result of `fn api_points_to_balance`
+			// to be 1/2 of the pool's balance.
+			StakingMock::set_bonded_balance(
+				default_bonded_account(),
+				Pools::depositor_min_bond() / 2,
+			);
+			assert_eq!(Pallet::<Runtime>::api_points_to_balance(1, 10), 5);
+
+			// if pool does not exist, points to balance ratio is 0.
+			assert_eq!(BondedPool::<Runtime>::get(2), None);
+			assert_eq!(Pallet::<Runtime>::api_points_to_balance(2, 10), 0);
+		})
+	}
+
+	#[test]
+	fn api_balance_to_points_works() {
+		ExtBuilder::default().build_and_execute(|| {
+			assert_eq!(Pallet::<Runtime>::api_balance_to_points(1, 0), 0);
+			assert_eq!(Pallet::<Runtime>::api_balance_to_points(1, 10), 10);
+
+			// slash half of the pool's balance. expect result of `fn api_balance_to_points`
+			// to be 2 * of the balance to add to the pool.
+			StakingMock::set_bonded_balance(
+				default_bonded_account(),
+				Pools::depositor_min_bond() / 2,
+			);
+			assert_eq!(Pallet::<Runtime>::api_balance_to_points(1, 10), 20);
+
+			// if pool does not exist, balance to points ratio is 0.
+			assert_eq!(BondedPool::<Runtime>::get(2), None);
+			assert_eq!(Pallet::<Runtime>::api_points_to_balance(2, 10), 0);
+		})
+	}
+
 	#[test]
 	fn ok_to_join_with_works() {
 		ExtBuilder::default().build_and_execute(|| {
@@ -1305,51 +1345,51 @@ mod claim_payout {
 		ExtBuilder::default().build_and_execute(|| {
 			let ed = Balances::minimum_balance();
 
-			assert_eq!(Pools::pending_rewards(10), Some(0));
+			assert_eq!(Pools::api_pending_rewards(10), Some(0));
 			Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap();
-			assert_eq!(Pools::pending_rewards(10), Some(30));
-			assert_eq!(Pools::pending_rewards(20), None);
+			assert_eq!(Pools::api_pending_rewards(10), Some(30));
+			assert_eq!(Pools::api_pending_rewards(20), None);
 
 			Balances::make_free_balance_be(&20, ed + 10);
 			assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
 
-			assert_eq!(Pools::pending_rewards(10), Some(30));
-			assert_eq!(Pools::pending_rewards(20), Some(0));
+			assert_eq!(Pools::api_pending_rewards(10), Some(30));
+			assert_eq!(Pools::api_pending_rewards(20), Some(0));
 
 			Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap();
 
-			assert_eq!(Pools::pending_rewards(10), Some(30 + 50));
-			assert_eq!(Pools::pending_rewards(20), Some(50));
-			assert_eq!(Pools::pending_rewards(30), None);
+			assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50));
+			assert_eq!(Pools::api_pending_rewards(20), Some(50));
+			assert_eq!(Pools::api_pending_rewards(30), None);
 
 			Balances::make_free_balance_be(&30, ed + 10);
 			assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1));
 
-			assert_eq!(Pools::pending_rewards(10), Some(30 + 50));
-			assert_eq!(Pools::pending_rewards(20), Some(50));
-			assert_eq!(Pools::pending_rewards(30), Some(0));
+			assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50));
+			assert_eq!(Pools::api_pending_rewards(20), Some(50));
+			assert_eq!(Pools::api_pending_rewards(30), Some(0));
 
 			Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap();
 
-			assert_eq!(Pools::pending_rewards(10), Some(30 + 50 + 20));
-			assert_eq!(Pools::pending_rewards(20), Some(50 + 20));
-			assert_eq!(Pools::pending_rewards(30), Some(20));
+			assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50 + 20));
+			assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20));
+			assert_eq!(Pools::api_pending_rewards(30), Some(20));
 
 			// 10 should claim 10, 20 should claim nothing.
 			assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10)));
-			assert_eq!(Pools::pending_rewards(10), Some(0));
-			assert_eq!(Pools::pending_rewards(20), Some(50 + 20));
-			assert_eq!(Pools::pending_rewards(30), Some(20));
+			assert_eq!(Pools::api_pending_rewards(10), Some(0));
+			assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20));
+			assert_eq!(Pools::api_pending_rewards(30), Some(20));
 
 			assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20)));
-			assert_eq!(Pools::pending_rewards(10), Some(0));
-			assert_eq!(Pools::pending_rewards(20), Some(0));
-			assert_eq!(Pools::pending_rewards(30), Some(20));
+			assert_eq!(Pools::api_pending_rewards(10), Some(0));
+			assert_eq!(Pools::api_pending_rewards(20), Some(0));
+			assert_eq!(Pools::api_pending_rewards(30), Some(20));
 
 			assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30)));
-			assert_eq!(Pools::pending_rewards(10), Some(0));
-			assert_eq!(Pools::pending_rewards(20), Some(0));
-			assert_eq!(Pools::pending_rewards(30), Some(0));
+			assert_eq!(Pools::api_pending_rewards(10), Some(0));
+			assert_eq!(Pools::api_pending_rewards(20), Some(0));
+			assert_eq!(Pools::api_pending_rewards(30), Some(0));
 		});
 	}
 
diff --git a/substrate/frame/staking/runtime-api/Cargo.toml b/substrate/frame/staking/runtime-api/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..9923b881c38d891eb71d010c3405da17ab2ea450
--- /dev/null
+++ b/substrate/frame/staking/runtime-api/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "pallet-staking-runtime-api"
+version = "4.0.0-dev"
+authors = ["Parity Technologies <admin@parity.io>"]
+edition = "2021"
+license = "Apache-2.0"
+homepage = "https://substrate.io"
+repository = "https://github.com/paritytech/substrate/"
+description = "RPC runtime API for transaction payment FRAME pallet"
+readme = "README.md"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
+sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" }
+
+[features]
+default = ["std"]
+std = [
+	"codec/std",
+	"sp-api/std",
+]
diff --git a/substrate/frame/staking/runtime-api/README.md b/substrate/frame/staking/runtime-api/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a999e519f8cbfae23ba0742d6849a533022fbadb
--- /dev/null
+++ b/substrate/frame/staking/runtime-api/README.md
@@ -0,0 +1,3 @@
+Runtime API definition for the staking pallet.
+
+License: Apache-2.0
diff --git a/substrate/frame/staking/runtime-api/src/lib.rs b/substrate/frame/staking/runtime-api/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..378599c665506007ddae5ea227829d4af2483103
--- /dev/null
+++ b/substrate/frame/staking/runtime-api/src/lib.rs
@@ -0,0 +1,32 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2023 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Runtime API definition for the staking pallet.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use codec::Codec;
+
+sp_api::decl_runtime_apis! {
+	pub trait StakingApi<Balance>
+		where
+			Balance: Codec,
+	{
+		/// Returns the nominations quota for a nominator with a given balance.
+		fn nominations_quota(balance: Balance) -> u32;
+	}
+}
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 6a35e2b8615659e31981adc4f99d3f4378126bd1..fc0bf082c7cafee11fbdd60285379882034deac2 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -972,6 +972,20 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
+impl<T: Config> Pallet<T> {
+	/// Returns the current nominations quota for nominators.
+	///
+	/// Used by the runtime API.
+	/// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it
+	/// is redundant. However, with the upcoming changes in
+	/// <https://github.com/paritytech/substrate/pull/12970>, the nominations quota will change
+	/// depending on the nominators balance. We're introducing this runtime API now to prepare the
+	/// community to use it before rolling out PR#12970.
+	pub fn api_nominations_quota(_balance: BalanceOf<T>) -> u32 {
+		T::MaxNominations::get()
+	}
+}
+
 impl<T: Config> ElectionDataProvider for Pallet<T> {
 	type AccountId = T::AccountId;
 	type BlockNumber = BlockNumberFor<T>;