diff --git a/client/value.go b/client/value.go
index 342aea66cc536113b49ead9e465ef6fac1408045..85a560dca5fa2bcd6efd7f642ddb3ac13ab16d48 100644
--- a/client/value.go
+++ b/client/value.go
@@ -7,6 +7,7 @@ import (
 	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_sendtxnbyjson "github.com/iotaledger/goshimmer/plugins/webapi/value/sendtransactionbyjson"
 	webapi_unspentoutputs "github.com/iotaledger/goshimmer/plugins/webapi/value/unspentoutputs"
 )
 
@@ -14,6 +15,7 @@ const (
 	routeAttachments    = "value/attachments"
 	routeGetTxnByID     = "value/transactionByID"
 	routeSendTxn        = "value/sendTransaction"
+	routeSendTxnByJSON  = "value/sendTransactionByJson"
 	routeUnspentOutputs = "value/unspentOutputs"
 )
 
@@ -52,7 +54,7 @@ func (api *GoShimmerAPI) GetUnspentOutputs(addresses []string) (*webapi_unspento
 	return res, nil
 }
 
-// SendTransaction sends the transaction(bytes) to Tangle and returns transaction ID
+// SendTransaction sends the transaction(bytes) to the Value Tangle and returns transaction ID.
 func (api *GoShimmerAPI) SendTransaction(txnBytes []byte) (string, error) {
 	res := &webapi_sendtxn.Response{}
 	if err := api.do(http.MethodPost, routeSendTxn,
@@ -62,3 +64,19 @@ func (api *GoShimmerAPI) SendTransaction(txnBytes []byte) (string, error) {
 
 	return res.TransactionID, nil
 }
+
+// SendTransactionByJSON sends the transaction(JSON) to the Value Tangle and returns transaction ID.
+func (api *GoShimmerAPI) SendTransactionByJSON(txn webapi_sendtxnbyjson.Request) (string, error) {
+	res := &webapi_sendtxn.Response{}
+	if err := api.do(http.MethodPost, routeSendTxnByJSON,
+		&webapi_sendtxnbyjson.Request{
+			Inputs:     txn.Inputs,
+			Outputs:    txn.Outputs,
+			Data:       txn.Data,
+			Signatures: txn.Signatures,
+		}, res); err != nil {
+		return "", err
+	}
+
+	return res.TransactionID, nil
+}
diff --git a/dapps/valuetransfers/packages/address/signaturescheme/bls.go b/dapps/valuetransfers/packages/address/signaturescheme/bls.go
index 7b10349b0419c144fd89151a071864f7f6bb8e0e..89cec265cacf5893709d8cd70fdce04338392356 100644
--- a/dapps/valuetransfers/packages/address/signaturescheme/bls.go
+++ b/dapps/valuetransfers/packages/address/signaturescheme/bls.go
@@ -227,5 +227,15 @@ func AggregateBLSSignatures(sigs ...Signature) (Signature, error) {
 	return NewBLSSignature(pubKeyBin, sigBin), nil
 }
 
+// PublicKeySize returns the size of the public key.
+func (sig *BLSSignature) PublicKeySize() int {
+	return BLSPublicKeySize
+}
+
+// SignatureSize returns the size of the signature.
+func (sig *BLSSignature) SignatureSize() int {
+	return BLSPrivateKeySize
+}
+
 // interface contract (allow the compiler to check if the implementation has all of the required methods).
 var _ Signature = &BLSSignature{}
diff --git a/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go b/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go
index 846d92de594628c9cea3c00d2057abb456cc6495..98e0767b63061f530a27fdb4b64261828e477e0b 100644
--- a/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go
+++ b/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go
@@ -124,4 +124,14 @@ func (signature *ED25519Signature) Address() address.Address {
 	return address.FromED25519PubKey(signature.publicKey)
 }
 
+// PublicKeySize returns the size of the public key.
+func (signature *ED25519Signature) PublicKeySize() int {
+	return ed25519.PublicKeySize
+}
+
+// SignatureSize returns the size of the signature.
+func (signature *ED25519Signature) SignatureSize() int {
+	return ed25519.SignatureSize
+}
+
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/dapps/valuetransfers/packages/address/signaturescheme/signature.go b/dapps/valuetransfers/packages/address/signaturescheme/signature.go
index eb7d6e47dff9cc57f78b307189d5f690814726e1..541dcf4d0cb52b95ed64fb1b7c148e7431eb7174 100644
--- a/dapps/valuetransfers/packages/address/signaturescheme/signature.go
+++ b/dapps/valuetransfers/packages/address/signaturescheme/signature.go
@@ -12,4 +12,10 @@ type Signature interface {
 
 	// Address returns the address that this signature signs.
 	Address() address.Address
+
+	// PublicKeySize returns the size of the public key.
+	PublicKeySize() int
+
+	// SignatureSize returns the size of the signature.
+	SignatureSize() int
 }
diff --git a/dapps/valuetransfers/packages/transaction/transaction.go b/dapps/valuetransfers/packages/transaction/transaction.go
index 7046fe4a93d76f50fa66dde7a4ea639cc14a7dc3..da41e4a4140bc49d769891ee296f98b86056bfd1 100644
--- a/dapps/valuetransfers/packages/transaction/transaction.go
+++ b/dapps/valuetransfers/packages/transaction/transaction.go
@@ -177,6 +177,20 @@ func (transaction *Transaction) SignaturesValid() bool {
 	return signaturesValid
 }
 
+// Signatures returns all the signatures in this transaction.
+func (transaction *Transaction) Signatures() (signatures []signaturescheme.Signature) {
+	transaction.inputs.ForEachAddress(func(address address.Address) bool {
+		signature, exists := transaction.signatures.Get(address)
+		if !exists || !signature.IsValid(transaction.EssenceBytes()) {
+			return false
+		}
+		signatures = append(signatures, signature)
+		return true
+	})
+
+	return signatures
+}
+
 // InputsCountValid returns true if the number of inputs in this transaction is not greater than MaxTransactionInputCount.
 func (transaction *Transaction) InputsCountValid() bool {
 	return transaction.inputs.Size() <= MaxTransactionInputCount
diff --git a/plugins/webapi/value/plugin.go b/plugins/webapi/value/plugin.go
index f9f4cb9b16b70f835a275b30528b27703e9a54d4..f9f8a4ca4169943fb4a50ece68ba5738fac0809f 100644
--- a/plugins/webapi/value/plugin.go
+++ b/plugins/webapi/value/plugin.go
@@ -7,6 +7,7 @@ import (
 	"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/sendtransactionbyjson"
 	"github.com/iotaledger/goshimmer/plugins/webapi/value/testsendtxn"
 	"github.com/iotaledger/goshimmer/plugins/webapi/value/unspentoutputs"
 	"github.com/iotaledger/hive.go/node"
@@ -33,6 +34,7 @@ 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/sendTransactionByJson", sendtransactionbyjson.Handler)
 	webapi.Server().POST("value/testSendTxn", testsendtxn.Handler)
 	webapi.Server().GET("value/transactionByID", gettransactionbyid.Handler)
 }
diff --git a/plugins/webapi/value/sendtransactionbyjson/handler.go b/plugins/webapi/value/sendtransactionbyjson/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..5300e48db0f2a219e8236d20df35ae128a7436c9
--- /dev/null
+++ b/plugins/webapi/value/sendtransactionbyjson/handler.go
@@ -0,0 +1,234 @@
+package sendtransactionbyjson
+
+import (
+	"fmt"
+	"net/http"
+	"sync"
+	"time"
+
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address/signaturescheme"
+	"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/iotaledger/hive.go/crypto/ed25519"
+	"github.com/iotaledger/hive.go/marshalutil"
+	"github.com/labstack/echo"
+	"github.com/mr-tron/base58/base58"
+)
+
+var (
+	sendTxMu           sync.Mutex
+	maxBookedAwaitTime = 5 * time.Second
+
+	// ErrMalformedInputs defines a malformed inputs error.
+	ErrMalformedInputs = fmt.Errorf("malformed inputs")
+	// ErrMalformedOutputs defines a malformed outputs error.
+	ErrMalformedOutputs = fmt.Errorf("malformed outputs")
+	// ErrMalformedData defines a malformed data error.
+	ErrMalformedData = fmt.Errorf("malformed data")
+	// ErrMalformedColor defines a malformed color error.
+	ErrMalformedColor = fmt.Errorf("malformed color")
+	// ErrMalformedPublicKey defines a malformed publicKey error.
+	ErrMalformedPublicKey = fmt.Errorf("malformed publicKey")
+	// ErrMalformedSignature defines a malformed signature error.
+	ErrMalformedSignature = fmt.Errorf("malformed signature")
+	// ErrWrongSignature defines a wrong signature error.
+	ErrWrongSignature = fmt.Errorf("wrong signature")
+	// ErrSignatureVersion defines a unsupported signature version error.
+	ErrSignatureVersion = fmt.Errorf("unsupported signature version")
+)
+
+// Handler sends a transaction.
+func Handler(c echo.Context) error {
+	sendTxMu.Lock()
+	defer sendTxMu.Unlock()
+
+	var request Request
+	if err := c.Bind(&request); err != nil {
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	tx, err := NewTransactionFromJSON(request)
+	if err != nil {
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	// validate transaction
+	err = valuetransfers.Tangle().ValidateTransactionToAttach(tx)
+	if err != nil {
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	// Prepare value payload and send the message to tangle
+	payload, err := valuetransfers.ValueObjectFactory().IssueTransaction(tx)
+	if err != nil {
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+	_, err = issuer.IssuePayload(payload)
+	if err != nil {
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+
+	if err := valuetransfers.AwaitTransactionToBeBooked(tx.ID(), maxBookedAwaitTime); err != nil {
+		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
+	}
+	return c.JSON(http.StatusOK, Response{TransactionID: tx.ID().String()})
+}
+
+// NewTransactionFromJSON returns a new transaction from a given JSON request or an error.
+func NewTransactionFromJSON(request Request) (*transaction.Transaction, error) {
+	// prepare inputs
+	inputs := make([]transaction.OutputID, len(request.Inputs))
+	for i, input := range request.Inputs {
+		b, err := base58.Decode(input)
+		if err != nil || len(b) != transaction.OutputIDLength {
+			return nil, ErrMalformedInputs
+		}
+		copy(inputs[i][:], b)
+	}
+
+	// prepare ouputs
+	outputs := make(map[address.Address][]*balance.Balance)
+	for _, output := range request.Outputs {
+		address, err := address.FromBase58(output.Address)
+		if err != nil {
+			return nil, ErrMalformedOutputs
+		}
+
+		balances := []*balance.Balance{}
+		for _, b := range output.Balances {
+			var color balance.Color
+			if b.Color == "IOTA" {
+				color = balance.ColorIOTA
+			} else {
+				colorBytes, err := base58.Decode(b.Color)
+				if err != nil || len(colorBytes) != balance.ColorLength {
+					return nil, ErrMalformedColor
+				}
+				copy(color[:], colorBytes)
+			}
+			balances = append(balances, &balance.Balance{
+				Value: b.Value,
+				Color: color,
+			})
+		}
+
+		outputs[address] = balances
+	}
+
+	// prepare transaction
+	tx := transaction.New(transaction.NewInputs(inputs...), transaction.NewOutputs(outputs))
+
+	// add data payload
+	if request.Data != nil {
+		tx.SetDataPayload(request.Data)
+	}
+
+	// add signatures
+	for _, signature := range request.Signatures {
+		switch signature.Version {
+
+		case address.VersionED25519:
+			pubKeyBytes, err := base58.Decode(signature.PublicKey)
+			if err != nil || len(pubKeyBytes) != ed25519.PublicKeySize {
+				return nil, ErrMalformedPublicKey
+			}
+
+			signatureBytes, err := base58.Decode(signature.Signature)
+			if err != nil || len(signatureBytes) != ed25519.SignatureSize {
+				return nil, ErrMalformedSignature
+			}
+
+			marshalUtil := marshalutil.New(1 + ed25519.PublicKeySize + ed25519.SignatureSize)
+			marshalUtil.WriteByte(address.VersionED25519)
+			marshalUtil.WriteBytes(pubKeyBytes[:])
+			marshalUtil.WriteBytes(signatureBytes[:])
+
+			sign, _, err := signaturescheme.Ed25519SignatureFromBytes(marshalUtil.Bytes())
+			if err != nil {
+				return nil, ErrWrongSignature
+			}
+			err = tx.PutSignature(sign)
+			if err != nil {
+				return nil, ErrWrongSignature
+			}
+
+		case address.VersionBLS:
+			pubKeyBytes, err := base58.Decode(signature.PublicKey)
+			if err != nil || len(pubKeyBytes) != signaturescheme.BLSPublicKeySize {
+				return nil, ErrMalformedPublicKey
+			}
+
+			signatureBytes, err := base58.Decode(signature.Signature)
+			if err != nil || len(signatureBytes) != signaturescheme.BLSSignatureSize {
+				return nil, ErrMalformedSignature
+			}
+
+			marshalUtil := marshalutil.New(signaturescheme.BLSFullSignatureSize)
+			marshalUtil.WriteByte(address.VersionBLS)
+			marshalUtil.WriteBytes(pubKeyBytes[:])
+			marshalUtil.WriteBytes(signatureBytes[:])
+
+			sign, _, err := signaturescheme.BLSSignatureFromBytes(marshalUtil.Bytes())
+			if err != nil {
+				return nil, ErrWrongSignature
+			}
+			err = tx.PutSignature(sign)
+			if err != nil {
+				return nil, ErrWrongSignature
+			}
+
+		default:
+			return nil, ErrSignatureVersion
+		}
+	}
+
+	return tx, nil
+}
+
+// Request holds the transaction object(json) to send.
+// e.g.,
+// {
+// 	"inputs": string[],
+// 	"outputs": {
+// 	   "address": string,
+// 	   "balances": {
+// 		   "value": number,
+// 		   "color": string
+// 	   }[];
+// 	 }[],
+// 	 "data": []byte,
+// 	 "signatures": {
+// 		"version": number,
+// 		"publicKey": string,
+// 		"signature": string
+// 	   }[]
+//  }
+type Request struct {
+	Inputs     []string    `json:"inputs"`
+	Outputs    []Output    `json:"outputs"`
+	Data       []byte      `json:"data,omitempty"`
+	Signatures []Signature `json:"signatures"`
+}
+
+// Output defines the struct of an output.
+type Output struct {
+	Address  string          `json:"address"`
+	Balances []utils.Balance `json:"balances"`
+}
+
+// Signature defines the struct of a signature.
+type Signature struct {
+	Version   byte   `json:"version"`
+	PublicKey string `json:"publicKey"`
+	Signature string `json:"signature"`
+}
+
+// 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/sendtransactionbyjson/transaction_test.go b/plugins/webapi/value/sendtransactionbyjson/transaction_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7ff143bd70aa9b5dbdc2ac54e7f573c6f6cd9b3a
--- /dev/null
+++ b/plugins/webapi/value/sendtransactionbyjson/transaction_test.go
@@ -0,0 +1,90 @@
+package sendtransactionbyjson
+
+import (
+	"testing"
+
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address/signaturescheme"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance"
+	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
+	"github.com/iotaledger/goshimmer/plugins/webapi/value/utils"
+	"github.com/iotaledger/hive.go/crypto/ed25519"
+	"github.com/mr-tron/base58/base58"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestNewTransactionFromJSON(t *testing.T) {
+	// generate ed25519 keypair
+	keyPair1 := ed25519.GenerateKeyPair()
+	sigScheme1 := signaturescheme.ED25519(keyPair1)
+	// generate BLS keypair
+	sigScheme2 := signaturescheme.RandBLS()
+	addr1 := sigScheme1.Address()
+	addr2 := sigScheme2.Address()
+	// create first input
+	o1 := transaction.NewOutputID(addr1, transaction.RandomID())
+	// create second input
+	o2 := transaction.NewOutputID(addr2, transaction.RandomID())
+	inputs := transaction.NewInputs(o1, o2)
+	bal := balance.New(balance.ColorIOTA, 1)
+	outputs := transaction.NewOutputs(map[address.Address][]*balance.Balance{address.Random(): {bal}})
+	tx := transaction.New(inputs, outputs)
+	tx.SetDataPayload([]byte("TEST"))
+	// sign with ed25519
+	tx.Sign(sigScheme1)
+	// sign with BLS
+	tx.Sign(sigScheme2)
+
+	// Parse inputs to base58
+	inputsBase58 := []string{}
+	inputs.ForEach(func(outputId transaction.OutputID) bool {
+		inputsBase58 = append(inputsBase58, base58.Encode(outputId.Bytes()))
+		return true
+	})
+
+	// Parse outputs to base58
+	outputsBase58 := []Output{}
+	outputs.ForEach(func(address address.Address, balances []*balance.Balance) bool {
+		var b []utils.Balance
+		for _, balance := range balances {
+			b = append(b, utils.Balance{
+				Value: balance.Value,
+				Color: balance.Color.String(),
+			})
+		}
+		t := Output{
+			Address:  address.String(),
+			Balances: b,
+		}
+		outputsBase58 = append(outputsBase58, t)
+
+		return true
+	})
+
+	// Parse signatures to base58
+	signaturesBase58 := []Signature{}
+	for _, signature := range tx.Signatures() {
+		signaturesBase58 = append(signaturesBase58, Signature{
+			Version:   signature.Bytes()[0],
+			PublicKey: base58.Encode(signature.Bytes()[1 : signature.PublicKeySize()+1]),
+			Signature: base58.Encode(signature.Bytes()[1+signature.PublicKeySize():]),
+		})
+	}
+
+	// create tx JSON
+	jsonRequest := Request{
+		Inputs:     inputsBase58,
+		Outputs:    outputsBase58,
+		Data:       []byte("TEST"),
+		Signatures: signaturesBase58,
+	}
+	txFromJSON, err := NewTransactionFromJSON(jsonRequest)
+	require.NoError(t, err)
+
+	// compare signatures
+	assert.Equal(t, tx.SignatureBytes(), txFromJSON.SignatureBytes())
+
+	// conmpare transactions
+	assert.Equal(t, tx, txFromJSON)
+}