Getting Started

The BotPlot API lets you integrate your AI chatbot into any application. Build custom chat interfaces, manage knowledge programmatically, and access analytics data.

Base URL

https://botplot.app/api/v1

Authentication

Authorization: Bearer YOUR_KEY

API Keys

pk_

Public Key

For chat endpoints. Safe to use in client-side code.

sk_

Secret Key

For management endpoints (knowledge, conversations, leads, analytics). Server-side only.

Find your keys in Dashboard → Settings

Rate Limits

PlanMonthly API Calls
FreeNo API access
Pro1,000 / month
Business5,000 / month
Enterprise10,000 / month

Rate limit info is included in response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset

Error Format

{
  "error": "Description of the error",
  "code": "ERROR_CODE"
}
StatusNameDescription
400Bad RequestInvalid request parameters or body
401UnauthorizedMissing or invalid API key
403ForbiddenAPI access requires a paid plan, or action not allowed
404Not FoundResource not found
429Too Many RequestsMonthly API limit exceeded
500Internal ErrorSomething went wrong on our end

Chat

POST/api/v1/chatPublic Key

Send a message and get a response. Creates a new conversation if no conversationId is provided.

ParameterTypeRequiredDescription
messagestringRequiredThe user message to send
conversationIdstringOptionalContinue an existing conversation
visitorIdstringOptionalUnique visitor identifier
curl -X POST "https://botplot.app/api/v1/chat" \
  -H "Authorization: Bearer pk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message": "What is your return policy?"
}'

Response

{
  "response": "Our return policy allows returns within 30 days of purchase...",
  "conversationId": "550e8400-e29b-41d4-a716-446655440000",
  "messageId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
  "sources": 3
}
POST/api/v1/chat/streamPublic Key

Send a message and get a streaming SSE response. Tokens arrive in real-time.

ParameterTypeRequiredDescription
messagestringRequiredThe user message to send
conversationIdstringOptionalContinue an existing conversation
visitorIdstringOptionalUnique visitor identifier
curl -X POST "https://botplot.app/api/v1/chat/stream" \
  -H "Authorization: Bearer pk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message": "How do I get started?"
}'

Response

data: {"type":"token","content":"To"}

data: {"type":"token","content":" get"}

data: {"type":"token","content":" started"}

data: {"type":"done","messageId":"...","conversationId":"..."}

Knowledge

GET/api/v1/knowledgeSecret Key

List all knowledge sources for the project.

curl -X GET "https://botplot.app/api/v1/knowledge" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "sources": [
    {
      "id": "550e8400-...",
      "type": "url",
      "name": "https://example.com",
      "status": "ready",
      "chunkCount": 12,
      "wordCount": 4500,
      "syncFrequency": "daily",
      "createdAt": "2026-02-15T10:30:00Z"
    }
  ]
}
POST/api/v1/knowledge/urlSecret Key

Add a URL source. Triggers async crawl, embedding, and indexing.

ParameterTypeRequiredDescription
urlstringRequiredThe URL to crawl and index
syncFrequencystringOptional"manual", "daily", or "weekly"
curl -X POST "https://botplot.app/api/v1/knowledge/url" \
  -H "Authorization: Bearer sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/docs",
  "syncFrequency": "daily"
}'

Response

{
  "sourceId": "550e8400-...",
  "status": "processing"
}
POST/api/v1/knowledge/qaSecret Key

Add a Q&A pair as a knowledge source.

ParameterTypeRequiredDescription
questionstringRequiredThe question
answerstringRequiredThe answer
curl -X POST "https://botplot.app/api/v1/knowledge/qa" \
  -H "Authorization: Bearer sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "question": "What are your hours?",
  "answer": "We are open Monday-Friday, 9am-5pm EST."
}'

Response

{
  "sourceId": "550e8400-...",
  "status": "processing"
}
GET/api/v1/knowledge/:sourceIdSecret Key

Get full details of a knowledge source including its chunks.

ParameterTypeRequiredDescription
sourceIdstringRequiredThe source ID
curl -X GET "https://botplot.app/api/v1/knowledge/:sourceId" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "source": {
    "id": "550e8400-...",
    "type": "url",
    "name": "https://example.com",
    "status": "ready"
  },
  "chunks": [
    {
      "id": "...",
      "content": "First paragraph...",
      "tokenCount": 150
    }
  ]
}
POST/api/v1/knowledge/:sourceId/recrawlSecret Key

Re-crawl a URL source to update its content.

ParameterTypeRequiredDescription
sourceIdstringRequiredThe source ID
curl -X POST "https://botplot.app/api/v1/knowledge/:sourceId/recrawl" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "success": true,
  "status": "processing"
}
DELETE/api/v1/knowledge/:sourceIdSecret Key

Delete a knowledge source and all its chunks.

ParameterTypeRequiredDescription
sourceIdstringRequiredThe source ID
curl -X DELETE "https://botplot.app/api/v1/knowledge/:sourceId" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "success": true
}

Conversations

GET/api/v1/conversationsSecret Key

List conversations with pagination and optional status filter.

