Moxtra Bot SDK

Moxtra's Bot SDK is to ease the Bot development for Moxtra's business collaboration platform. Once you complete the Bot App creation, others can install your Bot via Install a Bot.

Below diagram depicts the Bot App flow:

SDK

Currently, there are three SDKs you can clone from github:

Receive Messages

Bot would receive event messages while an event gets triggered. A sample outgoing comment event message looks like below:

{
    "message_id": "2889",
    "message_type": "comment_posted",
    "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
    "bot_id": "WILSbZF770SDZIk7DqJX5I0",
    "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
    "event": {
	"timestamp": "2017-04-25T23:17:10Z",
	"user": {
	    "id": "Utkj3YC5BxRHCCaq9widP67",
	    "name": "Joe Smith"
	},
	"comment": {
	    "id": "2888",
	    "text": "what is a bot?",
	    "audio": null
	},
	"target": {
	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
	    "object_type": "binder"
	}
    }
}


The request will not wait for the return value from the Bot. It is the Bot that has to make a request back on the REST API endpoint using the obtained "access_token". Depending on the event type, different message format gets generated as shown below:

{
     "message_id": "2889",
     "message_type": "bot_installed",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"bot": {
 	    "id": "W11o5lSYbxEAvALFXYBd7pH",
 	    "name": "Test Bot"
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "bot_uninstalled",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": null,
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"bot": {
 	    "id": "W11o5lSYbxEAvALFXYBd7pH"
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "comment_posted",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"comment": {
 	    "id": "2888",
 	    "text": "what is a bot?",
 	    "audio": null
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "comment_posted_on_page",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"comment": {
 	    "id": "2888",
 	    "text": "what is a bot?",
 	    "audio": null
 	},
 	"target": {
 	    "id": "2772",
 	    "object_type": "page"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "file_uploaded",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"file": {
 	    "id": "2888",
 	    "name": "foreground.png",
 	    "mimeType": "image/png"
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "meet_recording_ready",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"meet": {
 	    "id": "777652546",
 	    "topic": "Joe's Meet",
 	    "recording_url": null,
 	    "start_time": "2016-04-26T01:26:56Z",
 	    "end_time": "2016-04-26T01:27:56Z"
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "page_created",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"page": {
 	    "id": "2917",
 	    "type": "PAGE_TYPE_WHITEBOARD"
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "page_annotated",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"annotate": {
 	    "id": "2909"
 	},
 	"target": {
 	    "id": "2772",
 	    "object_type": "page"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "todo_created",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"todo": {
 	    "id": "2925",
 	    "name": "New project planning"
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}
{
     "message_id": "2889",
     "message_type": "todo_completed",
     "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
     "bot_id": "WILSbZF770SDZIk7DqJX5I0",
     "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
     "event": {
 	"timestamp": "2017-04-25T23:17:10Z",
 	"user": {
 	    "id": "Utkj3YC5BxRHCCaq9widP67",
 	    "name": "Joe Smith"
 	},
 	"todo": {
 	    "id": "2925",
 	    "name": "New project planning"
 	},
 	"target": {
 	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
 	    "object_type": "binder"
 	}
     }
}

Post Message to Binder

Bot uses the access_token obtained from each event message to post a message back to the same binder as originated event using the user authentication scheme as REST API.

POST /messages

Bot sends the message to the REST API endpoint URL using POST method with Content-Type: application/json with the following format:

{ 
    "message": {
	"text": "simple text message",
	"richtext": "text message in BBCode style",
	"fields": {  
	    "key1": "value1",
	    "key2": "value2",
	    ...
	},
	"action": "chat", "page", or "todo",
	"buttons": [  	
	    {
	    	"type": "account_link",
	    	"text": "TEXT"
	    },	
	    {
	    	"type": "postback",
	    	"text": "TEXT",
	    	"payload": "PAYLOAD"	    	
	    }
	]
    },
    "fields_template": [    
	{	
	    "template_type": "text", "richtext", or "page",
	    "template": "Template For Fields"
	},
	...
    ] 
  }

JSON Parameters
Name Type Description
text (in message) String Plain text message.
richtext (in message) String Text message in BBCode style.
fields (in message) JSON Key-value pairs in JSON.
action (in message) String Optional: on-demand target action for "chat", "page", or "todo".
buttons (in message) Array Buttons array.
type (in buttons array) String "account_link" or "postback".
text (in buttons array) String Text for the button.
payload (in buttons array) JSON or String Optional: payload for "postback" button.
template_type (in fields_template) String Optional for fields: on-demand template for "text", "richtext", or "page".
template (in fields_template) String Optional for fields: template for rendering key-value pairs.

Sample Request
POST /messages
{
    "message": {
    	"text": "@Anu Test LN do you need to schedule a meet?",
    	"buttons": [{
	    "type": "account_link",
	    "text": "Sign In"
	}, {
	    "type": "postback",
	    "text": "Not Sure?",
	    "payload": "MOXTRABOT_NOT SURE?"
	}]    
    }
}

Sample Request with RichText
POST /messages
{
    "message": {
	"richtext": "[table][tr][th][center]BBCode Info[/center][/th][/tr][tr][td][img=50x25]https://www.bbcode.org/images/lubeck_small.jpg[/img][/td][/tr][tr][td]From: [i]Anu Test LN[/i][/td][/tr][tr][td][color=Red]yes[/color][/td][/tr][/table]"
    }
}

  • Upload file and add audio comment with Content-Type: multipart/form-data and set parameters as follows:

    • payload - Optional the JSON message as before-mentioned

    • file - Optional the file that is getting uploaded into the binder, for example

      ...
      Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266
      Content-Length: 3234
      
      -----------------------------9051914041544843365972754266
      Content-Disposition: form-data; name="file"; filename="start.png"
      Content-Type: image/png
      
      Content of start.png
      
    • audio - Optional the audio file (audio/x-m4a, audio/3gpp) for audio comment that is getting uploaded into the binder, for example

      ...
      Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266
      Content-Length: 4568
      
      -----------------------------9051914041544843365972754266
      Content-Disposition: form-data; name="audio"; filename="test_comment.3gpp"
      Content-Type: audio/3gpp
      
      Content of test_comment.3gpp
      

Buttons

Two types of buttons you can put in the response message:

  • postback - a button contains "text" and "payload", which can be a JSON object or a string. Once the button gets tapped, a "postback" event postes to the Bot. The sample message is shown below:

    {
        "message_id": "1124",
        "message_type": "bot_postback",
        "binder_id": "BAGUChIRH7P7eBdR9h9nyR5",
        "access_token": "PAEqBS8wcXkzehdCQUdVQ2hJUkg3UDdlQmRSOWg5bnlSNYABvBaQAxQ",
        "event": {
    	"timestamp": "2017-04-25T23:17:10Z",
    	"user": {
    	    "id": "Utkj3YC5BxRHCCaq9widP67",
    	    "name": "Joe Smith"
    	},
    	"postback": {
    	    "text": "Not Sure?",
    	    "payload": "MOXTRABOT_NOT SURE?"
    	},
    	"target": {
    	    "id": "BAGUChIRH7P7eBdR9h9nyR5",
    	    "object_type": "binder"
    	}
        }
    }

    Follow the Node.js or Java example to handle "postback" event.

  • account_link - a button contains "text". Once tapped it will follow the Account Linking flow.

Register a Bot App

You need to have a Bot deployed with correct 'YOUR_VERIFY_TOKEN' for Moxtra to verify during Bot App creation. To create a Moxtra Bot App, please using the following link: MoxtraBot configuration

Bot verification flow: before saving bot configuration during bot app creation, a JSONP verification request with message_type=bot_verify&verify_token='YOUR_VERIFY_TOKEN'& bot_challenge='RANDOM_STRING' sending to the configured verify_url. To complete the bot creation, this request expects the same 'RANDOM_STRING' gets returned.

Example (Node.js)

if (req.query['message_type'] === 'bot_verify' && req.query['verify_token'] === this.verify_token) {
	console.log('Verification Succeed!')

	if (req.query['callback']) {
		res.status(200).jsonp(req.query['bot_challenge']);
	} else {
		res.status(200).send(req.query['bot_challenge']);
	}		    
}    

Example (Java)

String message_type = request.getParameter("message_type");

if ("bot_verify".equals(message_type)) {
	String verifyToken = request.getParameter("verify_token");	

	logger.info("verify_token: " + verifyToken + " configured: " + verify_token);

	if (verifyToken != null && verifyToken.equals(verify_token)) {
		// response challenge
		String challenge = request.getParameter("bot_challenge");	

		PrintWriter out = response.getWriter();

		// for JSONP
		String callback = request.getParameter("callback");
		if (callback != null) {
			response.setContentType("application/javascript");
			out.println(callback + "(\"" + challenge + "\")");
		} else {
			response.setContentType("text/plain");
			out.println(challenge);
		}
	}
}	

Test your Bot

After you have configured your Bot with required 'YOUR_CLIENT_SECRET' and other OAuth2 configurations if performing account linking.
You can install your Bot in one of your binders via UI or API.