Docs & API reference

Everything you need to connect your AI chatbot (on any AI model, including Grok, ChatGPT, Claude and Gemini), AI agents, n8n/Make automations, Google Sheets and CRM to ProofMyAI. Most setups take under 10 minutes and many need no code at all. Prefer video? Watch the 3-minute setup tutorial β†— or see alerts arrive in the live demo β†—.

πŸš€ Quick start

  1. Create a free account (50 conversations a month free).
  2. Open your project β†’ Settings and copy your API key (it starts with ap_live_). Each project has its own key.
  3. Pick what you want to monitor: upload chat transcripts, connect n8n/Make, or send events to the API below.
  4. Add a WhatsApp, Slack, Teams, email, Telegram or webhook channel under Settings β†’ Notifications so you hear about problems.

🧩 Connect without code

πŸ”‘ Authentication

Send your project API key with every request, in either header:

Authorization: Bearer ap_live_xxxxxxxxxxxxxxxx
# or
X-API-Key: ap_live_xxxxxxxxxxxxxxxx

Base URL: https://proofmyai.com/api/v1. Bodies are JSON (Content-Type: application/json), up to 2 MB. Keep the key on your server; don't put it in browser code. You can regenerate it in Settings at any time.

πŸ’¬ POST /chat-events: live chatbot monitoring

Send each conversation as it happens, either the full message history or just the newest question and answer. Personal data is masked before anything is stored or checked. Replies are graded in the background against your help articles and rules.

FieldTypeDescription
conversation_idstring, requiredYour ID for the conversation. Sending the same ID again adds only the new turns.
messagesarrayFull history: [{ role: "user" | "assistant", content }].
questionstringThe customer's message. Send it alone when the customer writes, and ProofMyAI alerts you if the bot never replies.
answerstringThe bot's reply to question.
bot_namestringOptional label when you run several bots.
latency_msintegerOptional: how long the reply took.
cost_usdnumberOptional: what the reply cost.
errorstringOptional: an error your bot hit while replying.
retrievedstring[]Optional (RAG bots): the text chunks your bot retrieved for this reply. When an answer is wrong, ProofMyAI says whether it was a retrieval problem (the right fact wasn't fetched), a generation problem (it was fetched and ignored) or missing documentation. Used for the check only, never stored.
trace_idstringOptional: your id for one end-to-end request (e.g. an order or ticket number). Send the same id to /check, /agent-runs, /workflow-runs, /approvals and /verify, then open Live tracking β†’ πŸ”— Traces to see every step on one timeline, with the first failing step highlighted. Kept up to 90 days (or your retention setting).

Send messages, or question + answer, or just question.

curl -X POST https://proofmyai.com/api/v1/chat-events \
  -H "Authorization: Bearer $PROOFMYAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "chat-8841",
    "question": "How much is shipping to Germany?",
    "answer": "Shipping to Germany is free on all orders.",
    "latency_ms": 1850
  }'

Response 202: {"accepted": 1}. Add ?wait=1 to wait for the verdicts (slower; useful for testing):

{"graded": 1, "results": [{"turn_index": 0, "verdict": "hallucination", "label": "Made up",
  "severity": "high", "reason": "The shipping article says Germany costs €9.90; free shipping is not mentioned."}]}

Verdicts: correct, unsupported (not in your docs), hallucination (made up), should_escalate, off_policy, unclear.

Tip: call the API without waiting for it (fire-and-forget) so your bot never slows down. The Live tracking page in your dashboard has ready-made cURL, JavaScript and Python snippets that do this safely, plus no-code steps for Intercom, Zendesk, Crisp and Tidio through n8n or Make.

πŸ›‘ POST /check: stop a bad answer before it's sent

The pre-send check (guardrail). Before your chatbot sends a reply, or before an AI agent acts on its decision (a refund, a discount, a booking), send the question and the draft reply. ProofMyAI checks it against your help docs and rules and answers in a few seconds. The answer is also monitored as usual.

curl -X POST https://proofmyai.com/api/v1/check   -H "Authorization: Bearer ap_live_your_key" -H "Content-Type: application/json"   -d '{"question": "Can I return a sale item for a refund?",
       "answer": "Yes, every item gets a full refund within 30 days."}'
{"decision": "block", "verdict": "hallucination", "label": "Made up", "severity": "high",
 "reason": "The returns article says sale items get store credit only.",
 "stated_as_fact": true,
 "source": "Returns & refunds",
 "evidence": "Sale items can be returned for store credit only, not a refund.",
 "area": "Returns & refunds", "area_autonomy": "human_review",
 "advice": "Do not send. Hand the customer to a person."}