ParameterTypeRequiredDescription
limitnumberOptionalMax results (default 20, max 100)
offsetnumberOptionalSkip N results
statusstringOptional"active", "closed", "archived", or "handed_off"
curl -X GET "https://botplot.app/api/v1/conversations" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "conversations": [
    {
      "id": "550e8400-...",
      "visitorId": "visitor_abc",
      "status": "active",
      "overallRating": 1,
      "handoffStatus": "none",
      "messageCount": 4,
      "firstMessage": "Hi, I have a question...",
      "createdAt": "2026-02-15T10:30:00Z"
    }
  ],
  "total": 42
}
GET/api/v1/conversations/:idSecret Key

Get a conversation with all its messages.

ParameterTypeRequiredDescription
idstringRequiredThe conversation ID
curl -X GET "https://botplot.app/api/v1/conversations/:id" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "conversation": {
    "id": "550e8400-...",
    "status": "active",
    "messages": [
      {
        "id": "...",
        "role": "user",
        "content": "What is your pricing?",
        "createdAt": "2026-02-15T10:30:00Z"
      },
      {
        "id": "...",
        "role": "assistant",
        "content": "Our pricing starts at...",
        "rating": 1,
        "createdAt": "2026-02-15T10:30:02Z"
      }
    ]
  }
}
DELETE/api/v1/conversations/:idSecret Key

Delete a conversation and all its messages.

ParameterTypeRequiredDescription
idstringRequiredThe conversation ID
curl -X DELETE "https://botplot.app/api/v1/conversations/:id" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "success": true
}

Leads

GET/api/v1/leadsSecret Key

List captured leads with pagination and search.

ParameterTypeRequiredDescription
limitnumberOptionalMax results (default 20, max 100)
offsetnumberOptionalSkip N results
searchstringOptionalSearch by name or email
curl -X GET "https://botplot.app/api/v1/leads" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "leads": [
    {
      "id": "550e8400-...",
      "name": "John Doe",
      "email": "john@example.com",
      "phone": "+1234567890",
      "createdAt": "2026-02-15T10:30:00Z"
    }
  ],
  "total": 15
}
DELETE/api/v1/leads/:idSecret Key

Delete a lead.

ParameterTypeRequiredDescription
idstringRequiredThe lead ID
curl -X DELETE "https://botplot.app/api/v1/leads/:id" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "success": true
}

Analytics

GET/api/v1/analyticsSecret Key

Get project analytics: conversations, messages, visitors, and trends.

ParameterTypeRequiredDescription
periodstringOptional"7d", "30d", or "90d" (default "30d")
curl -X GET "https://botplot.app/api/v1/analytics" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "overview": {
    "totalConversations": 156,
    "totalMessages": 892,
    "uniqueVisitors": 89,
    "avgMessagesPerConversation": 5.7,
    "leadsCollected": 23,
    "resolutionRate": 94.2
  },
  "messagesOverTime": [
    {
      "date": "2026-02-15",
      "messages": 12,
      "conversations": 5
    }
  ],
  "topQuestions": [
    {
      "question": "What is your pricing?",
      "count": 8
    }
  ]
}
GET/api/v1/analytics/ratingsSecret Key

Get customer satisfaction ratings summary and trends.

ParameterTypeRequiredDescription
periodstringOptional"7d", "30d", or "90d" (default "30d")
curl -X GET "https://botplot.app/api/v1/analytics/ratings" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "summary": {
    "totalRatings": 45,
    "positive": 38,
    "negative": 7,
    "satisfactionRate": 84.4
  },
  "ratingsTrend": [
    {
      "date": "2026-02-15",
      "positive": 3,
      "negative": 1
    }
  ]
}

Webhooks

GET/api/v1/projects/:projectId/webhooksSecret Key

List all webhooks for a project.

ParameterTypeRequiredDescription
projectIdstringRequiredThe project ID
curl -X GET "https://botplot.app/api/v1/projects/:projectId/webhooks" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "webhooks": [
    {
      "id": "550e8400-...",
      "url": "https://example.com/webhooks",
      "description": "My integration",
      "events": [
        "message.created",
        "lead.captured"
      ],
      "is_active": true,
      "created_at": "2026-02-15T10:30:00Z"
    }
  ]
}
POST/api/v1/projects/:projectId/webhooksSecret Key

Create a new webhook. Returns the signing secret (shown only once).

ParameterTypeRequiredDescription
projectIdstringRequiredThe project ID
urlstringRequiredHTTPS endpoint URL
eventsstring[]RequiredEvent types to subscribe to
descriptionstringOptionalFriendly description
curl -X POST "https://botplot.app/api/v1/projects/:projectId/webhooks" \
  -H "Authorization: Bearer sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/webhooks/botplot",
  "events": [
    "message.created",
    "lead.captured"
  ],
  "description": "CRM integration"
}'

Response

{
  "webhook": {
    "id": "550e8400-...",
    "url": "https://example.com/webhooks/botplot",
    "secret": "whsec_a1b2c3d4e5f6...",
    "events": [
      "message.created",
      "lead.captured"
    ],
    "is_active": true
  }
}
DELETE/api/v1/projects/:projectId/webhooks/:webhookIdSecret Key

