diff --git a/bindings/fileTransfer.go b/bindings/fileTransfer.go
new file mode 100644
index 0000000000000000000000000000000000000000..9b8b1da61c12064bf2e5cbe4ff26bb7a0a99d792
--- /dev/null
+++ b/bindings/fileTransfer.go
@@ -0,0 +1,338 @@
+package bindings
+
+import (
+	"encoding/json"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/fileTransfer"
+	ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
+	"gitlab.com/xx_network/primitives/id"
+	"time"
+)
+
+/* File Transfer Structs and Interfaces */
+
+// FileTransfer object is a bindings-layer struct which wraps a fileTransfer.FileTransfer interface
+type FileTransfer struct {
+	ft    fileTransfer.FileTransfer
+	e2eCl *E2e
+}
+
+// ReceivedFile is a public struct which represents the contents of an incoming file
+// Example JSON:
+// {
+//  "TransferID":"B4Z9cwU18beRoGbk5xBjbcd5Ryi9ZUFA2UBvi8FOHWo=", // ID of the incoming transfer for receiving
+//  "SenderID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",   // ID of sender of incoming file
+//  "Preview":"aXQncyBtZSBhIHByZXZpZXc=",                        // Preview of the incoming file
+//  "Name":"testfile.txt",                                       // Name of incoming file
+//  "Type":"text file",                                          // Incoming file type
+//  "Size":2048                                                  // Incoming file size
+// }
+type ReceivedFile struct {
+	TransferID []byte
+	SenderID   []byte
+	Preview    []byte
+	Name       string
+	Type       string
+	Size       int
+}
+
+// FileSend is a public struct which represents a file to be transferred
+// {
+//  "Name":"testfile.txt",  														// File name
+//  "Type":"text file",     														// File type
+//  "Preview":"aXQncyBtZSBhIHByZXZpZXc=",  											// Preview of contents
+//  "Contents":"VGhpcyBpcyB0aGUgZnVsbCBjb250ZW50cyBvZiB0aGUgZmlsZSBpbiBieXRlcw==" 	// Full contents of the file
+// }
+type FileSend struct {
+	Name     string
+	Type     string
+	Preview  []byte
+	Contents []byte
+}
+
+// Progress is a public struct which represents the progress of an in-progress file transfer
+// Example JSON:
+// {"Completed":false,	// Status of transfer (true if done)
+//  "Transmitted":128,	// Bytes transferred so far
+//  "Total":2048,		// Total size of file
+//  "Err":null			// Error status (if any)
+// }
+type Progress struct {
+	Completed   bool
+	Transmitted int
+	Total       int
+	Err         error
+}
+
+// ReceiveFileCallback is a bindings-layer interface which is called when a file is received
+// Accepts the result of calling json.Marshal on a ReceivedFile struct
+type ReceiveFileCallback interface {
+	Callback(payload []byte, err error)
+}
+
+// FileTransferSentProgressCallback is a bindings-layer interface which is called with the progress of a sending file
+// Accepts the result of calling json.Marshal on a Progress struct & a FilePartTracker interface
+type FileTransferSentProgressCallback interface {
+	Callback(payload []byte, t *FilePartTracker, err error)
+}
+
+// FileTransferReceiveProgressCallback is a bindings-layer interface which is called with the progress of a received file
+// Accepts the result of calling json.Marshal on a Progress struct & a FilePartTracker interface
+type FileTransferReceiveProgressCallback interface {
+	Callback(payload []byte, t *FilePartTracker, err error)
+}
+
+/* Main functions */
+
+// InitFileTransfer creates a bindings-level File Transfer manager
+// Accepts e2e client ID and marshalled params JSON
+func InitFileTransfer(e2eID int, paramsJSON []byte) (*FileTransfer, error) {
+
+	// Get bindings client from singleton
+	e2eCl, err := e2eTrackerSingleton.get(e2eID)
+	if err != nil {
+		return nil, err
+	}
+
+	// Client info
+	myID := e2eCl.api.GetReceptionIdentity().ID
+	rng := e2eCl.api.GetRng()
+
+	params, err := parseFileTransferParams(paramsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	// Create file transfer manager
+	m, err := fileTransfer.NewManager(params, myID,
+		e2eCl.api.GetCmix(), e2eCl.api.GetStorage(), rng)
+
+	// Add file transfer processes to client services tracking
+	err = e2eCl.api.AddService(m.StartProcesses)
+	if err != nil {
+		return nil, err
+	}
+
+	// Return wrapped manager
+	return &FileTransfer{ft: m, e2eCl: e2eCl}, nil
+}
+
+// Send is the bindings-level function for sending a File
+// Accepts:
+//  FileSend JSON payload
+//  Marshalled recipient ID
+//  Marshalled e2e Params JSON
+//  Number of retries allowed
+//  Limit on duration between retries
+//  FileTransferSentProgressCallback interface
+func (f *FileTransfer) Send(payload, recipientID, paramsJSON []byte, retry float32,
+	period string, callback FileTransferSentProgressCallback) ([]byte, error) {
+	// Unmarshal recipient ID
+	recipient, err := id.Unmarshal(recipientID)
+	if err != nil {
+		return nil, err
+	}
+
+	// Parse duration to time.Duration
+	p, err := time.ParseDuration(period)
+
+	// Wrap transfer progress callback to be passed to fileTransfer layer
+	cb := func(completed bool, arrived, total uint16,
+		st fileTransfer.SentTransfer, t fileTransfer.FilePartTracker, err error) {
+		prog := &Progress{
+			Completed:   completed,
+			Transmitted: int(arrived),
+			Total:       int(total),
+			Err:         err,
+		}
+		pm, err := json.Marshal(prog)
+		callback.Callback(pm, &FilePartTracker{t}, err)
+	}
+
+	// Unmarshal payload
+	fs := &FileSend{}
+	err = json.Unmarshal(payload, fs)
+	if err != nil {
+		return nil, err
+	}
+
+	sendNew := func(transferInfo []byte) error {
+		resp, err := f.e2eCl.SendE2E(int(catalog.NewFileTransfer), recipientID, transferInfo, paramsJSON)
+		if err != nil {
+			return err
+		}
+		jww.INFO.Printf("New file transfer message sent: %s", resp)
+		return nil
+	}
+
+	// Send file
+	ftID, err := f.ft.Send(recipient, fs.Name, fs.Type, fs.Contents, retry, fs.Preview, cb, p, sendNew)
+	if err != nil {
+		return nil, err
+	}
+
+	// Return Transfer ID
+	return ftID.Bytes(), nil
+}
+
+// Receive returns the full file on the completion of the transfer.
+// It deletes internal references to the data and unregisters any attached
+// progress callback. Returns an error if the transfer is not complete, the
+// full file cannot be verified, or if the transfer cannot be found.
+//
+// Receive can only be called once the progress callback returns that the
+// file transfer is complete.
+func (f *FileTransfer) Receive(tidBytes []byte) ([]byte, error) {
+	tid := ftCrypto.UnmarshalTransferID(tidBytes)
+	return f.ft.Receive(&tid)
+}
+
+// CloseSend deletes a file from the internal storage once a transfer has
+// completed or reached the retry limit. Returns an error if the transfer
+// has not run out of retries.
+//
+// This function should be called once a transfer completes or errors out
+// (as reported by the progress callback).
+func (f *FileTransfer) CloseSend(tidBytes []byte) error {
+	tid := ftCrypto.UnmarshalTransferID(tidBytes)
+	return f.ft.CloseSend(&tid)
+}
+
+/* Callback registration functions */
+
+// RegisterSentProgressCallback allows for the registration of a callback to
+// track the progress of an individual sent file transfer.
+// SentProgressCallback is auto registered on Send; this function should be
+// called when resuming clients or registering extra callbacks.
+// Accepts ID of the transfer, callback for transfer progress,
+// and period between retries
+func (f *FileTransfer) RegisterSentProgressCallback(tidBytes []byte,
+	callback FileTransferSentProgressCallback, period string) error {
+	cb := func(completed bool, arrived, total uint16,
+		st fileTransfer.SentTransfer, t fileTransfer.FilePartTracker, err error) {
+		prog := &Progress{
+			Completed:   completed,
+			Transmitted: int(arrived),
+			Total:       int(total),
+			Err:         err,
+		}
+		pm, err := json.Marshal(prog)
+		callback.Callback(pm, &FilePartTracker{t}, err)
+	}
+	p, err := time.ParseDuration(period)
+	if err != nil {
+		return err
+	}
+	tid := ftCrypto.UnmarshalTransferID(tidBytes)
+
+	return f.ft.RegisterSentProgressCallback(&tid, cb, p)
+}
+
+// RegisterReceivedProgressCallback allows for the registration of a
+// callback to track the progress of an individual received file transfer.
+// This should be done when a new transfer is received on the
+// ReceiveCallback.
+// Accepts ID of the transfer, callback for transfer progress and period between retries
+func (f *FileTransfer) RegisterReceivedProgressCallback(tidBytes []byte, callback FileTransferReceiveProgressCallback, period string) error {
+	cb := func(completed bool, received, total uint16,
+		rt fileTransfer.ReceivedTransfer, t fileTransfer.FilePartTracker, err error) {
+		prog := &Progress{
+			Completed:   completed,
+			Transmitted: int(received),
+			Total:       int(total),
+			Err:         err,
+		}
+		pm, err := json.Marshal(prog)
+		callback.Callback(pm, &FilePartTracker{t}, err)
+	}
+	p, err := time.ParseDuration(period)
+	if err != nil {
+		return err
+	}
+	tid := ftCrypto.UnmarshalTransferID(tidBytes)
+	return f.ft.RegisterReceivedProgressCallback(&tid, cb, p)
+}
+
+/* Utility Functions */
+
+func (f *FileTransfer) MaxFileNameLen() int {
+	return f.ft.MaxFileNameLen()
+}
+
+func (f *FileTransfer) MaxFileTypeLen() int {
+	return f.ft.MaxFileTypeLen()
+}
+
+func (f *FileTransfer) MaxFileSize() int {
+	return f.ft.MaxFileSize()
+}
+
+func (f *FileTransfer) MaxPreviewSize() int {
+	return f.ft.MaxPreviewSize()
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// File Part Tracker                                                          //
+////////////////////////////////////////////////////////////////////////////////
+
+// FilePartTracker contains the interfaces.FilePartTracker.
+type FilePartTracker struct {
+	m fileTransfer.FilePartTracker
+}
+
+// GetPartStatus returns the status of the file part with the given part number.
+// The possible values for the status are:
+// 0 = unsent
+// 1 = sent (sender has sent a part, but it has not arrived)
+// 2 = arrived (sender has sent a part, and it has arrived)
+// 3 = received (receiver has received a part)
+func (fpt FilePartTracker) GetPartStatus(partNum int) int {
+	return int(fpt.m.GetPartStatus(uint16(partNum)))
+}
+
+// GetNumParts returns the total number of file parts in the transfer.
+func (fpt FilePartTracker) GetNumParts() int {
+	return int(fpt.m.GetNumParts())
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Event Reporter                                                             //
+////////////////////////////////////////////////////////////////////////////////
+
+// EventReport is a public struct which represents the contents of an event report
+// Example JSON:
+// {"Priority":1,
+//  "Category":"Test Events",
+//  "EventType":"Ping",
+//  "Details":"This is an example of an event report"
+// }
+type EventReport struct {
+	Priority  int
+	Category  string
+	EventType string
+	Details   string
+}
+
+// ReporterFunc is a bindings-layer interface which receives info from the Event Manager
+// Accepts result of json.Marshal on an EventReport object
+type ReporterFunc interface {
+	Report(payload []byte, err error)
+}
+
+// reporter is the internal struct to match the event.Reporter interface
+type reporter struct {
+	r ReporterFunc
+}
+
+// Report matches the event.Reporter interface, wraps the info in an EventReport struct
+// and passes the marshalled struct to the internal callback
+func (r *reporter) Report(priority int, category, evtType, details string) {
+	rep := &EventReport{
+		Priority:  priority,
+		Category:  category,
+		EventType: evtType,
+		Details:   details,
+	}
+	r.r.Report(json.Marshal(rep))
+}
diff --git a/bindings/fileTransfer_test.go b/bindings/fileTransfer_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a89967891505ea911384361924a746d9094260ff
--- /dev/null
+++ b/bindings/fileTransfer_test.go
@@ -0,0 +1,59 @@
+package bindings
+
+import (
+	"encoding/json"
+	"gitlab.com/elixxir/crypto/fileTransfer"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
+	"testing"
+)
+
+func TestFileTransfer_inputs(t *testing.T) {
+	fs := &FileSend{
+		Name:     "testfile.txt",
+		Type:     "text file",
+		Preview:  []byte("it's me a preview"),
+		Contents: []byte("This is the full contents of the file in bytes"),
+	}
+	fsm, _ := json.Marshal(fs)
+	t.Log("FileSend example json:")
+	t.Log(string(fsm))
+	t.Log("\n")
+
+	tid, _ := fileTransfer.NewTransferID(csprng.NewSystemRNG())
+	sid := id.NewIdFromString("zezima", id.User, t)
+	rf := &ReceivedFile{
+		TransferID: tid.Bytes(),
+		SenderID:   sid.Marshal(),
+		Preview:    []byte("it's me a preview"),
+		Name:       "testfile.txt",
+		Type:       "text file",
+		Size:       2048,
+	}
+	rfm, _ := json.Marshal(rf)
+	t.Log("ReceivedFile example json:")
+	t.Log(string(rfm))
+	t.Log("\n")
+
+	p := &Progress{
+		Completed:   false,
+		Transmitted: 128,
+		Total:       2048,
+		Err:         nil,
+	}
+	pm, _ := json.Marshal(p)
+	t.Log("Progress example json:")
+	t.Log(string(pm))
+	t.Log("\n")
+
+	er := &EventReport{
+		Priority:  1,
+		Category:  "Test Events",
+		EventType: "Ping",
+		Details:   "This is an example of an event report",
+	}
+	erm, _ := json.Marshal(er)
+	t.Log("EventReport example json:")
+	t.Log(string(erm))
+	t.Log("\n")
+}
diff --git a/bindings/params.go b/bindings/params.go
index 860c1fbcd1077201c2d285d84af37881fe54e8eb..cc7883b30c673f6166eca4a1d865481a24554fe0 100644
--- a/bindings/params.go
+++ b/bindings/params.go
@@ -11,6 +11,8 @@ package bindings
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/fileTransfer"
+	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/xxdk"
 )
 
@@ -38,6 +40,40 @@ func GetDefaultE2EParams() []byte {
 	return data
 }
 
+// GetDefaultFileTransferParams returns a JSON serialized object with all the
+// File transfer parameters and their default values. Call this function and modify
+// the json to change file transfer settings.
+func GetDefaultFileTransferParams() []byte {
+	defaultParams := fileTransfer.DefaultParams()
+	data, err := defaultParams.MarshalJSON()
+	if err != nil {
+		jww.FATAL.Panicf("Unexpected error: %+v", err)
+	}
+	return data
+}
+
+// GetDefaultSingleUseParams returns a JSON serialized object with all the
+// single use parameters and their default values. Call this function and modify
+// the json to change single use settings.
+func GetDefaultSingleUseParams() []byte {
+	defaultParams := single.GetDefaultRequestParams()
+	data, err := defaultParams.MarshalJSON()
+	if err != nil {
+		jww.FATAL.Panicf("Unexpected error: %+v", err)
+	}
+	return data
+}
+
+func parseSingleUseParams(data []byte) (single.RequestParams, error) {
+	p := &single.RequestParams{}
+	return *p, p.UnmarshalJSON(data)
+}
+
+func parseFileTransferParams(data []byte) (fileTransfer.Params, error) {
+	p := &fileTransfer.Params{}
+	return *p, p.UnmarshalJSON(data)
+}
+
 func parseCMixParams(data []byte) (xxdk.CMIXParams, error) {
 	p := &xxdk.CMIXParams{}
 	err := p.Unmarshal(data)
diff --git a/bindings/restlike.go b/bindings/restlike.go
index be0bd004f7bce59111e3c347ceecb7b5eab5bfcf..4884098085771853832a9104bf0715975f06db72 100644
--- a/bindings/restlike.go
+++ b/bindings/restlike.go
@@ -8,7 +8,6 @@ package bindings
 
 import (
 	"encoding/json"
-
 	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/client/restlike"
 	"gitlab.com/elixxir/client/restlike/connect"
@@ -34,7 +33,7 @@ type RestlikeMessage struct {
 // RestlikeRequest performs a normal restlike request
 // request - marshalled RestlikeMessage
 // Returns marshalled result RestlikeMessage
-func RestlikeRequest(clientID int, connectionID int, request []byte) ([]byte, error) {
+func RestlikeRequest(clientID, connectionID int, request []byte) ([]byte, error) {
 	paramsJSON := GetDefaultE2EParams()
 
 	cl, err := cmixTrackerSingleton.get(clientID)
diff --git a/bindings/restlikeSingle.go b/bindings/restlikeSingle.go
new file mode 100644
index 0000000000000000000000000000000000000000..eb7d34beeb115d531015b4c06e026fe96b0e5d02
--- /dev/null
+++ b/bindings/restlikeSingle.go
@@ -0,0 +1,92 @@
+package bindings
+
+import (
+	"encoding/json"
+	"gitlab.com/elixxir/client/restlike"
+	"gitlab.com/elixxir/client/restlike/single"
+	"gitlab.com/elixxir/crypto/contact"
+)
+
+// RestlikeCallback is the public function type bindings can use to make an asynchronous restlike request
+// It accepts a json marshalled restlike.Message and an error (the results of calling json.Marshal on the message)
+type RestlikeCallback interface {
+	Callback([]byte, error)
+}
+
+// RequestRestLike sends a restlike request to a given contact
+// Accepts marshalled contact object as recipient, marshalled RestlikeMessage and params JSON
+// Returns json marshalled restlike.Message & error
+func RequestRestLike(e2eID int, recipient, request, paramsJSON []byte) ([]byte, error) {
+	c, err := e2eTrackerSingleton.get(e2eID)
+	if err != nil {
+		return nil, err
+	}
+	req := single.Request{
+		Net:    c.api.GetCmix(),
+		Rng:    c.api.GetRng().GetStream(),
+		E2eGrp: c.api.GetStorage().GetE2EGroup(),
+	}
+
+	message := &RestlikeMessage{}
+	err = json.Unmarshal(request, message)
+
+	recipientContact, err := contact.Unmarshal(recipient)
+	if err != nil {
+		return nil, err
+	}
+
+	params, err := parseSingleUseParams(paramsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := req.Request(recipientContact, restlike.Method(message.Method), restlike.URI(message.URI),
+		message.Content, &restlike.Headers{
+			Headers: message.Headers,
+			Version: 0,
+		}, params)
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(resp)
+}
+
+// AsyncRequestRestLike sends an asynchronous restlike request to a given contact
+// Accepts e2e client ID, marshalled contact object as recipient,
+// marshalled RestlikeMessage, marshalled Params json, and a RestlikeCallback
+// Returns an error, and the RestlikeCallback will be called with the results
+// of json marshalling the response when received
+func AsyncRequestRestLike(e2eID int, recipient, request, paramsJSON []byte, cb RestlikeCallback) error {
+	c, err := e2eTrackerSingleton.get(e2eID)
+	if err != nil {
+		return err
+	}
+	req := single.Request{
+		Net:    c.api.GetCmix(),
+		Rng:    c.api.GetRng().GetStream(),
+		E2eGrp: c.api.GetStorage().GetE2EGroup(),
+	}
+
+	message := &RestlikeMessage{}
+	err = json.Unmarshal(request, message)
+
+	recipientContact, err := contact.Unmarshal(recipient)
+	if err != nil {
+		return err
+	}
+
+	rlcb := func(message *restlike.Message) {
+		cb.Callback(json.Marshal(message))
+	}
+
+	params, err := parseSingleUseParams(paramsJSON)
+	if err != nil {
+		return err
+	}
+
+	return req.AsyncRequest(recipientContact, restlike.Method(message.Method), restlike.URI(message.URI),
+		message.Content, &restlike.Headers{
+			Headers: message.Headers,
+			Version: 0,
+		}, rlcb, params)
+}
diff --git a/bindings/single.go b/bindings/single.go
new file mode 100644
index 0000000000000000000000000000000000000000..048edda8aa7b56fa9122740c1791986a05e2bb9f
--- /dev/null
+++ b/bindings/single.go
@@ -0,0 +1,180 @@
+package bindings
+
+import (
+	"encoding/json"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/single"
+	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+/* PUBLIC WRAPPER METHODS */
+
+// TransmitSingleUse accepts a marshalled recipient contact object, tag, payload, params JSON, SingleUseResponse callback func & a
+// Client.  Transmits payload to recipient via single use
+func TransmitSingleUse(e2eID int, recipient []byte, tag string, payload, paramsJSON []byte, responseCB SingleUseResponse) ([]byte, error) {
+	e2eCl, err := e2eTrackerSingleton.get(e2eID)
+	if err != nil {
+		return nil, err
+	}
+
+	recipientContact, err := contact.Unmarshal(recipient)
+	if err != nil {
+		return nil, err
+	}
+
+	rcb := &singleUseResponse{response: responseCB}
+
+	params, err := parseSingleUseParams(paramsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	rids, eid, err := single.TransmitRequest(recipientContact, tag, payload, rcb, params, e2eCl.api.GetCmix(), e2eCl.api.GetRng().GetStream(), e2eCl.api.GetStorage().GetE2EGroup())
+
+	if err != nil {
+		return nil, err
+	}
+	sr := SingleUseSendReport{
+		EphID:       eid.EphId.Int64(),
+		ReceptionID: eid.Source.Marshal(),
+		RoundsList:  makeRoundsList(rids),
+	}
+	return json.Marshal(sr)
+}
+
+// Listen starts a single use listener on a given tag using the passed in client and SingleUseCallback func
+func Listen(e2eID int, tag string, cb SingleUseCallback) (StopFunc, error) {
+	e2eCl, err := e2eTrackerSingleton.get(e2eID)
+	if err != nil {
+		return nil, err
+	}
+
+	listener := singleUseListener{scb: cb}
+	dhpk, err := e2eCl.api.GetReceptionIdentity().GetDHKeyPrivate()
+	if err != nil {
+		return nil, err
+	}
+	l := single.Listen(tag, e2eCl.api.GetReceptionIdentity().ID, dhpk, e2eCl.api.GetCmix(), e2eCl.api.GetStorage().GetE2EGroup(), listener)
+	return l.Stop, nil
+}
+
+// JSON Types
+
+// SingleUseSendReport is the bindings struct used to represent information returned by single.TransmitRequest
+//
+// Example json marshalled struct:
+// {"Rounds":[1,5,9],
+//  "EphID":{"EphId":[0,0,0,0,0,0,3,89],
+//  "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}}
+type SingleUseSendReport struct {
+	RoundsList
+	ReceptionID []byte
+	EphID       int64
+}
+
+// SingleUseResponseReport is the bindings struct used to represent information passed
+// to the single.Response callback interface in response to single.TransmitRequest
+//
+// Example json marshalled struct:
+// {"Rounds":[1,5,9],
+//  "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==",
+//  "ReceptionID":{"EphId":[0,0,0,0,0,0,3,89],
+//  "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"},
+//  "Err":null}
+type SingleUseResponseReport struct {
+	RoundsList
+	Payload     []byte
+	ReceptionID []byte
+	EphID       int64
+	Err         error
+}
+
+// SingleUseCallbackReport is the bindings struct used to represent single use messages
+// received by a callback passed into single.Listen
+//
+// Example json marshalled struct:
+// {"Rounds":[1,5,9],
+//  "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==",
+//  "Partner":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+//  "EphID":{"EphId":[0,0,0,0,0,0,3,89],
+//  "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}}
+type SingleUseCallbackReport struct {
+	RoundsList
+	Payload     []byte
+	Partner     *id.ID
+	EphID       int64
+	ReceptionID []byte
+}
+
+// Function types
+
+// StopFunc is the function to stop a listener returned to the bindings layer when one is started
+type StopFunc func()
+
+// SingleUseCallback func is passed into Listen and called when messages are received
+// Accepts a SingleUseCallbackReport marshalled to json
+type SingleUseCallback interface {
+	Callback(callbackReport []byte, err error)
+}
+
+// SingleUseResponse is the public facing callback func passed by bindings clients into TransmitSingleUse
+// Accepts a SingleUseResponseReport marshalled to json
+type SingleUseResponse interface {
+	Callback(responseReport []byte, err error)
+}
+
+/* CALLBACK WRAPPERS */
+
+/* listener struct */
+
+// singleUseListener is the internal struct used to wrap a SingleUseCallback func,
+// which matches the single.Receiver interface
+type singleUseListener struct {
+	scb SingleUseCallback
+}
+
+// Callback is called whenever a single use message is heard by the listener, and translates the info to
+//a SingleUseCallbackReport which is marshalled & passed to bindings
+func (sl singleUseListener) Callback(req *single.Request, eid receptionID.EphemeralIdentity, rl []rounds.Round) {
+	var rids []id.Round
+	for _, r := range rl {
+		rids = append(rids, r.ID)
+	}
+
+	// Todo: what other info from req needs to get to bindings
+	scr := SingleUseCallbackReport{
+		Payload:     req.GetPayload(),
+		RoundsList:  makeRoundsList(rids),
+		Partner:     req.GetPartner(),
+		EphID:       eid.EphId.Int64(),
+		ReceptionID: eid.Source.Marshal(),
+	}
+
+	sl.scb.Callback(json.Marshal(scr))
+}
+
+/* response struct */
+
+// singleUseResponse is the private struct backing SingleUseResponse, which subscribes to the single.Response interface
+type singleUseResponse struct {
+	response SingleUseResponse
+}
+
+// Callback builds a SingleUseSendReport & passes the json marshalled version into the callback
+func (sr singleUseResponse) Callback(payload []byte, receptionID receptionID.EphemeralIdentity,
+	rounds []rounds.Round, err error) {
+	var rids []id.Round
+	for _, r := range rounds {
+		rids = append(rids, r.ID)
+	}
+	sendReport := SingleUseResponseReport{
+		RoundsList:  makeRoundsList(rids),
+		ReceptionID: receptionID.Source.Marshal(),
+		EphID:       receptionID.EphId.Int64(),
+		Payload:     payload,
+		Err:         err,
+	}
+	sr.response.Callback(json.Marshal(&sendReport))
+}
diff --git a/bindings/single_test.go b/bindings/single_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..807abe161b998bb259a5c9b757368746850e97bf
--- /dev/null
+++ b/bindings/single_test.go
@@ -0,0 +1,67 @@
+package bindings
+
+import (
+	"encoding/json"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"testing"
+	"time"
+)
+
+func TestSingleUseJsonMarshals(t *testing.T) {
+	rids := []id.Round{1, 5, 9}
+	rl := makeRoundsList(rids)
+	rid := id.NewIdFromString("zezima", id.User, t)
+	eid, _, _, err := ephemeral.GetId(rid, 16, time.Now().UnixNano())
+	if err != nil {
+		t.Fatalf("Failed to generate ephemeral id: %+v", err)
+	}
+	ephId := receptionID.EphemeralIdentity{
+		EphId:  eid,
+		Source: rid,
+	}
+	payload := make([]byte, 64)
+	rng := csprng.NewSystemRNG()
+	rng.Read(payload)
+	sendReport := SingleUseSendReport{
+		RoundsList:  rl,
+		EphID:       ephId.EphId.Int64(),
+		ReceptionID: ephId.Source.Marshal(),
+	}
+	srm, err := json.Marshal(sendReport)
+	if err != nil {
+		t.Errorf("Failed to marshal send report to JSON: %+v", err)
+	} else {
+		t.Logf("Marshalled send report:\n%s\n", string(srm))
+	}
+
+	responseReport := SingleUseResponseReport{
+		RoundsList:  rl,
+		Payload:     payload,
+		ReceptionID: ephId.Source.Marshal(),
+		EphID:       ephId.EphId.Int64(),
+		Err:         nil,
+	}
+	rrm, err := json.Marshal(responseReport)
+	if err != nil {
+		t.Errorf("Failed to marshal response report to JSON: %+v", err)
+	} else {
+		t.Logf("Marshalled response report:\n%s\n", string(rrm))
+	}
+
+	callbackReport := SingleUseCallbackReport{
+		RoundsList:  rl,
+		Payload:     payload,
+		Partner:     rid,
+		EphID:       ephId.EphId.Int64(),
+		ReceptionID: ephId.Source.Marshal(),
+	}
+	crm, err := json.Marshal(callbackReport)
+	if err != nil {
+		t.Errorf("Failed to marshal callback report to JSON: %+v", err)
+	} else {
+		t.Logf("Marshalled callback report:\n%s\n", string(crm))
+	}
+}