evidence is the exact sentence from your help docs behind the verdict. A quote from the AI judge is only kept if it appears in your docs word for word, so the evidence is never made up. It's also shown on every checked answer in your dashboard and in the CSV export.

stated_as_fact is true when a wrong answer was said with full confidence ("Yes, all items…", a specific price or deadline, no hedge). Customers act on those without double-checking, so they are rated a level more serious. Such answers are marked "Stated as fact" in your dashboard.

FieldTypeDescription
allowdecisionSafe to send or act on.
reviewdecisionHold it for a person to approve, or send a safe fallback such as "Let me check that for you". Every answer in an area your Trust report marks πŸ”΄ returns review.
blockdecisionDon't send it: it's made up, against your policy, or should go to a human.

/chat-events?wait=1 also returns a decision for each reply. Each check counts as one conversation on your plan. If the check fails or times out, fall back to sending the reply as usual (or to a human for high-stakes actions).

πŸ§ͺ POST /test-runs: regression tests in your deploy pipeline

Changed a prompt, a model or your help docs? Run your saved Chatbot tests before the change goes live. ProofMyAI asks your bot every test question right now and answers with pass/fail per question. Point url at a preview or staging deployment to test a pull request. CI runs don't raise incidents and don't replace the nightly run.

FieldTypeDescription
botstring or numberName or id of the saved bot. Optional when the project has one bot.
urlstringOptional: test this address instead of the saved one (same body template and answer location).
min_pass_ratenumber 0–1Share of questions that must pass for ok to be true. Default 1 (all).
curl -X POST https://proofmyai.com/api/v1/test-runs \
  -H "Authorization: Bearer $PROOFMYAI_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://preview-42.yourbot.com/chat"}'

{"ok": false, "bot": "Support bot", "passed": 19, "failed": 1, "total": 20, "pass_rate": 0.95,
 "failures": [{"question": "Can I return a sale item?", "answer": "Yes, full refund.",
   "reason": "The answer contains a forbidden statement: \"full refund\"."}]}

GitHub Actions example: fail the build when answers get worse.

# .github/workflows/bot-tests.yml
name: Chatbot regression tests
on: [pull_request]
jobs:
  proofmyai:
    runs-on: ubuntu-latest
    steps:
      - name: Run ProofMyAI tests
        run: |
          RESULT=$(curl -s -X POST https://proofmyai.com/api/v1/test-runs \
            -H "Authorization: Bearer ${{ secrets.PROOFMYAI_KEY }}" -H "Content-Type: application/json" \
            -d '{"url": "${{ vars.PREVIEW_BOT_URL }}"}')
          echo "$RESULT"
          echo "$RESULT" | jq -e '.ok == true' > /dev/null

Limit: 30 test runs per project per hour. Each question is graded by the AI judge when AI checking is on, otherwise by the expected facts and forbidden phrases you saved.

βœ‹ POST /approvals: a person approves what matters

"Automate the draft, never the send." Before your agent does something important (issues a refund, emails a customer, pays an invoice, writes to your CRM), it submits the action. Routine, reversible actions come back approved straight away. These wait as pending until someone clicks Approve or Reject on the Approvals page (you get an alert):

curl -X POST https://proofmyai.com/api/v1/approvals   -H "Authorization: Bearer ap_live_your_key" -H "Content-Type: application/json"   -d '{"action": "refund", "summary": "Refund order #4471 for Sara K.", "amount": 89, "currency": "GBP",
       "category": "refunds", "reversible": false, "agent_name": "Support agent", "action_id": "refund-4471",
       "details": "Hi Sara, I have refunded Β£89 to your card. It will arrive within 5 days.",
       "callback_url": "https://your-n8n.example.com/webhook/approval"}'
{"id": 812, "action_id": "refund-4471", "status": "pending", "needs_human": true,
 "reason": "This can't be undone, so a person approves it first.", "commitments": ["a refund", "a deadline"],
 "poll_url": "https://proofmyai.com/api/v1/approvals/812"}

Then wait for the decision: ProofMyAI POSTs {"id", "action_id", "status", "decided_by", "note"} to your callback_url, or poll GET /approvals/812. Only act when status is approved. Requests expire after 24 hours (expires_in_hours). If the agent submits an action again after a person rejected it, it stays rejected and you get an alert. Every decision is logged with who decided, when and their note. In n8n: HTTP Request node β†’ Wait node (resume on webhook) β†’ IF status = approved.

