diff --git a/go.mod b/go.mod
index 0b30354..391c1a5 100644
--- a/go.mod
+++ b/go.mod
@@ -12,6 +12,8 @@ require (
 	gopkg.in/leonelquinteros/gotext.v1 v1.3.1
 )
 
+require github.com/grassrootseconomics/ussd-data-service v0.0.0-20241003123429-4904b4438a3a // indirect
+
 require (
 	github.com/jackc/pgpassfile v1.0.0 // indirect
 	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
diff --git a/go.sum b/go.sum
index d566e2c..0ba38c1 100644
--- a/go.sum
+++ b/go.sum
@@ -18,6 +18,8 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1
 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU=
 github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo=
+github.com/grassrootseconomics/ussd-data-service v0.0.0-20241003123429-4904b4438a3a h1:q/YH7nE2j8epNmFnTu0tU1vwtCxtQ6nH+d7hRVV5krU=
+github.com/grassrootseconomics/ussd-data-service v0.0.0-20241003123429-4904b4438a3a/go.mod h1:hdKaKwqiW6/kphK4j/BhmuRlZDLo1+DYo3gYw5O0siw=
 github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo=
 github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y=
 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go
index dae4236..dd3efdb 100644
--- a/internal/handlers/ussd/menuhandler.go
+++ b/internal/handlers/ussd/menuhandler.go
@@ -66,6 +66,7 @@ type Handlers struct {
 	userdataStore  utils.DataStore
 	flagManager    *asm.FlagParser
 	accountService server.AccountServiceInterface
+	prefixDb       storage.PrefixDb
 }
 
 func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService server.AccountServiceInterface) (*Handlers, error) {
@@ -75,10 +76,14 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService s
 	userDb := &utils.UserDataStore{
 		Db: userdataStore,
 	}
+	// Instantiate the SubPrefixDb with "vouchers" prefix
+	prefixDb := storage.NewSubPrefixDb(userdataStore, []byte("vouchers"))
+
 	h := &Handlers{
 		userdataStore:  userDb,
 		flagManager:    appFlags,
 		accountService: accountService,
+		prefixDb:       prefixDb,
 	}
 	return h, nil
 }
@@ -1051,13 +1056,13 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by
 		if db.IsNotFound(err) {
 			publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
 			if err != nil {
-				return res, nil
+				return res, err
 			}
 
 			// Fetch vouchers from the API using the public key
 			vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey))
 			if err != nil {
-				return res, nil
+				return res, err
 			}
 
 			// Return if there is no voucher
@@ -1114,54 +1119,33 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte)
 		return res, nil
 	}
 
-	// process voucher data
-	voucherSymbolList, voucherBalanceList := ProcessVouchers(vouchersResp.Result.Holdings)
+	data := utils.ProcessVouchers(vouchersResp.Result.Holdings)
 
-	prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers"))
-	err = prefixdb.Put(ctx, []byte("sym"), []byte(voucherSymbolList))
-	if err != nil {
-		return res, nil
+	// Store all voucher data
+	dataMap := map[string]string{
+		"sym":  data.Symbols,
+		"bal":  data.Balances,
+		"deci": data.Decimals,
+		"addr": data.Addresses,
 	}
 
-	err = prefixdb.Put(ctx, []byte("bal"), []byte(voucherBalanceList))
-	if err != nil {
-		return res, nil
+	for key, value := range dataMap {
+		if err := h.prefixDb.Put(ctx, []byte(key), []byte(value)); err != nil {
+			return res, nil
+		}
 	}
 
 	return res, nil
 }
 
-// ProcessVouchers formats the holdings into symbol and balance lists.
-func ProcessVouchers(holdings []struct {
-	ContractAddress string `json:"contractAddress"`
-	TokenSymbol     string `json:"tokenSymbol"`
-	TokenDecimals   string `json:"tokenDecimals"`
-	Balance         string `json:"balance"`
-}) (string, string) {
-	var numberedSymbols, numberedBalances []string
-
-	for i, voucher := range holdings {
-		numberedSymbols = append(numberedSymbols, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol))
-		numberedBalances = append(numberedBalances, fmt.Sprintf("%d:%s", i+1, voucher.Balance))
-	}
-
-	voucherSymbolList := strings.Join(numberedSymbols, "\n")
-	voucherBalanceList := strings.Join(numberedBalances, "\n")
-
-	return voucherSymbolList, voucherBalanceList
-}
-
 // GetVoucherList fetches the list of vouchers and formats them
 func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 	var res resource.Result
 
 	// Read vouchers from the store
-	store := h.userdataStore
-	prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers"))
-
-	voucherData, err := prefixdb.Get(ctx, []byte("sym"))
+	voucherData, err := h.prefixDb.Get(ctx, []byte("sym"))
 	if err != nil {
-		return res, nil
+		return res, err
 	}
 
 	res.Content = string(voucherData)