Delete a webhook and all its delivery records.

ParameterTypeRequiredDescription
projectIdstringRequiredThe project ID
webhookIdstringRequiredThe webhook ID
curl -X DELETE "https://botplot.app/api/v1/projects/:projectId/webhooks/:webhookId" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "ok": true
}
POST/api/v1/projects/:projectId/webhooks/:webhookId/testSecret Key

Send a ping test event. Returns the delivery result immediately.

ParameterTypeRequiredDescription
projectIdstringRequiredThe project ID
webhookIdstringRequiredThe webhook ID
curl -X POST "https://botplot.app/api/v1/projects/:projectId/webhooks/:webhookId/test" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "delivery": {
    "deliveryId": "550e8400-...",
    "statusCode": 200,
    "responseBody": "OK",
    "success": true
  }
}

Branding

PATCH/api/v1/projects/:projectId/brandingSecret Key

Update white-label and custom logo settings. Requires Enterprise plan.

ParameterTypeRequiredDescription
projectIdstringRequiredThe project ID
white_labelbooleanOptionalEnable/disable white-label (removes BotPlot branding)
custom_logostringOptionalBase64 data URL of logo (PNG/JPG/SVG, max 100KB). Set to null to remove.
custom_domainstringOptionalCustom domain (e.g. chat.example.com). Set to null to remove.
curl -X PATCH "https://botplot.app/api/v1/projects/:projectId/branding" \
  -H "Authorization: Bearer sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "white_label": true,
  "custom_logo": "data:image/png;base64,iVBOR..."
}'

Response

{
  "white_label": true,
  "custom_logo": true
}
PATCH/api/v1/projects/:projectId/subdomainSecret Key

Configure a custom subdomain. Requires Enterprise plan. Must be unique, 3-30 chars, lowercase alphanumeric and hyphens.

ParameterTypeRequiredDescription
projectIdstringRequiredThe project ID
subdomainstringRequiredDesired subdomain (e.g. my-client-site)
curl -X PATCH "https://botplot.app/api/v1/projects/:projectId/subdomain" \
  -H "Authorization: Bearer sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "subdomain": "my-client-site"
}'

Response

{
  "subdomain": "my-client-site"
}
POST/api/v1/projects/:projectId/verify-domainSecret Key

Verify DNS configuration for a custom domain. Checks CNAME record resolution.

ParameterTypeRequiredDescription
projectIdstringRequiredThe project ID
curl -X POST "https://botplot.app/api/v1/projects/:projectId/verify-domain" \
  -H "Authorization: Bearer sk_YOUR_KEY"

Response

{
  "verified": true,
  "domain": "chat.example.com"
}

Verifying Webhook Signatures

Every webhook delivery includes an X-BotPlot-Signature header. Verify this signature to ensure the payload was sent by BotPlot and hasn't been tampered with.

Webhook Headers

HeaderDescription
X-BotPlot-SignatureHMAC-SHA256 signature: sha256=<hex>
X-BotPlot-EventThe event type (e.g., message.created)
X-BotPlot-DeliveryUnique delivery ID for deduplication
User-AgentBotPlot-Webhooks/1.0

Payload Format

{
  "event": "message.created",
  "project_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-02-15T10:30:00.000Z",
  "data": {
    "conversation_id": "...",
    "message_id": "...",
    "role": "assistant",
    "content": "Here is the answer to your question...",
    "confidence_score": 0.87,
    "created_at": "2026-02-15T10:30:00.000Z"
  }
}

Event Types

EventDescription
conversation.startedA new conversation was started
conversation.endedA conversation was idle for 30+ minutes and closed
message.createdA user or assistant message was created
lead.capturedA visitor submitted their contact info
handoff.requestedA visitor requested human support
rating.receivedA message or conversation was rated

Verification Examples

Node.js

const crypto = require("crypto");

function verifyWebhook(payload, signature, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express example
app.post("/webhooks/botplot", (req, res) => {
  const signature = req.headers["x-botplot-signature"];
  const isValid = verifyWebhook(
    JSON.stringify(req.body),
    signature,
    "whsec_YOUR_SECRET"
  );

  if (!isValid) return res.status(401).send("Invalid signature");

  const event = req.headers["x-botplot-event"];
  console.log("Received event:", event, req.body);
  res.status(200).send("OK");
});

Python

import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route("/webhooks/botplot", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-BotPlot-Signature", "")
    is_valid = verify_webhook(
        request.data,
        signature,
        "whsec_YOUR_SECRET"
    )

    if not is_valid:
        return "Invalid signature", 401

    event = request.headers.get("X-BotPlot-Event")
    print(f"Received event: {event}", request.json)
    return "OK", 200

cURL (testing)

# Generate a test signature
SECRET="whsec_YOUR_SECRET"
PAYLOAD='{"event":"ping","project_id":"...","timestamp":"...","data":{}}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/.* /sha256=/')

# Verify it matches X-BotPlot-Signature header
echo "Signature: $SIGNATURE"