BluetickedDeveloper docs

AI agents

5 endpoints, each with examples that open in the console prefilled.

All resources
GET/api/v1/ai-agentsai_agents:readTry in console

List AI agents

Every AI agent with its autonomy mode, channels and thresholds: the review surface.

Query parameters
statusstring
  • model is the model saved for the agent in the dashboard; effective_model is the model its replies run on now. A saved selection that is not yet available (such as claude-sonnet-5) or retired runs on the default, so the two can differ.
  • reply_mode is the autonomy ladder: triage/suggest draft for a human, auto replies on its own above confidence_threshold.
  • status filters to live, testing, paused or draft. live and testing both answer customers.
curl -X GET "https://app.blueticked.com/api/v1/ai-agents?status=live" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "ok": true,
  "agents": [
    {
      "id": "7e2a1b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
      "business_id": "22222222-2222-4222-9222-222222222222",
      "name": "Reception agent",
      "description": "Answers hours, prices and booking questions.",
      "status": "live",
      "model": "claude-sonnet-4-6",
      "effective_model": "claude-sonnet-4-6",
      "reply_mode": "suggest",
      "confidence_threshold": 0.7,
      "enabled_channels": [
        "whatsapp"
      ],
      "business_hours_only": true,
      "disclosure_text": "You are chatting with our AI assistant.",
      "created_at": "2026-07-10T09:00:00.000Z",
      "updated_at": "2026-08-01T10:00:00.000Z"
    }
  ]
}
GET/api/v1/ai-agents/{id}ai_agents:readTry in console

Get one AI agent

One agent in full, its persona text included.

  • The persona is the exact system text the agent replies with, worth auditing whenever behaviour surprises you.
  • effective_model is the model these replies run on; model is the selection saved in the dashboard, which can differ when that selection is not yet available.
curl -X GET "https://app.blueticked.com/api/v1/ai-agents/{id}" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "ok": true,
  "agent": {
    "id": "7e2a1b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
    "business_id": "22222222-2222-4222-9222-222222222222",
    "name": "Reception agent",
    "description": "Answers hours, prices and booking questions.",
    "status": "live",
    "model": "claude-sonnet-4-6",
    "effective_model": "claude-sonnet-4-6",
    "reply_mode": "suggest",
    "confidence_threshold": 0.7,
    "enabled_channels": [
      "whatsapp"
    ],
    "business_hours_only": true,
    "disclosure_text": "You are chatting with our AI assistant.",
    "created_at": "2026-07-10T09:00:00.000Z",
    "updated_at": "2026-08-01T10:00:00.000Z",
    "persona": "You are the friendly reception…"
  }
}
POST/api/v1/ai-agents/{id}/chatai_agents:chatTry in console

Chat with an AI agent

Converse with a live agent from your own surface: the agent as a headless channel.

Body parameters
messagerequiredstring
session_idrequiredstring
historyobject[]
  • STATELESS by design: the API stores nothing your end user types. history (max 12 turns, oldest first) is everything the agent remembers, and session_id survives only as a one-way hash in the billing ledger. Send the prior turns back on every call.
  • Each reply is charged from the prepaid wallet: R2.50, or its real model cost plus 20% when a very long reply costs more (ai.api_chat, the same price as every AI reply). An empty wallet answers 402 insufficient_balance; the workspace's shared API-chat ceiling (R25 a day of model cost, about 100 typical replies) answers 402 spend_cap_reached and resets at midnight UTC.
  • handoff_recommended: true means the reply scored below the agent's own confidence threshold, the same rule the autonomy ladder applies on WhatsApp. You own the surface, so the handoff is yours to route.
  • Show disclosure to your end user when present. Telling people they are talking to an AI is the merchant's stated policy, and in most jurisdictions the law.
  • Only a live or testing agent answers. A paused or draft one returns enable_requires_dashboard: enabling an autonomous responder is a human act.
  • Browser callers use a PUBLISHABLE key (blu_pub_…, minted at Developers → API keys → New widget key, which appears once two-step verification is on): safe to ship in page source because it only works on this endpoint and only from the exact origins it was minted for. The ready-made widget (<script src="https://app.blueticked.com/widget.js" data-agent="…" data-key="blu_pub_…" async></script>) is a client of this endpoint, nothing more.
curl -X POST "https://app.blueticked.com/api/v1/ai-agents/{id}/chat" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message": "What time do you open on Saturdays?",
  "session_id": "visitor-83f2",
  "history": [
    {
      "role": "customer",
      "body": "Hi!"
    },
    {
      "role": "agent",
      "body": "Hello! How can I help today?"
    }
  ]
}'
Response
{
  "ok": true,
  "reply": "We're open 08:00 to 13:00 on Saturdays.",
  "handoff_recommended": false,
  "disclosure": "You are chatting with our AI assistant."
}
POST/api/v1/ai-agents/{id}/chat/handoffai_agents:chatTry in console

Hand a chat to a human

The chat visitor leaves their details and becomes a lead, with the transcript attached.

Body parameters
session_idrequiredstring
namestring
phonestring
transcriptobject[]
consentrequiredboolean
  • This is the ONE place in the agent channel where anything personal is stored, and only because the visitor asked: consent must be literally true (a ticked checkbox), and at least one of phone / email must be present. Otherwise 400 and nothing is written.
  • The result is a LEAD in the Leads pipeline (source agent_chat) with the transcript on its answer card, linked to a deduped contact. The visitor's ticked box is consent to being contacted about this enquiry, kept on the lead; it never subscribes them to marketing. The team follows up on real channels, so there is no new inbox to watch.
  • No model runs and nothing is metered here: it would be absurd to charge for receiving a lead.
  • A PAUSED agent still hands off (a visitor mid-conversation deserves a human, not a wall); only a draft agent answers 404.
  • The ready-made widget does all of this itself: the visitor types "agent" or clicks the handoff link, fills the inline form, done.
curl -X POST "https://app.blueticked.com/api/v1/ai-agents/{id}/chat/handoff" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "session_id": "visitor-83f2",
  "name": "Sam Nkosi",
  "phone": "+27800000001",
  "transcript": [
    {
      "role": "customer",
      "body": "Do you deliver to Worcester?"
    },
    {
      "role": "agent",
      "body": "A member of our team will confirm that."
    }
  ],
  "consent": true
}'
Response
{
  "ok": true,
  "lead_created": true,
  "reply": "Thanks — the team has your details and the conversation so far, and will be in touch."
}
PATCH/api/v1/ai-agents/{id}ai_agents:writeTry in console

Pause an AI agent

Stop an agent replying immediately: the always-available safe direction.

Body parameters
enabledrequiredboolean
  • { enabled: true } is refused with enable_requires_dashboard. Re-enabling an autonomous responder is a human act, made where its persona and escalation rules are visible.
curl -X PATCH "https://app.blueticked.com/api/v1/ai-agents/{id}" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": false
}'
Response
{
  "ok": true,
  "agent": {
    "id": "7e2a1b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
    "business_id": "22222222-2222-4222-9222-222222222222",
    "name": "Reception agent",
    "description": "Answers hours, prices and booking questions.",
    "status": "paused",
    "model": "claude-sonnet-4-6",
    "effective_model": "claude-sonnet-4-6",
    "reply_mode": "suggest",
    "confidence_threshold": 0.7,
    "enabled_channels": [
      "whatsapp"
    ],
    "business_hours_only": true,
    "disclosure_text": "You are chatting with our AI assistant.",
    "created_at": "2026-07-10T09:00:00.000Z",
    "updated_at": "2026-08-01T10:00:00.000Z"
  }
}