@@ -1172,8 +1156,6 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte)
 // ViewVoucher retrieves the token holding and balance from the subprefixDB
 func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 	var res resource.Result
-	store := h.userdataStore
-
 	sessionId, ok := ctx.Value("SessionId").(string)
 	if !ok {
 		return res, fmt.Errorf("missing session")
@@ -1182,126 +1164,51 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r
 	flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher")
 
 	inputStr := string(input)
-
 	if inputStr == "0" || inputStr == "99" {
 		res.FlagReset = append(res.FlagReset, flag_incorrect_voucher)
 		return res, nil
 	}
 
-	prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers"))
-
-	// Retrieve the voucher symbol list
-	voucherSymbolList, err := prefixdb.Get(ctx, []byte("sym"))
+	metadata, err := utils.GetVoucherData(ctx, h.prefixDb, inputStr)
 	if err != nil {
-		return res, fmt.Errorf("failed to retrieve voucher symbol list: %v", err)
+		return res, fmt.Errorf("failed to retrieve voucher data: %v", err)
 	}
 
-	// Retrieve the voucher balance list
-	voucherBalanceList, err := prefixdb.Get(ctx, []byte("bal"))
-	if err != nil {
-		return res, fmt.Errorf("failed to retrieve voucher balance list: %v", err)
-	}
-
-	// match the voucher symbol and balance with the input
-	matchedSymbol, matchedBalance := MatchVoucher(inputStr, string(voucherSymbolList), string(voucherBalanceList))
-
-	// If a match is found, write the temporary sym and balance
-	if matchedSymbol != "" && matchedBalance != "" {
-		err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(matchedSymbol))
-		if err != nil {
-			return res, err
-		}
-		err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte(matchedBalance))
-		if err != nil {
-			return res, err
-		}
-
-		res.FlagReset = append(res.FlagReset, flag_incorrect_voucher)
-		res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance)
-	} else {
+	if metadata == nil {
 		res.FlagSet = append(res.FlagSet, flag_incorrect_voucher)
+		return res, nil
 	}
 
+	if err := utils.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil {
+		return res, err
+	}
+
+	res.FlagReset = append(res.FlagReset, flag_incorrect_voucher)
+	res.Content = fmt.Sprintf("%s\n%s", metadata.TokenSymbol, metadata.Balance)
+
 	return res, nil
 }
 
-// MatchVoucher finds the matching voucher symbol and balance based on the input.
-func MatchVoucher(inputStr string, voucherSymbols, voucherBalances string) (string, string) {
-	// Split the lists into slices for processing
-	symbols := strings.Split(voucherSymbols, "\n")
-	balances := strings.Split(voucherBalances, "\n")
-
-	var matchedSymbol, matchedBalance string
-
-	for i, symbol := range symbols {
-		symbolParts := strings.SplitN(symbol, ":", 2)
-		if len(symbolParts) != 2 {
-			continue
-		}
-		voucherNum := symbolParts[0]
-		voucherSymbol := symbolParts[1]
-
-		// Check if input matches either the number or the symbol
-		if inputStr == voucherNum || strings.EqualFold(inputStr, voucherSymbol) {
-			matchedSymbol = voucherSymbol
-			// Ensure there's a corresponding balance
-			if i < len(balances) {
-				matchedBalance = strings.SplitN(balances[i], ":", 2)[1]
-			}
-			break
-		}
-	}
-
-	return matchedSymbol, matchedBalance
-}
-
-// SetVoucher retrieves the temporary sym and balance,
-// sets them as the active data and
-// clears the temporary data
+// SetVoucher retrieves the temp voucher data and sets it as the active data
 func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 	var res resource.Result
-	var err error
-	store := h.userdataStore
 
 	sessionId, ok := ctx.Value("SessionId").(string)
 	if !ok {
 		return res, fmt.Errorf("missing session")
 	}
 
-	// get the current temporary symbol
-	temporarySym, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM)
-	if err != nil {
-		return res, err
-	}
-	// get the current temporary balance
-	temporaryBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL)
+	// Get temporary data
+	tempData, err := utils.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId)
 	if err != nil {
 		return res, err
 	}
 
-	// set the active symbol
-	err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(temporarySym))
-	if err != nil {
-		return res, err
-	}
-	// set the active balance
-	err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(temporaryBal))
-	if err != nil {
+	// Set as active and clear temporary data
+	if err := utils.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil {
 		return res, err
 	}
 
-	// reset the temporary symbol
-	err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(""))
-	if err != nil {
-		return res, err
-	}
-	// reset the temporary balance
-	err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte(""))
-	if err != nil {
-		return res, err
-	}
-
-	res.Content = string(temporarySym)
-
+	res.Content = tempData.TokenSymbol
 	return res, nil
 }
diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go
index 0b70e80..a960cfc 100644
--- a/internal/handlers/ussd/menuhandler_test.go
+++ b/internal/handlers/ussd/menuhandler_test.go
@@ -25,6 +25,8 @@ import (
 	"github.com/grassrootseconomics/eth-custodial/pkg/api"
 	testdataloader "github.com/peteole/testdata-loader"
 	"github.com/stretchr/testify/require"
+
+	dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
 )
 
 var (
@@ -1489,8 +1491,8 @@ func TestValidateAmount(t *testing.T) {
 			},
 		},
 		{
-			name:    "Test with invalid amount format",
-			input:   []byte("0.02ms"),
+			name:      "Test with invalid amount format",
+			input:     []byte("0.02ms"),
 			activeBal: []byte("5"),
 			expectedResult: resource.Result{
 				FlagSet: []uint32{flag_invalid_amount},
@@ -1819,40 +1821,6 @@ func TestConfirmPin(t *testing.T) {
 	}
 }
 
-func TestSetVoucher(t *testing.T) {
-	mockDataStore := new(mocks.MockUserDataStore)
-
-	sessionId := "session123"
-	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
-
-	temporarySym := []byte("tempSym")
-	temporaryBal := []byte("tempBal")
-
-	// Set expectations for the mock data store
-	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return(temporarySym, nil)
-	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return(temporaryBal, nil)
-	mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, temporarySym).Return(nil)
-	mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, temporaryBal).Return(nil)
-	mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")).Return(nil)
-	mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")).Return(nil)
-
-	h := &Handlers{
-		userdataStore: mockDataStore,
-	}
-
-	// Call the method under test
-	res, err := h.SetVoucher(ctx, "someSym", []byte{})
-
-	// Assert that no errors occurred
-	assert.NoError(t, err)
-
-	// Assert that the result content is correct
-	assert.Equal(t, string(temporarySym), res.Content)
-
-	// Assert that expectations were met
-	mockDataStore.AssertExpectations(t)
-}
-
 func TestFetchCustodialBalances(t *testing.T) {
 	fm, err := NewFlagManager(flagsPath)
 	if err != nil {
@@ -1934,3 +1902,256 @@ func TestFetchCustodialBalances(t *testing.T) {
 		})
 	}
 }