Safety guarantees (each one is covered by an automated test that runs before every release):

πŸ”Ž Verify results: don't take the agent's word for it

Agents and workflows can report "done" when the CRM record never saved or the email never went out. Tell ProofMyAI where the result should be, and it checks the real system. If the result isn't there, it checks again 30 seconds later, then raises a high alert.

On an agent run, add verify to your /agent-runs body (checked about 10 seconds after the run):

"verify": {"url": "https://api.yourcrm.com/v1/leads/8812", "headers": {"Authorization": "Bearer crm_key"},
           "expect_text": "sara@shop.co", "delay_seconds": 10}

From any workflow (for example an n8n HTTP Request node after "Create record"):

curl -X POST https://proofmyai.com/api/v1/verify   -H "Authorization: Bearer ap_live_your_key" -H "Content-Type: application/json"   -d '{"name": "Lead sync", "reference": "lead 8812", "url": "https://api.yourcrm.com/v1/leads/8812",
       "headers": {"Authorization": "Bearer crm_key"}, "expect_text": "sara@shop.co"}'

Response: {"passed": false, "detail": "api.yourcrm.com answered 404. The record may not exist."}. Passes when the URL answers 2xx (or expect_status) and, if set, contains expect_text. Headers are used for the check only and are never stored. Only public URLs can be checked.

πŸ’“ Heartbeats: catch the job that never ran

Error handlers only fire when a job runs and fails. A cron that stopped, a dead server or a disabled trigger fails in silence. Add a heartbeat on the n8n & Make page, then call its URL at the end of the job:

curl -fsS https://proofmyai.com/api/hb/hb_your_token          # finished OK
curl -fsS "https://proofmyai.com/api/hb/hb_your_token/fail?msg=disk%20full"   # report a failure now

If the check-in doesn't arrive within the schedule plus a grace period (20%, at least 5 minutes), you get an alert. It clears on the next check-in. No API key is needed: the URL is the secret, so keep it private.

πŸ—‚οΈ CRM monitoring

Connect your CRM on the CRM page. It's read-only, and ProofMyAI stores only hashes and filled/empty flags, never names, emails or phone numbers. Direct connectors: HubSpot, Salesforce, Pipedrive, Zoho CRM, GoHighLevel, Freshsales, Close, ActiveCampaign and Microsoft Dynamics 365, checked every 15 minutes. You get alerts when new leads stop arriving (learned from your CRM's rhythm), new records miss an email/phone or owner, duplicates appear, hundreds of records change at once, leads aren't contacted in time, or the connection fails.

For any other CRM (Monday, Attio, Copper, Keap, Bitrix24, Odoo, Airtable…), send records from n8n, Make or Zapier when they are created or updated:

curl -X POST https://proofmyai.com/api/v1/crm-records   -H "Authorization: Bearer ap_live_your_key" -H "Content-Type: application/json"   -d '{"source": "Monday CRM", "records": [{"id": "123", "kind": "lead", "created_at": "2026-10-18T09:30:00Z",
       "updated_at": "2026-10-18T09:30:00Z", "email": "sara@shop.co", "phone": "+44 7700 900123",
       "name": "Sara K.", "owner": "Ali", "last_activity_at": null}]}'

Response 202: {"received": 1, "new": 1, "duplicates": 0}. Up to 500 records per call; kind is contact, lead or deal.

πŸ‘ POST /feedback: customer ratings

Send each thumbs up/down or star rating your customers give the bot. ProofMyAI shows customer satisfaction overall and per topic on the Analytics page. Use the same conversation_id you send to /chat-events.

curl -X POST https://proofmyai.com/api/v1/feedback   -H "Authorization: Bearer ap_live_your_key" -H "Content-Type: application/json"   -d '{"conversation_id": "chat-8812", "rating": "down", "comment": "Wrong delivery price"}'

rating: "up" / "down", true / false, whole stars 1–5, or a decimal score from 0 to 1. Optional: turn_index (which reply was rated) and comment. Response 201: {"ok": true, "id": 42}.

πŸ€– POST /agent-runs: AI agent monitoring

Send one request when an agent run finishes. ProofMyAI checks it for loops, tool errors, runaway cost, slow runs, empty output and answers the tools didn't support.

