Help & Support
Our help database contains answers to most of the common questions regarding our products.
If you are unable to locate a satisfactory answer for your query by searching here, please contact us.
How do I automate creating channels with the Channel API?
Cbox Pro provides a very simple API for creating new channels on the fly.
At the Channels page in your control panel you will find your secret API URL. You can open this URL directly in your browser to test it, but it's intended to be called by back-end scripts running on your own site.
The return format for this call is a single line of tab-separated plain-text fields. If there was an error, the first field is "FAIL" and the second field is an error code. If a new thread was successfully generated, the first field is "OK", and the second and third fields are the thread ID and thread key, respectively.
By way of example, this very simple PHP script will generate threads for your Cbox. New threads created via the API will show up in your control panel, but you should store the thread ID and key in your own database as well.
<?php
$cb_tid = null;
$cb_tkey = null;
$cb_rs = file_get_contents('YOUR_API_URL', 'r');
$cb_rp = explode("\t", $cb_rs);
if ($cb_rp[0] === 'FAIL') {
// There was an error.
// $cb_rp[1] contains the error code
}
else if ($cb_rp[0] === 'OK') {
// Success
$cb_tid = $cb_rp[1];
$cb_tkey = $cb_rp[2];
}
else {
// Some other error occured.
}
if ($cb_tid && $cb_tkey) {
// New key generated. Store $cb_tid and $cb_tkey in your database or user session.
// And insert them into your Cbox HTML code iframe src URLs:
// ....&sec=main&tid=<?php echo $cb_tid;?>&tkey=<?php echo $cb_tkey;?>
// ....&sec=form&tid=<?php echo $cb_tid;?>&tkey=<?php echo $cb_tkey;?>
}
?>
Bot users
You can register a bot user at your Users page. Bot users are like ordinary registered users, except that instead of a password they are issued an access token. You cannot log in via the normal profile dialog. Instead, you can use the token directly in HTTP requests to Cbox.
We do not currently support an official API, but to demonstrate how you might read and post to your Cbox using a bot, the proof-of-concept PHP script below takes a simple HTTP-based approach. Run this script on your own server, and your bot will post to your Cbox. After its initial message, it will poll for messages containing trigger words, to which it will respond.
You can run the script from a shell, or have it run automatically with a crontab entry. When it's running, test it by entering a message in your Cbox such as "hello bot", "time?", or "what is the weather in new york?"
#!/usr/bin/php
<?php
define('LISTEN', true);
define('PID_FILE', './cboxbot.pid');
// Edit these lines for your Cbox and bot user.
$box = array('srv' => 7, 'id' => 1, 'tag' => 'bOxTag');
$bot = array('name' => 'mybot', 'token' => 'XJC-bottoken-asKC', 'url' => '');
$msg = 'Hello world!';
$callmap = array(
'/\bhello bot\b/iu' => 'bot_greet',
'/\btime\?/iu' => 'bot_time',
'/\bweather in ([a-zA-Z-0-9 ,]+)/iu' => 'bot_weather',
);
// Basic reply
function bot_time ($msg) {
return date("M d Y H:i:s");
}
// An example incorporating message data.
function bot_greet ($msg) {
return "Hello ".$msg['name'];
}
// An example calling an external API
function bot_weather ($msg, $matches) {
$place = $matches[1];
if (!$place) {
return;
}
$query = 'select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="'.addslashes($place).'")';
$url = 'https://query.yahooapis.com/v1/public/yql?q='.urlencode($query).'&format=json&u=c&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys';
$out = file_get_contents($url);
if (!$out) {
return;
}
$wobj = json_decode($out);
if (!$wobj->query->results) {
return;
}
$cond = $wobj->query->results->channel->item->condition;
$desc = $wobj->query->results->channel->description;
return "[b]".$cond->text." ".$cond->temp."F [/b] (".$desc." at ".$cond->date.")";
}
// Do not edit past this point.
set_time_limit(0);
$id = cbox_post($msg, $bot, $box, $error);
if (!$id) {
echo $error;
}
else {
echo "Posted ID $id\n";
}
if (!LISTEN) {
exit;
}
// Synchronization.
// PID file is not removed on exit, but it is unlocked. A locked file indicates a running process.
$fp = fopen(PID_FILE, 'a+');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
echo "Could not lock PID file. Process already running?\n";
exit;
}
ftruncate($fp, 0);
fwrite($fp, posix_getpid()."\n");
fflush($fp);
do {
$msgs = cbox_get_msgs($id, $bot, $box);
if (!$msgs || !is_array($msgs)) {
sleep(5);
continue;
}
$id = (int)$msgs[0]['id'];
for ($i = 0; $i < count($msgs); $i++) {
if ($msgs[0]['name'] == $bot['name']) {
continue; // Ignore bot's own messages.
}
$msgtext = $msgs[$i]['message'];
foreach ($callmap as $expr => $func) {
$matches = array();
if (preg_match($expr, $msgtext, $matches)) {
$reply = call_user_func($func, $msgs[$i], $matches);
if ($reply) {
cbox_post($reply, $bot, $box, $error);
}
}
}
}
sleep(2);
} while (true);
function cbox_get_msgs ($id, $user, $box, &$error = '') {
$srv = $box['srv'];
$boxid = $box['id'];
$boxtag = $box['tag'];
$host = "www$srv.cbox.ws";
$path = "/box/?boxid=$boxid&boxtag=$boxtag&sec=archive";
$port = 80;
$timeout = 30;
$get = array(
'i' => (int)$id,
'k' => $user['token'],
'fwd' => 1,
'aj' => 1
);
$req = '';
$res = '';
foreach ($get as $k => $v) {
$path .= "&$k=".urlencode($v);
}
$hdr = "GET $path HTTP/1.1\r\n";
$hdr .= "Host: $host\r\n\r\n";
$fp = fsockopen ($host, $port, $errno, $errstr, $timeout);
if (!$fp) {
$error = "Could not open socket: $errno - $errstr\n";
return;
}
fputs ($fp, $hdr);
while (!feof($fp)) {
$res .= fgets ($fp, 1024);
}
fclose ($fp);
if (!$res || !strpos($res, "200 OK")) {
$error = "Bad response:\r\n $res";
return;
}
$matches = array();
preg_match_all('/\n([^\t\n]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t'
.'([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t/', $res, $matches);
$msgs = array();
$map = array('id', 'time', 'date', 'name', 'group', 'url', 'message');
for ($m = 0; $m < count($map); $m++) {
for ($i = 0; $i < count($matches[$m+1]); $i++) {
$msgs[$i][$map[$m]] = $matches[$m+1][$i];
}
}
return $msgs;
}
function cbox_post ($msg, $user, $box, &$error = '') {
$srv = $box['srv'];
$boxid = $box['id'];
$boxtag = $box['tag'];
$host = "www$srv.cbox.ws";
$path = "/box/?boxid=$boxid&boxtag=$boxtag&sec=submit";
$port = 80;
$timeout = 30;
$post = array(
'nme' => $user['name'],
'key' => $user['token'],
'eml' => $user['url'],
'pst' => $msg,
'aj' => '1'
);
$req = '';
$res = '';
foreach ($post as $k => $v) {
$req .= "$k=".urlencode($v)."&";
}
$req = substr($req, 0, -1);
$hdr = "POST $path HTTP/1.1\r\n";
$hdr .= "Host: $host\r\n";
$hdr .= "Content-Type: application/x-www-form-urlencoded\r\n";
$hdr .= "Content-Length: ".strlen($req)."\r\n\r\n";
$fp = fsockopen ($host, $port, $errno, $errstr, $timeout);
if (!$fp) {
$error = "Could not open socket: $errno - $errstr\n";
return;
}
fputs ($fp, $hdr.$req);
while (!feof($fp)) {
$res .= fgets ($fp, 1024);
}
fclose ($fp);
if (!$res || !strpos($res, "200 OK")) {
$error = "Bad response:\r\n $res";
return;
}
$matches = array();
preg_match('/1(.*)\t(.*)\t(.*)\t(.*)\t(.*)\t(.*)/', $res, $matches);
$err = $matches[1];
$id = $matches[6];
if ($err) {
$error = "Got error from Cbox: $err";
return;
}
return $id;
}
?>
Using the Cbox webhook
Getting started
This feature requires some familiarity with hosting your own scripts on the Web. Our code examples are in PHP, but you can use any platform and programming language you like, providing you can access HTTP POST data.
The Cbox webhook is an HTTP POST callback mechanism for getting a copy of new messages as they are posted to your Cbox. A couple of lines of PHP are sufficient to get started:
<?php
$input = @file_get_contents("php://input");
$json = json_decode($input);
// $json contains array of messages
error_log(print_r($json, true), 1, "your-email@example.com");
echo "OK";
?>
With the above code uploaded to your server, test that it works by opening the corresponding URL, e.g. https://yoursite.example.com/cbox.php, and confirming that you see "OK". You can then enter it as your callback URL in your Cbox settings.
When a user posts a message, Cbox will issue an HTTP POST request to your callback URL,
with Content-Type application/json. The request body will look something like this:
[{"type":"message","box":802140,"channel":0,"time":1488526982,"uid":0,"name":"test","text":"this is a test","link":"","ip":"0.0.0.0"}]
The object is an array of messages. There can be multiple messages in a single POST. Your code can do whatever you like with the messages; it just needs to return an HTTP OK status to Cbox. Any response body is ignored.
Message contents
The message webhook is located after the message-accepted stage and before filtering. This means your endpoint will only receive messages that are being published on your Cbox (i.e. not messages from banned users). They will be "raw", having none of the built-in or custom filters applied (i.e. no boxcode expansion). Important to note is that messages can contain any UTF-8 character, and so should be escaped as appropriate before storage or display.
Message properties:
type— always set to "message"box— your Cbox ID.channel— The channel ID to which the message was posted.id— The message ID.time— Unix times when the message was received.uid— Registered user ID. Guest IDs are undefined or zero.name— The user's name, as entered.text— The text of the message, as entered.link— Link associated with the message; the profile URL.ip— IP address of the user.
Errors and retry
Your endpoint needs to return an HTTP success header (status codes in the 2XX range) in response to the POST.
If it returns any other status, or times out, Cbox will consider the delivery to have failed. On failure, Cbox will buffer messages for
retry. Cbox will retry the POST at increasingly long intervals, even in the absence of further new messages.
Cbox buffers are not unlimited; if your endpoint is down for an extended time, the oldest messages may be dropped.
Notes
- Cbox ignores the body sent in response to the POST, and does not wait for it to complete.
- Return a
200 OKto Cbox as quickly as possible. Otherwise, there is a risk of a timeout, which will cause the same message(s) to be re-sent. If your message processing is slow, move it "offline", either by completing and flushing the HTTP response early and continuing to work, or by offloading incoming messages to another service. - For forwards-compatibility, confirm that
type == 'message'in your code; new event types may be supported in future. - The box and channel properties mean you can multiplex several Cboxes to a single endpoint, and filter or switch based on channel.
- Message ID is a monotonically increasing number. Larger IDs are always newer messages.
- Although some properties are 32-bit integers, it's recommended that you treat all values as UTF-8 strings for storage or further processing.
- The POST request includes a custom HTTP header,
X-Cbox-Timewhich contains the Unix timestamp at the moment the POST was sent. You can use this to calculate differential message times.
Can I have more than one Cbox?
Yes, you can have as many as you like! Create a separate account for each Cbox. You will need a unique account name for each, but we recommend using the same email address.
If you need a large number of Cboxes, you might want to be on our Cbox Pro plan. Cbox Pro supports channels, which are independent conversation threads. Each channel can be embedded or linked as if it were a separate Cbox, and will host a separate conversation. Channels share the same theme, settings and users, and you only need one control panel login to manage them.