diff --git a/bindings/broadcast.go b/bindings/broadcast.go
new file mode 100644
index 0000000000000000000000000000000000000000..d2773904333e46902c85166f66ec5a05a4e3ee91
--- /dev/null
+++ b/bindings/broadcast.go
@@ -0,0 +1,185 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"encoding/json"
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/broadcast"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	"gitlab.com/xx_network/crypto/signature/rsa"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+)
+
+// Channel is a bindings-level struct encapsulating the broadcast.Channel client object.
+type Channel struct {
+	ch broadcast.Channel
+}
+
+// ChannelDef is the bindings representation of an elixxir/crypto broadcast.Channel object.
+//
+// Example JSON:
+//  {"Name": "My broadcast channel",
+//   "Description":"A broadcast channel for me to test things",
+//   "Salt":"gpUqW7N22sffMXsvPLE7BA==",
+//   "PubKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1DZ0NJUUN2YkZVckJKRFpqT3Y0Y0MvUHZZdXNvQkFtUTFkb3Znb044aHRuUjA2T3F3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0="
+//  }
+type ChannelDef struct {
+	Name        string
+	Description string
+	Salt        []byte
+	PubKey      []byte
+}
+
+// BroadcastMessage is the bindings representation of a broadcast message.
+//
+// Example JSON:
+//  {"RoundID":42,
+//   "EphID":[0,0,0,0,0,0,24,61],
+//   "Payload":"SGVsbG8sIGJyb2FkY2FzdCBmcmllbmRzIQ=="
+//  }
+type BroadcastMessage struct {
+	BroadcastReport
+	Payload []byte
+}
+
+// BroadcastReport is the bindings representation of the info on how a broadcast message was sent
+//
+// Example JSON:
+//  {"RoundID":42,
+//   "EphID":[0,0,0,0,0,0,24,61]
+//  }
+type BroadcastReport struct {
+	RoundID int
+	EphID   ephemeral.Id
+}
+
+// BroadcastListener is the public function type bindings can use to listen for broadcast messages.
+// It accepts the result of calling json.Marshal on a BroadcastMessage object.
+type BroadcastListener interface {
+	Callback([]byte, error)
+}
+
+// NewBroadcastChannel creates a bindings-layer broadcast channel & starts listening for new messages
+//
+// Params
+//  - cmixId - internal ID of cmix
+//  - channelDefinition - JSON marshalled ChannelDef object
+func NewBroadcastChannel(cmixId int, channelDefinition []byte) (*Channel, error) {
+	c, err := cmixTrackerSingleton.get(cmixId)
+	if err != nil {
+		return nil, err
+	}
+
+	def := &ChannelDef{}
+	err = json.Unmarshal(channelDefinition, def)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to unmarshal underlying channel definition")
+	}
+
+	channelID, err := cryptoBroadcast.NewChannelID(def.Name, def.Description, def.Salt, def.PubKey)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to generate channel ID")
+	}
+	chanPubLoaded, err := rsa.LoadPublicKeyFromPem(def.PubKey)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to load public key")
+	}
+
+	ch, err := broadcast.NewBroadcastChannel(cryptoBroadcast.Channel{
+		ReceptionID: channelID,
+		Name:        def.Name,
+		Description: def.Description,
+		Salt:        def.Salt,
+		RsaPubKey:   chanPubLoaded,
+	}, c.api.GetCmix(), c.api.GetRng())
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to create broadcast channel client")
+	}
+
+	return &Channel{ch: ch}, nil
+}
+
+// Listen registers a BroadcastListener for a given method.
+// This allows users to handle incoming broadcast messages.
+//
+// Params:
+//  - l - BroadcastListener object
+//  - method - int corresponding to broadcast.Method constant, 0 for symmetric or 1 for asymmetric
+func (c *Channel) Listen(l BroadcastListener, method int) error {
+	broadcastMethod := broadcast.Method(method)
+	listen := func(payload []byte,
+		receptionID receptionID.EphemeralIdentity, round rounds.Round) {
+		l.Callback(json.Marshal(&BroadcastMessage{
+			BroadcastReport: BroadcastReport{
+				RoundID: int(round.ID),
+				EphID:   receptionID.EphId,
+			},
+			Payload: payload,
+		}))
+	}
+	return c.ch.RegisterListener(listen, broadcastMethod)
+}
+
+// Broadcast sends a given payload over the broadcast channel using symmetric broadcast.
+func (c *Channel) Broadcast(payload []byte) ([]byte, error) {
+	rid, eid, err := c.ch.Broadcast(payload, cmix.GetDefaultCMIXParams())
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(BroadcastReport{
+		RoundID: int(rid),
+		EphID:   eid,
+	})
+}
+
+// BroadcastAsymmetric sends a given payload over the broadcast channel using asymmetric broadcast.
+// This mode of encryption requires a private key.
+func (c *Channel) BroadcastAsymmetric(payload, pk []byte) ([]byte, error) {
+	pkLoaded, err := rsa.LoadPrivateKeyFromPem(pk)
+	if err != nil {
+		return nil, err
+	}
+	rid, eid, err := c.ch.BroadcastAsymmetric(pkLoaded, payload, cmix.GetDefaultCMIXParams())
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(BroadcastReport{
+		RoundID: int(rid),
+		EphID:   eid,
+	})
+}
+
+// MaxPayloadSize returns the maximum possible payload size which can be broadcast.
+func (c *Channel) MaxPayloadSize() int {
+	return c.ch.MaxPayloadSize()
+}
+
+// MaxAsymmetricPayloadSize returns the maximum possible payload size which can be broadcast.
+func (c *Channel) MaxAsymmetricPayloadSize() int {
+	return c.ch.MaxAsymmetricPayloadSize()
+}
+
+// Get returns the result of calling json.Marshal on a ChannelDef based on the underlying crypto broadcast.Channel.
+func (c *Channel) Get() ([]byte, error) {
+	def := c.ch.Get()
+	return json.Marshal(&ChannelDef{
+		Name:        def.Name,
+		Description: def.Description,
+		Salt:        def.Salt,
+		PubKey:      rsa.CreatePublicKeyPem(def.RsaPubKey),
+	})
+}
+
+// Stop stops the channel from listening for more messages.
+func (c *Channel) Stop() {
+	c.ch.Stop()
+}
diff --git a/bindings/broadcast_test.go b/bindings/broadcast_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..48fa0bed595de2664f5b5f011d129ed53c3a97e6
--- /dev/null
+++ b/bindings/broadcast_test.go
@@ -0,0 +1,68 @@
+package bindings
+
+import (
+	"encoding/json"
+	"gitlab.com/elixxir/crypto/cmix"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/crypto/signature/rsa"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"testing"
+	"time"
+)
+
+func TestChannelDef_JSON(t *testing.T) {
+	rng := csprng.NewSystemRNG()
+	rng.SetSeed([]byte("rng"))
+	pk, _ := rsa.GenerateKey(rng, 256)
+	cd := ChannelDef{
+		Name:        "My broadcast channel",
+		Description: "A broadcast channel for me to test things",
+		Salt:        cmix.NewSalt(rng, 16),
+		PubKey:      rsa.CreatePublicKeyPem(pk.GetPublic()),
+	}
+
+	cdJson, err := json.Marshal(cd)
+	if err != nil {
+		t.Errorf("Failed to marshal channel def: %+v", err)
+	}
+	t.Log(string(cdJson))
+}
+
+func TestBroadcastMessage_JSON(t *testing.T) {
+	uid := id.NewIdFromString("zezima", id.User, t)
+	eid, _, _, err := ephemeral.GetId(uid, 16, time.Now().UnixNano())
+	if err != nil {
+		t.Errorf("Failed to form ephemeral ID: %+v", err)
+	}
+	bm := BroadcastMessage{
+		BroadcastReport: BroadcastReport{
+			RoundID: 42,
+			EphID:   eid,
+		},
+		Payload: []byte("Hello, broadcast friends!"),
+	}
+	bmJson, err := json.Marshal(bm)
+	if err != nil {
+		t.Errorf("Failed to marshal broadcast message: %+v", err)
+	}
+	t.Log(string(bmJson))
+}
+
+func TestBroadcastReport_JSON(t *testing.T) {
+	uid := id.NewIdFromString("zezima", id.User, t)
+	eid, _, _, err := ephemeral.GetId(uid, 16, time.Now().UnixNano())
+	if err != nil {
+		t.Errorf("Failed to form ephemeral ID: %+v", err)
+	}
+	br := BroadcastReport{
+		RoundID: 42,
+		EphID:   eid,
+	}
+
+	brJson, err := json.Marshal(br)
+	if err != nil {
+		t.Errorf("Failed to marshal broadcast report: %+v", err)
+	}
+	t.Log(string(brJson))
+}
diff --git a/broadcast/asymmetric.go b/broadcast/asymmetric.go
index 8fab1b5a24dad08ade68a369857f2dca06795c1e..2b263cad705cadcfd0f9fb5a819a1c019cb8bb4b 100644
--- a/broadcast/asymmetric.go
+++ b/broadcast/asymmetric.go
@@ -23,11 +23,6 @@ const (
 	internalPayloadSizeLength     = 2
 )
 