FieldTypeDescription
run_idstring, requiredUnique ID of this run. Sending the same run_id twice returns 409.
agent_namestring, requiredWhich agent ran, e.g. "refund-agent".
goalstringWhat the agent was asked to do.
statusstringsuccess (default), error, timeout or cancelled. Send running when the run starts (just run_id and agent_name) to be alerted if it never finishes.
final_outputstringThe agent's final answer or result.
stepsarrayEach step: { type: llm | tool | retrieval | other, name, input, output, error, duration_ms, tokens, cost_usd }.
curl -X POST https://proofmyai.com/api/v1/agent-runs \
  -H "Authorization: Bearer $PROOFMYAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "run_id": "run_2026_0412",
    "agent_name": "refund-agent",
    "goal": "Refund order #1043",
    "status": "success",
    "final_output": "Refund of $49 issued.",
    "steps": [
      {"type": "tool", "name": "lookup_order", "output": {"total": 49}, "duration_ms": 320},
      {"type": "tool", "name": "issue_refund", "error": "Payment API timeout", "duration_ms": 30000, "cost_usd": 0.002}
    ]
  }'

Response 201 (example):

{"id": 812, "score": 55, "issues": [
  {"code": "TOOL_ERRORS", "severity": "high", "message": "..."},
  {"code": "ENDED_ON_ERROR", "severity": "medium", "message": "The last step failed but the run still reported success."}]}

Issue codes: RUN_FAILED, TOOL_ERRORS, LOOP_DETECTED, TOO_MANY_STEPS, OVER_BUDGET, SLOW_RUN, EMPTY_OUTPUT, ENDED_ON_ERROR, DESTRUCTIVE_ACTION, plus from the AI review GOAL_NOT_MET and UNGROUNDED_OUTPUT. Set your step, cost and time limits in project Settings.

Destructive actions. Tool calls that delete, drop, wipe or overwrite data (a tool named delete_record or volumeDelete, DROP TABLE, DELETE FROM without WHERE, rm -rf, git push --force, an HTTP DELETE) are flagged DESTRUCTIVE_ACTION: high, with an alert, when they touch production, backups or everything at once. Send these actions to /approvals with reversible: false first. If a person approved one with the same trace_id, it is recorded but not alerted.

Agents that go quiet. ProofMyAI learns each agent's normal rhythm and alerts (AGENT_STOPPED) when it stops running, with no settings. To catch runs that start but never finish (hung, crashed, killed), send {"run_id": "...", "agent_name": "...", "status": "running"} when a run starts (answers 202), then the finished run with the same run_id. Starts with no result are alerted as AGENT_RUN_UNFINISHED.

πŸ“‘ OpenTelemetry traces (no code changes)

Already instrumented with OpenTelemetry, or using a framework that is (LangChain/LangGraph, CrewAI, OpenAI Agents SDK, LlamaIndex, Vercel AI SDK, or OpenLLMetry/OpenInference instrumentation)? Point the exporter at ProofMyAI with three environment variables. Each finished trace becomes an agent run with the same checks: failed steps, loops, runaway cost and latency, empty output, and step-by-step timing.

OTEL_EXPORTER_OTLP_ENDPOINT=https://proofmyai.com/api/v1/otel
OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer ap_live_your_key
OTEL_EXPORTER_OTLP_PROTOCOL=http/json

Spans that follow the OpenTelemetry GenAI conventions (gen_ai.*) or OpenInference (openinference.span.kind, input.value, output.value) become LLM, tool and retrieval steps, with tokens, timing and errors. The agent name comes from gen_ai.agent.name or your service.name. Send OTLP as JSON; protobuf isn't supported yet.

πŸ“ž POST /calls: voice bots and phone AI

Send each finished phone call. Every bot answer is checked like a chat reply, and the call is checked for the failure staff testing misses: the caller asked for a person and was never transferred, or the bot said it was transferring them and the transfer never happened.

FieldTypeDescription
call_idstring, requiredYour id for the call. Sending the same call twice is ignored.
transcriptarray or string[{ role: user | assistant, content }], or text like "AI: Hello\nUser: Hi".
transferredbooleanWhether the call was transferred to a person. If you can't tell, send ended_reason instead.
ended_reasonstringHow the call ended, e.g. customer-hung-up or call_transfer.
bot_namestringOptional: which voice bot.
duration_secondsnumberOptional.
curl -X POST https://proofmyai.com/api/v1/calls \
  -H "Authorization: Bearer $PROOFMYAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"call_id": "c_1029", "bot_name": "Front desk", "transferred": false,
       "transcript": [{"role": "assistant", "content": "Village offices, how can I help?"},
                      {"role": "user", "content": "Can I speak to someone in Parks and Recreation?"},
                      {"role": "assistant", "content": "Sure, transferring you now."}]}'

