Stripe

Stripe

Gate AI-managed Stripe operations — refunds, payouts, subscription changes, charge disputes — behind a human approval step before the Stripe API call executes.

Prerequisites

  • Stripe account with server-side API access.
  • Cheqpoint Connection Key.

Steps

  1. Identify AI-driven Stripe operations that need human review (refunds, payouts, subscription cancellations).
  2. In your server-side code, initialise the Cheqpoint client with your Connection Key.
  3. Before calling the Stripe API, call cheq.requestSync() with the transaction details in details.
  4. If approved, proceed with the Stripe API call using the effective payload (prefer modifiedDetails to allow reviewers to adjust amounts).
  5. If rejected, log the decision and return an appropriate error or message to the caller.
  6. For high-volume systems, use requestAsync() with a callbackUrl to avoid blocking the payment flow.

Installation

bash
npm install @cheqpoint/sdk stripe

Sample request payload

json
{
  "action": "issue_refund",
  "summary": "AI agent requesting full refund for charge ch_3NxYz for $349.00",
  "details": {
    "charge_id": "ch_3NxYzAbCdEfGhIjK",
    "amount_cents": 34900,
    "currency": "usd",
    "reason": "duplicate",
    "customer_id": "cus_QaAbCdEfGhIjK"
  },
  "justification": "Customer provided proof of duplicate charge within dispute window."
}

Sample Cheqpoint response

json
{
  "status": "approved",
  "modifiedDetails": {
    "amount_cents": 17450
  },
  "decisionNote": "Approved partial refund only — 50% per policy for this dispute reason."
}

Node.js — requestSync() before Stripe refund

javascript
import Stripe from "stripe";
import { CheqpointClient } from "@cheqpoint/sdk";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const cheq = new CheqpointClient({ apiKey: process.env.CHEQPOINT_CONNECTION_KEY! });

async function issueAIRefund(chargeId: string, amountCents: number, reason: string) {
  const result = await cheq.requestSync({
    action: "issue_refund",
    summary: `AI agent requesting refund for charge ${chargeId}`,
    details: { charge_id: chargeId, amount_cents: amountCents, reason },
    timeoutMs: 60_000,
  });

  if (result.status === "approved") {
    // Use modified amount if reviewer changed it
    const effectiveAmount = result.modifiedDetails?.amount_cents ?? amountCents;
    return await stripe.refunds.create({
      charge: chargeId,
      amount: effectiveAmount as number,
      reason: reason as Stripe.RefundCreateParams.Reason,
    });
  }

  if (result.status === "rejected") {
    throw new Error(`Refund rejected: ${result.decisionNote ?? "no reason given"}`);
  }

  // status === "pending" — decision still awaiting
  return { status: "pending", approvalId: result.approvalId };
}

Async pattern with callbackUrl

javascript
// For high-volume or time-sensitive payment flows, fire-and-forget:
const result = await cheq.requestAsync({
  action: "issue_refund",
  summary: `AI agent requesting refund for charge ${chargeId}`,
  details: { charge_id: chargeId, amount_cents: amountCents },
  // Cheqpoint will POST the final decision here when a reviewer decides:
  callbackUrl: "https://api.yourapp.com/webhooks/cheqpoint-decision",
});

// result.status === "pending"  → queued for review
// result.status === "approved" → auto-approved by a rule (no human wait)
// result.approvalId            → use for tracking

Notes

Always prefer modifiedDetails over the original payload — reviewers may adjust refund amounts, currency, or reason codes before approving.

Tips

Gate all AI-initiated financial operations, but allow read-only Stripe queries (balance, charge lookup) to pass through without review.

Get your Connection Key at cheqpoint.co/signup.