diff --git a/client/value.go b/client/value.go
new file mode 100644
index 0000000000000000000000000000000000000000..342aea66cc536113b49ead9e465ef6fac1408045
--- /dev/null
+++ b/client/value.go
@@ -0,0 +1,64 @@
+package client
+
+import (
+	"fmt"
+	"net/http"
+
+	webapi_attachments "github.com/iotaledger/goshimmer/plugins/webapi/value/attachments"
+	webapi_gettxn "github.com/iotaledger/goshimmer/plugins/webapi/value/gettransactionbyid"
+	webapi_sendtxn "github.com/iotaledger/goshimmer/plugins/webapi/value/sendtransaction"
+	webapi_unspentoutputs "github.com/iotaledger/goshimmer/plugins/webapi/value/unspentoutputs"
+)
+
+const (
+	routeAttachments    = "value/attachments"
+	routeGetTxnByID     = "value/transactionByID"
+	routeSendTxn        = "value/sendTransaction"
+	routeUnspentOutputs = "value/unspentOutputs"
+)
+
+// GetAttachments gets the attachments of a transaction ID
+func (api *GoShimmerAPI) GetAttachments(base58EncodedTxnID string) (*webapi_attachments.Response, error) {
+	res := &webapi_attachments.Response{}
+	if err := api.do(http.MethodGet, func() string {
+		return fmt.Sprintf("%s?txnID=%s", routeAttachments, base58EncodedTxnID)
+	}(), nil, res); err != nil {
+		return nil, err
+	}
+
+	return res, nil
+}
+
+// GetTransactionByID gets the transaction of a transaction ID
+func (api *GoShimmerAPI) GetTransactionByID(base58EncodedTxnID string) (*webapi_gettxn.Response, error) {
+	res := &webapi_gettxn.Response{}
+	if err := api.do(http.MethodGet, func() string {
+		return fmt.Sprintf("%s?txnID=%s", routeGetTxnByID, base58EncodedTxnID)
+	}(), nil, res); err != nil {
+		return nil, err
+	}
+
+	return res, nil
+}
+
+// GetUnspentOutputs return unspent output IDs of addresses
+func (api *GoShimmerAPI) GetUnspentOutputs(addresses []string) (*webapi_unspentoutputs.Response, error) {
+	res := &webapi_unspentoutputs.Response{}
+	if err := api.do(http.MethodPost, routeUnspentOutputs,
+		&webapi_unspentoutputs.Request{Addresses: addresses}, res); err != nil {
+		return nil, err
+	}
+
+	return res, nil
+}
+
+// SendTransaction sends the transaction(bytes) to Tangle and returns transaction ID
+func (api *GoShimmerAPI) SendTransaction(txnBytes []byte) (string, error) {
+	res := &webapi_sendtxn.Response{}
+	if err := api.do(http.MethodPost, routeSendTxn,
+		&webapi_sendtxn.Request{TransactionBytes: txnBytes}, res); err != nil {
+		return "", err
+	}
+
+	return res.TransactionID, nil
+}
diff --git a/dapps/valuetransfers/packages/transaction/outputid.go b/dapps/valuetransfers/packages/transaction/outputid.go
index 3eadb0977520e425dc3fea61fd743ccaf665c893..b8386d60dbc42dfbbb7bb78a73481fb14999284f 100644
--- a/dapps/valuetransfers/packages/transaction/outputid.go
+++ b/dapps/valuetransfers/packages/transaction/outputid.go
@@ -1,6 +1,7 @@
 package transaction
 
 import (
+	"fmt"
 	"github.com/mr-tron/base58"
 
 	"github.com/iotaledger/hive.go/marshalutil"
@@ -19,6 +20,27 @@ func NewOutputID(outputAddress address.Address, transactionID ID) (outputID Outp
 	return
 }
 
+// OutputIDFromBase58 creates an output id from a base58 encoded string.
+func OutputIDFromBase58(base58String string) (outputid OutputID, err error) {
+	// decode string
+	bytes, err := base58.Decode(base58String)
+	if err != nil {
+		return
+	}
+
+	// sanitize input
+	if len(bytes) != OutputIDLength {
+		err = fmt.Errorf("base58 encoded string does not match the length of a output id")
+
+		return
+	}
+
+	// copy bytes to result
+	copy(outputid[:], bytes)
+
+	return
+}
+
 // OutputIDFromBytes unmarshals an OutputID from a sequence of bytes.
 func OutputIDFromBytes(bytes []byte) (result OutputID, consumedBytes int, err error) {
 	// parse the bytes
diff --git a/pluginmgr/webapi/plugins.go b/pluginmgr/webapi/plugins.go
index dd7a2e0ba9001cd6b5d1fbed6e92e535713f0769..48b6ba7002cc83baf1d553bbd94bc4967ad0f645 100644
--- a/pluginmgr/webapi/plugins.go
+++ b/pluginmgr/webapi/plugins.go
@@ -8,6 +8,7 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/webapi/info"
 	"github.com/iotaledger/goshimmer/plugins/webapi/message"
 	"github.com/iotaledger/goshimmer/plugins/webapi/spammer"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value"
 	"github.com/iotaledger/goshimmer/plugins/webauth"
 	"github.com/iotaledger/hive.go/node"
 )
@@ -21,4 +22,5 @@ var PLUGINS = node.Plugins(
 	message.Plugin,
 	autopeering.Plugin,
 	info.Plugin,
+	value.Plugin,
 )
diff --git a/plugins/webapi/value/attachments/handler.go b/plugins/webapi/value/attachments/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..71cca4df720c44af2312ca0178c1a61ebe02cef3
--- /dev/null
+++ b/plugins/webapi/value/attachments/handler.go
@@ -0,0 +1,68 @@
+package attachments
+
+import (
+	"net/http"
+
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/utils"
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/log"
+)
+
+// Handler gets the value attachments.
+func Handler(c echo.Context) error {
+	txnID, err := transaction.IDFromBase58(c.QueryParam("txnID"))
+	if err != nil {
+		log.Info(err)
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	var valueObjs []ValueObject
+
+	// get txn by txn id
+	txnObj := valuetransfers.Tangle.Transaction(txnID)
+	if !txnObj.Exists() {
+		return c.JSON(http.StatusNotFound, Response{Error: "Transaction not found"})
+	}
+	txn := utils.ParseTransaction(txnObj.Unwrap())
+
+	// get attachements by txn id
+	for _, attachmentObj := range valuetransfers.Tangle.Attachments(txnID) {
+		if !attachmentObj.Exists() {
+			continue
+		}
+		attachment := attachmentObj.Unwrap()
+
+		// get payload by payload id
+		payloadObj := valuetransfers.Tangle.Payload(attachment.PayloadID())
+		if !payloadObj.Exists() {
+			continue
+		}
+		payload := payloadObj.Unwrap()
+
+		// append value object
+		valueObjs = append(valueObjs, ValueObject{
+			ID:          payload.ID().String(),
+			ParentID0:   payload.TrunkID().String(),
+			ParentID1:   payload.BranchID().String(),
+			Transaction: txn,
+		})
+	}
+
+	return c.JSON(http.StatusOK, Response{Attachments: valueObjs})
+}
+
+// Response is the HTTP response from retreiving value objects.
+type Response struct {
+	Attachments []ValueObject `json:"attachments,omitempty"`
+	Error       string        `json:"error,omitempty"`
+}
+
+// ValueObject holds the information of a value object.
+type ValueObject struct {
+	ID          string            `json:"id"`
+	ParentID0   string            `json:"parent0_id"`
+	ParentID1   string            `json:"parent1_id"`
+	Transaction utils.Transaction `json:"transaction"`
+}
diff --git a/plugins/webapi/value/gettransactionbyid/handler.go b/plugins/webapi/value/gettransactionbyid/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..3ae7e4fd029bdb77af3359aa8664099c3c68b3af
--- /dev/null
+++ b/plugins/webapi/value/gettransactionbyid/handler.go
@@ -0,0 +1,44 @@
+package gettransactionbyid
+
+import (
+	"net/http"
+
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/utils"
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/log"
+)
+
+// Handler gets the transaction by id.
+func Handler(c echo.Context) error {
+	txnID, err := transaction.IDFromBase58(c.QueryParam("txnID"))
+	if err != nil {
+		log.Info(err)
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	// get txn by txn id
+	txnObj := valuetransfers.Tangle.Transaction(txnID)
+	if !txnObj.Exists() {
+		return c.JSON(http.StatusNotFound, Response{Error: "Transaction not found"})
+	}
+	txn := utils.ParseTransaction(txnObj.Unwrap())
+
+	// TODO: get inclusion state
+	return c.JSON(http.StatusOK, Response{
+		Transaction: txn,
+		InclusionState: utils.InclusionState{
+			Confirmed: true,
+			Conflict:  false,
+			Liked:     true,
+		},
+	})
+}
+
+// Response is the HTTP response from retreiving transaction.
+type Response struct {
+	Transaction    utils.Transaction    `json:"transaction,omitempty"`
+	InclusionState utils.InclusionState `json:"inclusion_state,omitempty"`
+	Error          string               `json:"error,omitempty"`
+}
diff --git a/plugins/webapi/value/plugin.go b/plugins/webapi/value/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..72facce9182a959913a67031ecdf92ea0d3b40ca
--- /dev/null
+++ b/plugins/webapi/value/plugin.go
@@ -0,0 +1,27 @@
+package value
+
+import (
+	"github.com/iotaledger/goshimmer/plugins/webapi"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/attachments"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/gettransactionbyid"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/sendtransaction"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/testsendtxn"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/unspentoutputs"
+	"github.com/iotaledger/hive.go/node"
+)
+
+// PluginName is the name of the web API DRNG endpoint plugin.
+const PluginName = "WebAPI Value Endpoint"
+
+var (
+	// Plugin is the plugin instance of the web API DRNG endpoint plugin.
+	Plugin = node.NewPlugin(PluginName, node.Enabled, configure)
+)
+
+func configure(_ *node.Plugin) {
+	webapi.Server.GET("value/attachments", attachments.Handler)
+	webapi.Server.POST("value/unspentOutputs", unspentoutputs.Handler)
+	webapi.Server.POST("value/sendTransaction", sendtransaction.Handler)
+	webapi.Server.POST("value/testSendTxn", testsendtxn.Handler)
+	webapi.Server.GET("value/transactionByID", gettransactionbyid.Handler)
+}
diff --git a/plugins/webapi/value/sendtransaction/handler.go b/plugins/webapi/value/sendtransaction/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..b1dfa63d99ed7f3b85b4ac1432f4e9e4ab1ecc61
--- /dev/null
+++ b/plugins/webapi/value/sendtransaction/handler.go
@@ -0,0 +1,48 @@
+package sendtransaction
+
+import (
+	"net/http"
+
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
+	"github.com/iotaledger/goshimmer/plugins/issuer"
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/log"
+)
+
+// Handler sends a transaction.
+func Handler(c echo.Context) error {
+	var request Request
+	if err := c.Bind(&request); err != nil {
+		log.Info(err.Error())
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	// prepare transaction
+	tx, _, err := transaction.FromBytes(request.TransactionBytes)
+	if err != nil {
+		log.Info(err.Error())
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	// Prepare value payload and send the message to tangle
+	payload := valuetransfers.ValueObjectFactory().IssueTransaction(tx)
+	_, err = issuer.IssuePayload(payload)
+	if err != nil {
+		log.Info(err.Error())
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	return c.JSON(http.StatusOK, Response{TransactionID: tx.ID().String()})
+}
+
+// Request holds the transaction object(bytes) to send.
+type Request struct {
+	TransactionBytes []byte `json:"txn_bytes"`
+}
+
+// Response is the HTTP response from sending transaction.
+type Response struct {
+	TransactionID string `json:"transaction_id,omitempty"`
+	Error         string `json:"error,omitempty"`
+}
diff --git a/plugins/webapi/value/testsendtxn/handler.go b/plugins/webapi/value/testsendtxn/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..927de126357de3f4c84a88dcf8bc94b77a4370a8
--- /dev/null
+++ b/plugins/webapi/value/testsendtxn/handler.go
@@ -0,0 +1,84 @@
+package testsendtxn
+
+import (
+	"net/http"
+
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
+	"github.com/iotaledger/goshimmer/plugins/issuer"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/utils"
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/log"
+)
+
+// Handler sends a transaction.
+func Handler(c echo.Context) error {
+	var request Request
+	if err := c.Bind(&request); err != nil {
+		log.Info(err.Error())
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	// prepare inputs
+	outputids := []transaction.OutputID{}
+	for _, in := range request.Inputs {
+		id, err := transaction.OutputIDFromBase58(in)
+		if err != nil {
+			log.Info(err.Error())
+			return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+		}
+		outputids = append(outputids, id)
+	}
+	inputs := transaction.NewInputs(outputids...)
+
+	// prepare outputs
+	outmap := map[address.Address][]*balance.Balance{}
+	for _, out := range request.Outputs {
+		addr, err := address.FromBase58(out.Address)
+		if err != nil {
+			log.Info(err.Error())
+			return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+		}
+
+		// iterate balances
+		balances := []*balance.Balance{}
+		for _, b := range out.Balances {
+			// get token color
+			color, _, err := balance.ColorFromBytes([]byte(b.Color))
+			if err != nil {
+				log.Info(err.Error())
+				return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+			}
+			balances = append(balances, balance.New(color, b.Value))
+		}
+		outmap[addr] = balances
+	}
+	outputs := transaction.NewOutputs(outmap)
+
+	// prepare transaction
+	// Note: not signed
+	tx := transaction.New(inputs, outputs)
+
+	// Prepare value payload and send the message to tangle
+	payload := valuetransfers.ValueObjectFactory().IssueTransaction(tx)
+	_, err := issuer.IssuePayload(payload)
+	if err != nil {
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	return c.JSON(http.StatusOK, Response{TransactionID: tx.ID().String()})
+}
+
+// Request holds the inputs and outputs to send.
+type Request struct {
+	Inputs  []string       `json:"inputs"`
+	Outputs []utils.Output `json:"outputs"`
+}
+
+// Response is the HTTP response from sending transaction.
+type Response struct {
+	TransactionID string `json:"transaction_id,omitempty"`
+	Error         string `json:"error,omitempty"`
+}
diff --git a/plugins/webapi/value/unspentoutputs/handler.go b/plugins/webapi/value/unspentoutputs/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..7523fcb52226a1fe00f0e6831125fd398ea6136e
--- /dev/null
+++ b/plugins/webapi/value/unspentoutputs/handler.go
@@ -0,0 +1,78 @@
+package unspentoutputs
+
+import (
+	"net/http"
+
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/utils"
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/log"
+)
+
+// Handler gets the unspent outputs.
+func Handler(c echo.Context) error {
+	var request Request
+	if err := c.Bind(&request); err != nil {
+		log.Info(err.Error())
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	var unspents []UnspentOutput
+	for _, strAddress := range request.Addresses {
+		address, err := address.FromBase58(strAddress)
+		if err != nil {
+			log.Info(err.Error())
+			continue
+		}
+
+		outputids := make([]OutputID, 0)
+		// get outputids by address
+		for id, outputObj := range valuetransfers.Tangle.OutputsOnAddress(address) {
+			output := outputObj.Unwrap()
+
+			// TODO: get inclusion state
+			if output.ConsumerCount() == 0 {
+				outputids = append(outputids, OutputID{
+					ID: id.String(),
+					InclusionState: utils.InclusionState{
+						Confirmed: true,
+						Conflict:  false,
+						Liked:     true,
+					},
+				})
+			}
+		}
+
+		unspents = append(unspents, UnspentOutput{
+			Address:   strAddress,
+			OutputIDs: outputids,
+		})
+	}
+
+	return c.JSON(http.StatusOK, Response{UnspentOutputs: unspents})
+}
+
+// Request holds the addresses to query.
+type Request struct {
+	Addresses []string `json:"addresses,omitempty"`
+	Error     string   `json:"error,omitempty"`
+}
+
+// Response is the HTTP response from retreiving value objects.
+type Response struct {
+	UnspentOutputs []UnspentOutput `json:"unspent_outputs,omitempty"`
+	Error          string          `json:"error,omitempty"`
+}
+
+// UnspentOutput holds the address and the corresponding unspent output ids
+type UnspentOutput struct {
+	Address   string     `json:"address"`
+	OutputIDs []OutputID `json:"output_ids"`
+}
+
+// OutputID holds the output id and its inclusion state
+type OutputID struct {
+	ID             string               `json:"id"`
+	InclusionState utils.InclusionState `json:"inclusion_state"`
+}
diff --git a/plugins/webapi/value/utils/transaction_handler.go b/plugins/webapi/value/utils/transaction_handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..308904d55c3e577c0d6f5cdd08b0d2fecc0590f2
--- /dev/null
+++ b/plugins/webapi/value/utils/transaction_handler.go
@@ -0,0 +1,70 @@
+package utils
+
+import (
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
+)
+
+// ParseTransaction handle transaction json object.
+func ParseTransaction(t *transaction.Transaction) (txn Transaction) {
+	var inputs []string
+	var outputs []Output
+	// process inputs
+	t.Inputs().ForEachAddress(func(currentAddress address.Address) bool {
+		inputs = append(inputs, currentAddress.String())
+		return true
+	})
+
+	// process outputs: address + balance
+	t.Outputs().ForEach(func(address address.Address, balances []*balance.Balance) bool {
+		var b []Balance
+		for _, balance := range balances {
+			b = append(b, Balance{
+				Value: balance.Value(),
+				Color: balance.Color().String(),
+			})
+		}
+		t := Output{
+			Address:  address.String(),
+			Balances: b,
+		}
+		outputs = append(outputs, t)
+
+		return true
+	})
+
+	return Transaction{
+		Inputs:      inputs,
+		Outputs:     outputs,
+		Signature:   t.SignatureBytes(),
+		DataPayload: t.GetDataPayload(),
+	}
+}
+
+// Transaction holds the information of a transaction.
+type Transaction struct {
+	Inputs      []string `json:"inputs"`
+	Outputs     []Output `json:"outputs"`
+	Signature   []byte   `json:"signature"`
+	DataPayload []byte   `json:"data_payload"`
+}
+
+// Output consists an address and balances
+type Output struct {
+	Address  string    `json:"address"`
+	Balances []Balance `json:"balances"`
+}
+
+// Balance holds the value and the color of token
+type Balance struct {
+	Value int64  `json:"value"`
+	Color string `json:"color"`
+}
+
+// InclusionState represents the different states of an OutputID
+type InclusionState struct {
+	Confirmed bool `json:"confirmed,omitempty"`
+	Conflict  bool `json:"conflict,omitempty"`
+	Liked     bool `json:"liked,omitempty"`
+}