-// MaxAsymmetricPayloadSize returns the maximum size for an asymmetric broadcast payload
-func (bc *broadcastClient) maxAsymmetricPayload() int {
-	return bc.maxParts() * bc.channel.MaxAsymmetricPayloadSize()
-}
-
 // BroadcastAsymmetric broadcasts the payload to the channel. Requires a healthy network state to send
 // Payload must be equal to bc.MaxAsymmetricPayloadSize, and the channel PrivateKey must be passed in
 func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) (
@@ -40,7 +35,7 @@ func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, paylo
 	// Check payload size
 	if len(payload) > bc.MaxAsymmetricPayloadSize() {
 		return 0, ephemeral.Id{},
-			errors.Errorf(errPayloadSize, len(payload), bc.maxAsymmetricPayload())
+			errors.Errorf(errPayloadSize, len(payload), bc.MaxAsymmetricPayloadSize())
 	}
 	payloadLength := uint16(len(payload))
 
@@ -54,7 +49,8 @@ func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, paylo
 		return 0, ephemeral.Id{}, errors.WithMessage(err, "Failed to encrypt asymmetric broadcast message")
 	}
 
-	// Create service object to send message
+	// Create service using asymmetric broadcast service tag & channel reception ID
+	// Allows anybody with this info to listen for messages on this channel
 	service := message.Service{
 		Identifier: bc.channel.ReceptionID.Bytes(),
 		Tag:        asymmetricBroadcastServiceTag,
@@ -76,10 +72,3 @@ func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, paylo
 	return bc.net.Send(
 		bc.channel.ReceptionID, fp, service, sizedPayload, mac, cMixParams)
 }
