Integrations
SDKs & integrations
Call ConvoAI from your own code with any HTTP client, or wire it into Zapier, Make and n8n with their built-in webhook and HTTP modules. No extra infrastructure required.
Client libraries#
All examples use the base URL https://convoai.cloud/api/v1/ and read the key from an environment variable. See the API reference for every endpoint.
Python#
A thin wrapper around requests (pip install requests).
import os
import requests
BASE_URL = "https://convoai.cloud/api/v1"
class ConvoAIError(Exception):
def __init__(self, status, body):
super().__init__(f"{status} {body.get('error')}: {body.get('detail')}")
self.status = status
self.body = body
class ConvoAI:
def __init__(self, api_key=None):
self.session = requests.Session()
self.session.headers["Authorization"] = f"Bearer {api_key or os.environ['CONVOAI_API_KEY']}"
def request(self, method, path, **kwargs):
resp = self.session.request(method, f"{BASE_URL}{path}", timeout=30, **kwargs)
if resp.status_code == 204:
return None
body = resp.json() if resp.content else {}
if resp.status_code >= 400:
raise ConvoAIError(resp.status_code, body)
return bodyChat with an agent
client = ConvoAI()
first = client.request("POST", "/agents/42/chat/", json={
"message": "Do you have availability this Friday?",
})
print(first["reply"])
# Continue the same conversation
follow_up = client.request("POST", "/agents/42/chat/", json={
"message": "10am works. Book it for Jane Doe.",
"session_id": first["session_id"],
})Page through open conversations
page = 1
while True:
data = client.request("GET", "/agents/42/conversations/",
params={"status": "open", "page": page})
for conv in data["results"]:
print(conv["id"], conv["contact_name"], conv["last_message_at"])
if not data["next"]:
break
page += 1Add a knowledge document
doc = client.request("POST", "/agents/42/knowledge/", json={
"title": "Shipping policy",
"doc_type": "text",
"content": "Standard delivery is 5 to 7 business days…",
})
print(doc["id"], doc["chunk_count"])To receive events, see the signature verification examples.
JavaScript / TypeScript#
Uses the built-in fetch, so it runs on Node.js 18+ and edge runtimes with no dependencies.
const BASE_URL = "https://convoai.cloud/api/v1";
export class ConvoAIError extends Error {
constructor(public status: number, public body: { error?: string; detail?: string }) {
super(`${status} ${body.error}: ${body.detail}`);
}
}
export async function convoai<T = unknown>(
method: "GET" | "POST" | "PATCH" | "DELETE",
path: string,
body?: unknown,
): Promise<T> {
const res = await fetch(`${BASE_URL}${path}`, {
method,
headers: {
Authorization: `Bearer ${process.env.CONVOAI_API_KEY}`,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
if (res.status === 204) return undefined as T;
const data = await res.json();
if (!res.ok) throw new ConvoAIError(res.status, data);
return data as T;
}Send a WhatsApp message
await convoai("POST", "/agents/42/messages/", {
to: "+15551234567",
type: "text",
text: "Hi! Your order #4821 has shipped.",
});
// Outside the 24-hour window, use an approved template
await convoai("POST", "/agents/42/messages/", {
to: "+15551234567",
type: "template",
template_name: "order_shipped",
template_params: ["4821"],
language_code: "en_US",
});Create a contact and tag it
// Returns 201 for a new contact, 200 if that phone already exists for the agent
const contact = await convoai<{ id: number }>("POST", "/contacts/", {
agent_id: 42,
phone: "+15551234567",
name: "Maria Garcia",
email: "maria@example.com",
stage: "prospect",
});
await convoai("POST", `/contacts/${contact.id}/tags/`, { tags: ["vip", "spanish"] });Receive webhooks in a Next.js route handler
import crypto from "node:crypto";
export async function POST(req: Request) {
const raw = Buffer.from(await req.arrayBuffer());
const header = req.headers.get("x-convoai-signature") ?? "";
const expected = crypto
.createHmac("sha256", process.env.CONVOAI_WEBHOOK_SECRET!)
.update(raw)
.digest();
const received = Buffer.from(header.replace(/^sha256=/, ""), "hex");
if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) {
return Response.json({ error: "Invalid signature" }, { status: 403 });
}
const event = req.headers.get("x-convoai-event");
const payload = JSON.parse(raw.toString("utf8"));
// ... handle the event
return Response.json({ received: true });
}Zapier#
There is no ConvoAI app in the Zapier directory. Use Zapier's built-in Webhooks by Zapier steps instead: a catch hook to receive ConvoAI events, and a request action to call the API.
- 1
Catch ConvoAI events
Create a Zap whose trigger is Webhooks by Zapier → Catch Hook and copy the URL Zapier gives you. - 2
Register that URL in ConvoAI
Add it on your agent's Integrations page in the dashboard, or withPOST /agents/{agent_id}/webhooks/, choosing the events you want. - 3
Call the API from an action
Add a Webhooks by Zapier action (POST or Custom Request) pointing at a ConvoAI endpoint, with the headerAuthorization: Bearer YOUR_API_KEYand a JSON body.
appointment.created arrives, post the appointment to Slack and add a row to a spreadsheet, all in one Zap.Make#
Make scenarios use the Webhooks → Custom webhook module as a trigger and the HTTP → Make a request module for API calls.
- 1
Add a Custom webhook trigger
Make generates a unique URL. Register it in ConvoAI on your agent's Integrations page or through the webhooks API. - 2
Build the scenario
Chain modules (Google Sheets, a CRM, Slack, email) after the trigger and map fields from the event'sdataobject. - 3
Call ConvoAI with the HTTP module
Configure the request as below, then activate the scenario.
URL: https://convoai.cloud/api/v1/agents/42/messages/
Method: POST
Headers: Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Body (raw JSON):
{
"to": "{{contact.phone}}",
"type": "text",
"text": "Hi {{contact.name}}, your appointment is confirmed for {{appointment.date}}."
}n8n#
In n8n, use the Webhook node to receive events and the HTTP Request node to call the API.
- 1
Create a credential
Under Credentials → New → Header Auth, set the name toAuthorizationand the value toBearer YOUR_API_KEY. Save it as “ConvoAI API”. - 2
Receive events with a Webhook node
Add a Webhook node (method POST) as the trigger, copy its production URL and register it in ConvoAI. - 3
Call the API with HTTP Request nodes
Select the “ConvoAI API” credential, set the method and URL, and use expressions to pass data from earlier nodes.
JSON.stringify() of the parsed body. ConvoAI serialises JSON with spaces after : and ,, so re-serialising in JavaScript produces different bytes and the check always fails. Enable the Webhook node's raw body option and hash those bytes, as in the Node.js example.Other languages#
Every ConvoAI feature is reachable over standard HTTP. Sending a message from PHP, Ruby and Go:
<?php
$ch = curl_init('https://convoai.cloud/api/v1/agents/42/messages/');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CONVOAI_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+15551234567',
'type' => 'text',
'text' => 'Hello from PHP!',
]),
]);
$response = json_decode(curl_exec($ch), true);
echo $response['status']; // queuedrequire "net/http"
require "json"
uri = URI("https://convoai.cloud/api/v1/agents/42/messages/")
req = Net::HTTP::Post.new(uri, {
"Authorization" => "Bearer #{ENV.fetch("CONVOAI_API_KEY")}",
"Content-Type" => "application/json",
})
req.body = { to: "+15551234567", type: "text", text: "Hello from Ruby!" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)["status"] # queuedpackage main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
body, _ := json.Marshal(map[string]string{
"to": "+15551234567", "type": "text", "text": "Hello from Go!",
})
req, _ := http.NewRequest("POST", "https://convoai.cloud/api/v1/agents/42/messages/", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("CONVOAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(resp.StatusCode, result["status"]) // 201 queued
}- Endpoints, parameters and errors: API reference
- Events and signatures: Webhooks
