Developer docs
Get an API keyIotaBot Email API
Send from your own domain, reply in thread, and receive every email as JSON.
Send and receive email with PHP
Send with cURL, receive with a plain PHP endpoint — no framework needed.
- Create an API key (a test key never sends) and a webhook endpoint in Developers.
- Set
IOTABOT_API_KEYandIOTABOT_WEBHOOK_SECRET(the endpoint'swhsec_…secret) in your environment. - Run the program below. Point the endpoint at
/iotabot/webhookon your server.
iotabot.php
<?php
// iotabot.php — one function for every send.
const API = 'https://api.iotabot.com/v1';
function iotabot_send(array $body): array {
$ch = curl_init(API . '/messages');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('IOTABOT_API_KEY'),
'Content-Type: application/json',
// One Idempotency-Key per message: reuse it if you retry, so it is never sent twice.
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => json_encode($body),
]);
$res = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status >= 300) throw new RuntimeException($res['error']['code'] . ': ' . $res['error']['message']);
return $res['data'];
}
send.php
<?php
// send.php — start a new email thread from one of your verified addresses (GET /v1/email/senders).
require __DIR__ . '/iotabot.php';
$sent = iotabot_send([
'channel' => 'email',
'to' => 'priya@example.com',
'from' => 'support@acme.com',
'subject' => 'Your order #1042',
'html' => '<p>Hi Priya, your order shipped yesterday.</p>',
]);
echo "queued {$sent['id']} in conversation {$sent['conversation_id']}\n";
webhook.php
<?php
// webhook.php — receive inbound email as JSON and reply in the same thread.
require __DIR__ . '/iotabot.php';
function iotabot_verified(string $raw, string $header, string $secret): bool {
$t = 0; $sigs = [];
foreach (explode(',', $header) as $part) {
[$k, $v] = array_pad(explode('=', $part, 2), 2, '');
if ($k === 't') $t = (int) $v;
if ($k === 'v1') $sigs[] = $v;
}
if (abs(time() - $t) > 300) return false; // older than 5 minutes
$expected = hash_hmac('sha256', $t . '.' . $raw, $secret);
foreach ($sigs as $sig) if (hash_equals($expected, $sig)) return true;
return false;
}
$raw = file_get_contents('php://input');
$event = json_decode($raw, true);
if ($event['type'] === 'endpoint.verification') { // sent once, when you add the endpoint
header('Content-Type: application/json');
echo json_encode(['challenge' => $event['data']['challenge']]);
exit;
}
if (!iotabot_verified($raw, $_SERVER['HTTP_IOTABOT_SIGNATURE'] ?? '', getenv('IOTABOT_WEBHOOK_SECRET'))) {
http_response_code(401);
exit;
}
if ($event['type'] === 'message.received') {
$conversation = $event['data']['conversation'];
$email = $event['data']['message']['email'];
error_log($email['from'] . ' wrote: ' . $email['subject']);
iotabot_send(['conversation_id' => $conversation['id'], 'text' => 'Thanks — we are on it!']);
}
http_response_code(200);