Response 201: {"call_id": "c_1029", "answers_checked": 2, "issues": [{"code": "CALL_NOT_TRANSFERRED", "severity": "high", ...}]}. Codes: CALL_NOT_TRANSFERRED (high, alerted) and TRANSFER_NOT_OFFERED (medium, when you don't send whether it transferred and the bot never offered to).

🀝 Promised follow-ups: "I'll get back to you"

A reply like "I'll check with the warehouse and get back to you" breaks no policy, so answer checks pass it. But it's a promise, and if no task exists behind it the customer just waits. ProofMyAI tracks every promise in live chats until it's kept:

Otherwise you get PROMISE_NOT_KEPT once the deadline passes (24 hours by default, set in Settings), and PROMISE_CHASED straight away if the customer writes "any update?" first. On /check, a reply that promises a follow-up without a task_id comes back as review, with promise and promise_has_task: false.

curl -X POST https://proofmyai.com/api/v1/followups \
  -H "Authorization: Bearer $PROOFMYAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"conversation_id": "chat_8812", "bot_name": "Website bot", "task_id": "odoo-task-4471"}'

Use the same conversation_id and bot_name you send to /chat-events. Send "status": "done" if the follow-up already happened.

βš™οΈ POST /workflow-runs: n8n, Make and Zapier

Most people connect n8n or Make with an API key instead (see above). Use this endpoint for Zapier, self-built pipelines, or to push runs yourself. Send one run or an array of up to 500.

FieldTypeDescription
workflow_idstring, requiredYour workflow or scenario ID.
execution_idstring, requiredUnique ID of this run (duplicates are ignored).
statusstring, requiredsuccess, error, warning, running, waiting, cancelled or crashed.
platformstringn8n, make, zapier or other (default).
workflow_namestringReadable name shown in alerts.
started_atISO 8601When the run started, with a time zone, e.g. 2026-09-29T10:15:00Z.
duration_msnumberHow long it took.
output_itemsintegerHow many items it produced. An empty "success" is flagged when it's unusual for this workflow (ProofMyAI learns its normal quiet spells).
input_itemsintegerHow many items it received, e.g. new orders fetched. 0 in and 0 out is a quiet run (no alert); items in but 0 out is a high alert.
error_messagestringThe error, if any.
retriesintegerOptional: extra attempts the run needed (e.g. a node that succeeded on its 3rd try). Workflows that need retries in 20%+ of runs get a RETRY_RATE_HIGH alert, because a success that needed retries hides a flaky step.
retry_ofstringOptional: the execution this run retries. n8n's own "Retry execution" re-runs are detected automatically.
curl -X POST https://proofmyai.com/api/v1/workflow-runs \
  -H "Authorization: Bearer $PROOFMYAI_KEY" \
  -H "Content-Type: application/json" \
  -d '[{"platform": "zapier", "workflow_id": "order-sync", "workflow_name": "Shopify β†’ Sheets",
        "execution_id": "ex_99121", "status": "success", "output_items": 0, "duration_ms": 2400}]'

Response 201: {"received": 1, "created": 1, "duplicates": 0}

⚠️ Errors & limits

StatusMeaning
400Invalid JSON or a missing/invalid field. The error field says which one.
401Missing or wrong API key, or the account is suspended.
402Your plan's monthly limit is reached. Upgrade under Plan & billing; nothing else breaks.
409An agent run with this run_id was already recorded.
413Body over 2 MB, or more than 500 workflow runs in one request.
429More than 600 requests per minute for one project. Retry after a short pause.

Errors look like {"error": "conversation_id: Required"}. A service health check is available at https://proofmyai.com/api/health, and live status at /status.

πŸ”’ Privacy & data

Emails, phone numbers, card numbers, IBANs, IP addresses and names are masked before storage or AI checks. Per project you can turn on results-only storage, set auto-delete, add your own words to mask, or switch AI checking off. Details in the Trust Center.

Stuck? Open a support ticket or message us on WhatsApp. See what's new in the changelog.

Docs & API reference Β· ProofMyAI