+
+func TestSetDefaultVoucher(t *testing.T) {
+	fm, err := NewFlagManager(flagsPath)
+	if err != nil {
+		t.Logf(err.Error())
+	}
+	flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher")
+	if err != nil {
+		t.Logf(err.Error())
+	}
+	// Define session ID and mock data
+	sessionId := "session123"
+	publicKey := "0X13242618721"
+	notFoundErr := db.ErrNotFound{}
+	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
+
+	tests := []struct {
+		name           string
+		vouchersResp   *models.VoucherHoldingResponse
+		expectedResult resource.Result
+	}{
+		{
+			name: "Test set default voucher when no active voucher exists",
+			vouchersResp: &models.VoucherHoldingResponse{
+				Ok:          true,
+				Description: "Vouchers fetched successfully",
+				Result: models.VoucherResult{
+					Holdings: []dataserviceapi.TokenHoldings{
+						{
+							ContractAddress: "0x123",
+							TokenSymbol:     "TOKEN1",
+							TokenDecimals:   "18",
+							Balance:         "100",
+						},
+					},
+				},
+			},
+			expectedResult: resource.Result{},
+		},
+		{
+			name: "Test no vouchers available",
+			vouchersResp: &models.VoucherHoldingResponse{
+				Ok:          true,
+				Description: "No vouchers available",
+				Result: models.VoucherResult{
+					Holdings: []dataserviceapi.TokenHoldings{},
+				},
+			},
+			expectedResult: resource.Result{
+				FlagSet: []uint32{flag_no_active_voucher},
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mockDataStore := new(mocks.MockUserDataStore)
+			mockAccountService := new(mocks.MockAccountService)
+
+			h := &Handlers{
+				userdataStore:  mockDataStore,
+				accountService: mockAccountService,
+				flagManager:    fm.parser,
+			}
+
+			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(""), notFoundErr)
+			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil)
+
+			mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil)
+
+			if len(tt.vouchersResp.Result.Holdings) > 0 {
+				firstVoucher := tt.vouchersResp.Result.Holdings[0]
+				mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(firstVoucher.TokenSymbol)).Return(nil)
+				mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(firstVoucher.Balance)).Return(nil)
+			}
+
+			res, err := h.SetDefaultVoucher(ctx, "set_default_voucher", []byte("some-input"))
+
+			assert.NoError(t, err)
+
+			assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result")
+
+			mockDataStore.AssertExpectations(t)
+			mockAccountService.AssertExpectations(t)
+		})
+	}
+}
+
+func TestCheckVouchers(t *testing.T) {
+	mockDataStore := new(mocks.MockUserDataStore)
+	mockAccountService := new(mocks.MockAccountService)
+	mockSubPrefixDb := new(mocks.MockSubPrefixDb)
+
+	sessionId := "session123"
+	publicKey := "0X13242618721"
+
+	h := &Handlers{
+		userdataStore:  mockDataStore,
+		accountService: mockAccountService,
+		prefixDb:       mockSubPrefixDb,
+	}
+
+	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
+
+	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil)
+
+	mockVouchersResponse := &models.VoucherHoldingResponse{}
+	mockVouchersResponse.Result.Holdings = []dataserviceapi.TokenHoldings{
+		{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"},
+		{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"},
+	}
+
+	mockAccountService.On("FetchVouchers", string(publicKey)).Return(mockVouchersResponse, nil)
+
+	mockSubPrefixDb.On("Put", ctx, []byte("sym"), []byte("1:SRF\n2:MILO")).Return(nil)
+	mockSubPrefixDb.On("Put", ctx, []byte("bal"), []byte("1:100\n2:200")).Return(nil)
+	mockSubPrefixDb.On("Put", ctx, []byte("deci"), []byte("1:6\n2:4")).Return(nil)
+	mockSubPrefixDb.On("Put", ctx, []byte("addr"), []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa")).Return(nil)
+
+	_, err := h.CheckVouchers(ctx, "check_vouchers", []byte(""))
+
+	assert.NoError(t, err)
+
+	mockDataStore.AssertExpectations(t)
+	mockAccountService.AssertExpectations(t)
+}
+
+func TestGetVoucherList(t *testing.T) {
+	mockSubPrefixDb := new(mocks.MockSubPrefixDb)
+
+	sessionId := "session123"
+	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
+
+	h := &Handlers{
+		prefixDb: mockSubPrefixDb,
+	}
+
+	mockSubPrefixDb.On("Get", ctx, []byte("sym")).Return([]byte("1:SRF\n2:MILO"), nil)
+
+	res, err := h.GetVoucherList(ctx, "", []byte(""))
+	assert.NoError(t, err)
+	assert.Contains(t, res.Content, "1:SRF\n2:MILO")
+
+	mockSubPrefixDb.AssertExpectations(t)
+}
+
+func TestViewVoucher(t *testing.T) {
+	fm, err := NewFlagManager(flagsPath)
+	if err != nil {
+		t.Logf(err.Error())
+	}
+	mockDataStore := new(mocks.MockUserDataStore)
+	mockSubPrefixDb := new(mocks.MockSubPrefixDb)
+
+	sessionId := "session123"
+	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
+
+	h := &Handlers{
+		userdataStore: mockDataStore,
+		flagManager:   fm.parser,
+		prefixDb:      mockSubPrefixDb,
+	}
+
+	// Define mock voucher data
+	mockVoucherData := map[string]string{
+		"sym":  "1:SRF",
+		"bal":  "1:100",
+		"deci": "1:6",
+		"addr": "1:0xd4c288865Ce",
+	}
+
+	for key, value := range mockVoucherData {
+		mockSubPrefixDb.On("Get", ctx, []byte(key)).Return([]byte(value), nil)
+	}
+
+	// Set up expectations for mockDataStore
+	expectedData := map[utils.DataTyp]string{
+		utils.DATA_TEMPORARY_SYM:     "SRF",
+		utils.DATA_TEMPORARY_BAL:     "100",
+		utils.DATA_TEMPORARY_DECIMAL: "6",
+		utils.DATA_TEMPORARY_ADDRESS: "0xd4c288865Ce",
+	}
+
+	for dataType, dataValue := range expectedData {
+		mockDataStore.On("WriteEntry", ctx, sessionId, dataType, []byte(dataValue)).Return(nil)
+	}
+
+	res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1"))
+	assert.NoError(t, err)
+	assert.Contains(t, res.Content, "SRF\n100")
+
+	mockDataStore.AssertExpectations(t)
+	mockSubPrefixDb.AssertExpectations(t)
+}
+
+func TestSetVoucher(t *testing.T) {
+	mockDataStore := new(mocks.MockUserDataStore)
+
+	sessionId := "session123"
+	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
+
+	// Define the temporary voucher data
+	tempData := &dataserviceapi.TokenHoldings{
+		TokenSymbol:     "SRF",
+		Balance:         "200",
+		TokenDecimals:   "6",
+		ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
+	}
+
+	// Define the expected active entries
+	activeEntries := map[utils.DataTyp][]byte{
+		utils.DATA_ACTIVE_SYM:     []byte(tempData.TokenSymbol),
+		utils.DATA_ACTIVE_BAL:     []byte(tempData.Balance),
+		utils.DATA_ACTIVE_DECIMAL: []byte(tempData.TokenDecimals),
+		utils.DATA_ACTIVE_ADDRESS: []byte(tempData.ContractAddress),
+	}
+
+	// Define the temporary entries to be cleared
+	tempEntries := map[utils.DataTyp][]byte{
+		utils.DATA_TEMPORARY_SYM:     []byte(""),
+		utils.DATA_TEMPORARY_BAL:     []byte(""),
+		utils.DATA_TEMPORARY_DECIMAL: []byte(""),
+		utils.DATA_TEMPORARY_ADDRESS: []byte(""),
+	}
+
+	// Mocking ReadEntry calls for temporary data retrieval
+	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.TokenSymbol), nil)
+	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return([]byte(tempData.Balance), nil)
+	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return([]byte(tempData.TokenDecimals), nil)
+	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return([]byte(tempData.ContractAddress), nil)
+
+	// Mocking WriteEntry calls for setting active data
+	for key, value := range activeEntries {
+		mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil)
+	}
+
+	// Mocking WriteEntry calls for clearing temporary data
+	for key, value := range tempEntries {
+		mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil)
+	}
+
+	h := &Handlers{
+		userdataStore: mockDataStore,
+	}
+
+	res, err := h.SetVoucher(ctx, "someSym", []byte{})
+
+	assert.NoError(t, err)
+
+	assert.Equal(t, string(tempData.TokenSymbol), res.Content)
+
+	mockDataStore.AssertExpectations(t)
+}
diff --git a/internal/models/vouchersresponse.go b/internal/models/vouchersresponse.go
index 010730f..09b085d 100644
--- a/internal/models/vouchersresponse.go
+++ b/internal/models/vouchersresponse.go
@@ -1,15 +1,14 @@
 package models
 
