How it works

Cheqpoint blocks AI agent actions before they execute and routes them to a human reviewer. The SDK call blocks - the agent waits - and only fires when a human approves.

1. AI agent calls cheqpoint.guard() or checkpoint()

SDK
Your AI agent submits an action via the SDK. The call blocks until a human decides or a timeout occurs. The action code runs only on approval - it cannot fire on a decline.

2. Cheqpoint routes to a reviewer

Routing
Based on your workspace rules, the request is assigned to a Review Group and its inbox. Reviewers are notified via Slack, email, Teams, or Discord within seconds.

3. Human decides

Review
The reviewer sees full context - action, request details, AI reasoning, risk score - and approves, declines, or modifies the payload. A two-step confirmation prevents accidental submits.

4. Decision returns to the AI agent

Execution
The SDK receives the decision. If approved, the agent continues with the effective payload (original or modified). All actions are logged to the immutable audit trail.

How the risk score gets set

The riskScore is a float from 0.0 (low risk) to 1.0 (critical). It controls which rule branch fires and what reviewers see. You set it in one of two ways.

Option A - LLM assessment (tool schema)

When the AI agent calls Cheqpoint as a tool (OpenAI function calling, Vercel AI SDK tool, LangChain tool), the tool schema instructs the model to self-assess:

openai schema excerpt
// From sdk/js/src/openai-schema.ts
riskScore: {
  type: "number",
  description:
    "Risk score 0.0–1.0. Low (0.1–0.3): small refund, established customer. " +
    "High (0.7–0.9): large amount, new account, or suspicious pattern.",
}

Option B - Deterministic calculation in your code

Your backend computes the score from business rules before calling the SDK. This is the most predictable approach for financial workflows.

typescript
const riskScore =
  orderAmount > 10000   ? 0.8  // large refund
  : customerAgeDays < 7 ? 0.7  // new account
  : 0.2;                        // standard case

await cheqpoint.guard(
  {
    action: "process_refund",
    riskScore,
    summary: `Refund £${orderAmount / 100} for Order #${orderId}`,
    details: { orderId, amount: orderAmount, customerEmail },
  },
  async (ctx) => {
    // Runs ONLY on approval - ctx.details contains any reviewer edits
    await stripe.refunds.create(ctx.details);
  },
);

End-to-end example: customer refund

A customer reports a damaged item and asks for a £125 refund. Here is the complete request lifecycle from chat message to money movement.

1

Customer asks for a refund

Customer: "My item for Order #ORD-4821 arrived damaged. I want a £125 refund." The AI checks the DB - order confirmed, delivered yesterday, no prior refunds.

2

AI assesses risk and calls the SDK

The AI determines this action involves real-world funds. Instead of calling Stripe directly, it calls cheqpoint.guard() with riskScore: 0.65, summary, and order details as the payload. The backend thread blocks here.

3

Rules engine evaluates the request

Cheqpoint receives POST /api/approvals/request. Rules run: amount £125 + risk 0.65 doesn't match the auto-approve rule (amount < £20 AND risk < 0.3). Request status → PENDING, routed to Support Leads queue.

4

AI tells the customer it's in review

While polling in the background, the chatbot responds: "I've submitted your £125 refund for review (ref #req_9182). You'll hear back shortly." The customer is not left waiting in silence.

5

Reviewer approves in the inbox or Slack

A Team Lead sees the request in their inbox or Slack notification. They see: action summary, order history, the AI's justification, and the 0.65 risk score. They click Approve (or modify the amount to £100 first, then approve).

6

Action executes - SDK unblocks

Cheqpoint sets status APPROVED. The SDK receives the decision and unblocks. The guard() callback runs with ctx.details = modifiedDetails ?? original details. stripe.refunds.create() fires. Confirmation email goes to the customer. Audit trail records everything.

The request lifecycle

Every request follows this path. Auto-approve rules short-circuit the human step for low-risk actions; everything else reaches a reviewer.

🤖AI agent→SDK call (guard / checkpoint)
📤SDK→POST /api/approvals/request
⚖️Rules engine→Auto-approve OR route to queue
🔔Notification→Slack / email / Teams / Discord
👤Human decision→Approve / Decline / Modify
✅SDK unblocks→Action executes (approved only)
📋Audit trail→Immutable log - who, what, when, why

Quick Decisions

For teams that move fast, the approval inbox supports a Quick Decisions mode. Toggle it on with the switch in the top-right of the decision panel. With Quick Decisions enabled:

  • Approve - one click, no reason required. The decision is submitted immediately.
  • Decline - opens a minimal note field (optional) and a single confirm button.

Your Quick Decisions preference is saved per browser. You can switch back to the full reason-picker flow at any time. Quick Decisions is ideal for high-volume inboxes where reviewers already have context.

System Health Check

The Developer → System Health Check lets you verify every configured integration in one click. It tests the approval flow, your Connection Key, email, Slack, Teams, Discord, Zapier, n8n, PagerDuty, Linear, and Jira in parallel and shows a pass/fail with latency for each. Use it after initial setup or whenever you change a configuration.