-
-// Helper function for maximum number of encrypted message parts
-func (bc *broadcastClient) maxParts() int {
-	encPartSize := bc.channel.RsaPubKey.Size()
-	maxSend := bc.net.GetMaxMessageLength()
-	return maxSend / encPartSize
-}
diff --git a/broadcast/interface.go b/broadcast/interface.go
index badfc8bc7e4009c59753d2fd39bf55b5d5043cad..bd464945549ba67b4800dcef5c1f4f9d339d061d 100644
--- a/broadcast/interface.go
+++ b/broadcast/interface.go
@@ -25,6 +25,7 @@ import (
 type ListenerFunc func(payload []byte,
 	receptionID receptionID.EphemeralIdentity, round rounds.Round)
 
+// Channel is the public-facing interface to interact with broadcast channels
 type Channel interface {
 	// MaxPayloadSize returns the maximum size for a symmetric broadcast payload
 	MaxPayloadSize() int
@@ -45,6 +46,7 @@ type Channel interface {
 	BroadcastAsymmetric(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) (
 		id.Round, ephemeral.Id, error)
 
+	// RegisterListener registers a listener for broadcast messages
 	RegisterListener(listenerCb ListenerFunc, method Method) error
 
 	// Stop unregisters the listener callback and stops the channel's identity
diff --git a/broadcast/symmetric.go b/broadcast/symmetric.go
index e9b96f75c845dc0da8d91f87235d2e011db1cf2c..601c2bebec39f7c00c1e389a9f2d0d8ccc5122f3 100644
--- a/broadcast/symmetric.go
+++ b/broadcast/symmetric.go
@@ -53,7 +53,8 @@ func (bc *broadcastClient) Broadcast(payload []byte, cMixParams cmix.CMIXParams)
 	encryptedPayload, mac, fp := bc.channel.EncryptSymmetric(payload, rng)
 	rng.Close()
 
-	// Create service
+	// Create service using symmetric broadcast service tag & channel reception ID
+	// Allows anybody with this info to listen for messages on this channel
 	service := message.Service{
 		Identifier: bc.channel.ReceptionID.Bytes(),
 		Tag:        symmetricBroadcastServiceTag,