-// VoucherHoldingResponse represents a single voucher holding
+import dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
+
 type VoucherHoldingResponse struct {
-	Ok          bool   `json:"ok"`
-	Description string `json:"description"`
-	Result      struct {
-		Holdings []struct {
-			ContractAddress string `json:"contractAddress"`
-			TokenSymbol     string `json:"tokenSymbol"`
-			TokenDecimals   string `json:"tokenDecimals"`
-			Balance         string `json:"balance"`
-		} `json:"holdings"`
-	} `json:"result"`
+	Ok          bool          `json:"ok"`
+	Description string        `json:"description"`
+	Result      VoucherResult `json:"result"`
+}
+
+// VoucherResult holds the list of token holdings
+type VoucherResult struct {
+	Holdings []dataserviceapi.TokenHoldings `json:"holdings"`
 }
diff --git a/internal/storage/db.go b/internal/storage/db.go
index 060f0c0..8c9ff35 100644
--- a/internal/storage/db.go
+++ b/internal/storage/db.go
@@ -10,6 +10,14 @@ const (
 	DATATYPE_USERSUB = 64
 )
 
+// PrefixDb interface abstracts the database operations.
+type PrefixDb interface {
+	Get(ctx context.Context, key []byte) ([]byte, error)
+	Put(ctx context.Context, key []byte, val []byte) error
+}
+
+var _ PrefixDb = (*SubPrefixDb)(nil)
+
 type SubPrefixDb struct {
 	store db.Db
 	pfx   []byte
@@ -29,11 +37,7 @@ func (s *SubPrefixDb) toKey(k []byte) []byte {
 func (s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) {
 	s.store.SetPrefix(DATATYPE_USERSUB)
 	key = s.toKey(key)
-	v, err := s.store.Get(ctx, key)
-	if err != nil {
-		return nil, err
-	}
-	return v, nil
+	return s.store.Get(ctx, key)
 }
 
 func (s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error {
diff --git a/internal/testutil/mocks/subprefixdbmock.go b/internal/testutil/mocks/subprefixdbmock.go
new file mode 100644
index 0000000..e98bcb6
--- /dev/null
+++ b/internal/testutil/mocks/subprefixdbmock.go
@@ -0,0 +1,21 @@
+package mocks
+
+import (
+	"context"
+
+	"github.com/stretchr/testify/mock"
+)
+
+type MockSubPrefixDb struct {
+	mock.Mock
+}
+
+func (m *MockSubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) {
+	args := m.Called(ctx, key)
+	return args.Get(0).([]byte), args.Error(1)
+}
+
+func (m *MockSubPrefixDb) Put(ctx context.Context, key, val []byte) error {
+	args := m.Called(ctx, key, val)
+	return args.Error(0)
+}
diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go
index 6332345..745b80d 100644
--- a/internal/testutil/testservice/TestAccountService.go
+++ b/internal/testutil/testservice/TestAccountService.go
@@ -7,6 +7,7 @@ import (
 
 	"git.grassecon.net/urdt/ussd/internal/models"
 	"github.com/grassrootseconomics/eth-custodial/pkg/api"
+	dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
 )
 
 type TestAccountService struct {
@@ -75,20 +76,8 @@ func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey
 func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) {
 	return &models.VoucherHoldingResponse{
 		Ok: true,
-		Result: struct {
-			Holdings []struct {
-				ContractAddress string `json:"contractAddress"`
-				TokenSymbol     string `json:"tokenSymbol"`
-				TokenDecimals   string `json:"tokenDecimals"`
-				Balance         string `json:"balance"`
-			} `json:"holdings"`
-		}{
-			Holdings: []struct {
-				ContractAddress string `json:"contractAddress"`
-				TokenSymbol     string `json:"tokenSymbol"`
-				TokenDecimals   string `json:"tokenDecimals"`
-				Balance         string `json:"balance"`
-			}{
+		Result: models.VoucherResult{
+			Holdings: []dataserviceapi.TokenHoldings{
 				{
 					ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee",
 					TokenSymbol:     "SRF",
diff --git a/internal/utils/db.go b/internal/utils/db.go
index 2c1e6fa..802e092 100644
--- a/internal/utils/db.go
+++ b/internal/utils/db.go
@@ -29,6 +29,10 @@ const (
 	DATA_TEMPORARY_BAL
 	DATA_ACTIVE_BAL
 	DATA_PUBLIC_KEY_REVERSE
+	DATA_TEMPORARY_DECIMAL
+	DATA_ACTIVE_DECIMAL
+	DATA_TEMPORARY_ADDRESS
+	DATA_ACTIVE_ADDRESS
 )
 
 func typToBytes(typ DataTyp) []byte {
diff --git a/internal/utils/vouchers.go b/internal/utils/vouchers.go
new file mode 100644
index 0000000..b027cc1
--- /dev/null
+++ b/internal/utils/vouchers.go
@@ -0,0 +1,161 @@
+package utils
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"git.grassecon.net/urdt/ussd/internal/storage"
+	dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
+)
+
+// VoucherMetadata helps organize data fields
+type VoucherMetadata struct {
+	Symbols   string
+	Balances  string
+	Decimals  string
+	Addresses string
+}
+
+// ProcessVouchers converts holdings into formatted strings
+func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata {
+	var data VoucherMetadata
+	var symbols, balances, decimals, addresses []string
+
+	for i, h := range holdings {
+		symbols = append(symbols, fmt.Sprintf("%d:%s", i+1, h.TokenSymbol))
+		balances = append(balances, fmt.Sprintf("%d:%s", i+1, h.Balance))
+		decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals))
+		addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress))
+	}
+
+	data.Symbols = strings.Join(symbols, "\n")
+	data.Balances = strings.Join(balances, "\n")
+	data.Decimals = strings.Join(decimals, "\n")
+	data.Addresses = strings.Join(addresses, "\n")
+
+	return data
+}
+
+// GetVoucherData retrieves and matches voucher data
+func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) {
+	keys := []string{"sym", "bal", "deci", "addr"}
+	data := make(map[string]string)
+
+	for _, key := range keys {
+		value, err := db.Get(ctx, []byte(key))
+		if err != nil {
+			return nil, fmt.Errorf("failed to get %s: %v", key, err)
+		}
+		data[key] = string(value)
+	}
+
+	symbol, balance, decimal, address := MatchVoucher(input,
+		data["sym"],
+		data["bal"],
+		data["deci"],
+		data["addr"])
+
+	if symbol == "" {
+		return nil, nil
+	}
+
+	return &dataserviceapi.TokenHoldings{
+		TokenSymbol:     string(symbol),
+		Balance:         string(balance),
+		TokenDecimals:   string(decimal),
+		ContractAddress: string(address),
+	}, nil
+}
+
+// MatchVoucher finds the matching voucher symbol, balance, decimals and contract address based on the input.
+func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, balance, decimal, address string) {
+	symList := strings.Split(symbols, "\n")
+	balList := strings.Split(balances, "\n")
+	decList := strings.Split(decimals, "\n")
+	addrList := strings.Split(addresses, "\n")
+
+	for i, sym := range symList {
+		parts := strings.SplitN(sym, ":", 2)
+	
+		if input == parts[0] || strings.EqualFold(input, parts[1]) {
+			symbol = parts[1]
+			if i < len(balList) {
+				balance = strings.SplitN(balList[i], ":", 2)[1]
+			}
+			if i < len(decList) {
+				decimal = strings.SplitN(decList[i], ":", 2)[1]
+			}
+			if i < len(addrList) {
+				address = strings.SplitN(addrList[i], ":", 2)[1]
+			}
+			break
+		}
+	}
+	return
+}
+
+// StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore.
+func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error {
+	entries := map[DataTyp][]byte{
+		DATA_TEMPORARY_SYM:     []byte(data.TokenSymbol),
+		DATA_TEMPORARY_BAL:     []byte(data.Balance),
+		DATA_TEMPORARY_DECIMAL: []byte(data.TokenDecimals),
+		DATA_TEMPORARY_ADDRESS: []byte(data.ContractAddress),
+	}
+
+	for key, value := range entries {
+		if err := store.WriteEntry(ctx, sessionId, key, value); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// GetTemporaryVoucherData retrieves temporary voucher metadata from the DataStore.
+func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId string) (*dataserviceapi.TokenHoldings, error) {
+	keys := []DataTyp{
+		DATA_TEMPORARY_SYM,
+		DATA_TEMPORARY_BAL,
+		DATA_TEMPORARY_DECIMAL,
+		DATA_TEMPORARY_ADDRESS,
+	}
+
+	data := &dataserviceapi.TokenHoldings{}
+	values := make([][]byte, len(keys))
+
+	for i, key := range keys {
+		value, err := store.ReadEntry(ctx, sessionId, key)
+		if err != nil {
+			return nil, err
+		}
+		values[i] = value
+	}
+
+	data.TokenSymbol = string(values[0])
+	data.Balance = string(values[1])
+	data.TokenDecimals = string(values[2])
+	data.ContractAddress = string(values[3])
+
+	return data, nil
+}
+
+// UpdateVoucherData sets the active voucher data in the DataStore.
+func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error {
+	// Active voucher data entries
+	activeEntries := map[DataTyp][]byte{
+		DATA_ACTIVE_SYM:     []byte(data.TokenSymbol),
+		DATA_ACTIVE_BAL:     []byte(data.Balance),
+		DATA_ACTIVE_DECIMAL: []byte(data.TokenDecimals),
+		DATA_ACTIVE_ADDRESS: []byte(data.ContractAddress),
+	}
+
+	// Write active data
+	for key, value := range activeEntries {
+		if err := store.WriteEntry(ctx, sessionId, key, value); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/internal/utils/vouchers_test.go b/internal/utils/vouchers_test.go
new file mode 100644
index 0000000..a609d27
--- /dev/null
+++ b/internal/utils/vouchers_test.go
@@ -0,0 +1,203 @@
+package utils
+
+import (
+	"context"
+	"testing"
+
+	"git.grassecon.net/urdt/ussd/internal/storage"
+	"github.com/alecthomas/assert/v2"
+	"github.com/stretchr/testify/require"
+
+	memdb "git.defalsify.org/vise.git/db/mem"
+	dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
+)
+
+// InitializeTestDb sets up and returns an in-memory database and store.
+func InitializeTestDb(t *testing.T) (context.Context, *UserDataStore) {
+	ctx := context.Background()
+
+	// Initialize memDb
+	db := memdb.NewMemDb()
+	err := db.Connect(ctx, "")
+	require.NoError(t, err, "Failed to connect to memDb")
+
+	// Create UserDataStore with memDb
+	store := &UserDataStore{Db: db}
+
+	t.Cleanup(func() {
+		db.Close() // Ensure the DB is closed after each test
+	})
+
+	return ctx, store
+}
+
+func TestMatchVoucher(t *testing.T) {
+	symbols := "1:SRF\n2:MILO"
+	balances := "1:100\n2:200"
+	decimals := "1:6\n2:4"
+	addresses := "1:0xd4c288865Ce\n2:0x41c188d63Qa"
+
+	// Test for valid voucher
+	symbol, balance, decimal, address := MatchVoucher("2", symbols, balances, decimals, addresses)
+
+	// Assertions for valid voucher
+	assert.Equal(t, "MILO", symbol)
+	assert.Equal(t, "200", balance)
+	assert.Equal(t, "4", decimal)
+	assert.Equal(t, "0x41c188d63Qa", address)
+
+	// Test for non-existent voucher
+	symbol, balance, decimal, address = MatchVoucher("3", symbols, balances, decimals, addresses)
+
+	// Assertions for non-match
+	assert.Equal(t, "", symbol)
+	assert.Equal(t, "", balance)
+	assert.Equal(t, "", decimal)
+	assert.Equal(t, "", address)
+}
+
+func TestProcessVouchers(t *testing.T) {
+	holdings := []dataserviceapi.TokenHoldings{
+		{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"},
+		{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"},
+	}
+
+	expectedResult := VoucherMetadata{
+		Symbols:   "1:SRF\n2:MILO",
+		Balances:  "1:100\n2:200",
+		Decimals:  "1:6\n2:4",
+		Addresses: "1:0xd4c288865Ce\n2:0x41c188d63Qa",
+	}
+
+	result := ProcessVouchers(holdings)
+
+	assert.Equal(t, expectedResult, result)
+}
+
+func TestGetVoucherData(t *testing.T) {
+	ctx := context.Background()
+
+	db := memdb.NewMemDb()
+	err := db.Connect(ctx, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	spdb := storage.NewSubPrefixDb(db, []byte("vouchers"))
+
+	// Test voucher data
+	mockData := map[string][]byte{
+		"sym":  []byte("1:SRF\n2:MILO"),
+		"bal":  []byte("1:100\n2:200"),
+		"deci": []byte("1:6\n2:4"),
+		"addr": []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"),
+	}
+
+	// Put the data
+	for key, value := range mockData {
+		err = spdb.Put(ctx, []byte(key), []byte(value))
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	result, err := GetVoucherData(ctx, spdb, "1")
+
+	assert.NoError(t, err)
+	assert.Equal(t, "SRF", result.TokenSymbol)
+	assert.Equal(t, "100", result.Balance)
+	assert.Equal(t, "6", result.TokenDecimals)
+	assert.Equal(t, "0xd4c288865Ce", result.ContractAddress)
+}
+
+func TestStoreTemporaryVoucher(t *testing.T) {
+	ctx, store := InitializeTestDb(t)
+	sessionId := "session123"
+
+	// Test data
+	voucherData := &dataserviceapi.TokenHoldings{
+		TokenSymbol:     "SRF",
+		Balance:         "200",
+		TokenDecimals:   "6",
+		ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
+	}
+
+	// Execute the function being tested
+	err := StoreTemporaryVoucher(ctx, store, sessionId, voucherData)
+	require.NoError(t, err)
+
+	// Verify stored data
+	expectedEntries := map[DataTyp][]byte{
+		DATA_TEMPORARY_SYM:     []byte("SRF"),
+		DATA_TEMPORARY_BAL:     []byte("200"),
+		DATA_TEMPORARY_DECIMAL: []byte("6"),
+		DATA_TEMPORARY_ADDRESS: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"),
+	}
+
+	for key, expectedValue := range expectedEntries {
+		storedValue, err := store.ReadEntry(ctx, sessionId, key)
+		require.NoError(t, err)
+		require.Equal(t, expectedValue, storedValue, "Mismatch for key %v", key)
+	}
+}
+
+func TestGetTemporaryVoucherData(t *testing.T) {
+	ctx, store := InitializeTestDb(t)
+	sessionId := "session123"
+
+	// Test voucher data
+	tempData := &dataserviceapi.TokenHoldings{
+		TokenSymbol:     "SRF",
+		Balance:         "200",
+		TokenDecimals:   "6",
+		ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
+	}
+
+	// Store the data
+	err := StoreTemporaryVoucher(ctx, store, sessionId, tempData)
+	require.NoError(t, err)
+
+	// Execute the function being tested
+	data, err := GetTemporaryVoucherData(ctx, store, sessionId)
+	require.NoError(t, err)
+	require.Equal(t, tempData, data)
+}
+
+func TestUpdateVoucherData(t *testing.T) {
+	ctx, store := InitializeTestDb(t)
+	sessionId := "session123"
+
+	// New voucher data
+	newData := &dataserviceapi.TokenHoldings{
+		TokenSymbol:     "SRF",
+		Balance:         "200",
+		TokenDecimals:   "6",
+		ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
+	}
+
+	// Old temporary data
+	tempData := &dataserviceapi.TokenHoldings{
+		TokenSymbol:     "OLD",
+		Balance:         "100",
+		TokenDecimals:   "8",
+		ContractAddress: "0xold",
+	}
+	require.NoError(t, StoreTemporaryVoucher(ctx, store, sessionId, tempData))
+
+	// Execute update
+	err := UpdateVoucherData(ctx, store, sessionId, newData)
+	require.NoError(t, err)
+
+	// Verify active data was stored correctly
+	activeEntries := map[DataTyp][]byte{
+		DATA_ACTIVE_SYM:     []byte(newData.TokenSymbol),
+		DATA_ACTIVE_BAL:     []byte(newData.Balance),
+		DATA_ACTIVE_DECIMAL: []byte(newData.TokenDecimals),
+		DATA_ACTIVE_ADDRESS: []byte(newData.ContractAddress),
+	}
+
+	for key, expectedValue := range activeEntries {
+		storedValue, err := store.ReadEntry(ctx, sessionId, key)
+		require.NoError(t, err)
+		require.Equal(t, expectedValue, storedValue, "Active data mismatch for key %v", key)
+	}
+}