Build your first approval
This is the shortest path to a real Nuvouch loop: your server creates an approval, Nuvouch asks the user, your webhook verifies the callback, and your app executes only after approval.
Use Nuvouch for approval infrastructure
Nuvouch is for AI agent platforms, payment and fintech platforms, API platforms with dangerous actions, and enterprise workflow tools that need a durable user decision before execution.
Install the SDK
npm install @nuvouch/nodeNUVOUCH_API_KEY=itg_live_xxxxx
NUVOUCH_CALLBACK_SECRET=nuvouch_live_callback_secret
NUVOUCH_WEBHOOK_URL=https://your-app.example.com/webhooks/nuvouchCreate an approval
import { Nuvouch } from "@nuvouch/node";
const nuvouch = new Nuvouch({
apiKey: process.env.NUVOUCH_API_KEY,
});
const externalRequestId = "payment_auth_001";
const approval = await nuvouch.approvals.create({
subject: {
id: "cus_123",
label: "Ada Lovelace",
},
source: {
key: "merchant:acct_live_001",
name: "Stripe Live Account",
},
action: {
type: "payment.authorization",
title: "Approve payment",
description: "Allow Billing Agent to charge $84.00",
},
amount: {
value: 84.0,
currency: "USD",
},
details: [
{ label: "Merchant", value: "OpenAI API" },
{ label: "Billing period", value: "May 2026" },
],
actor: {
type: "ai_agent",
name: "Billing Agent",
},
risk: {
level: "medium",
signals: ["automated_action", "usage_threshold_exceeded"],
},
decisions: [
{ label: "Approve", value: "approve" },
{ label: "Deny", value: "deny" },
],
externalRequestId,
metadata: {
paymentIntentId: "pi_123",
},
});
console.log(approval.id, approval.status);Use subject for the user or customer, source for the product/account/provider origin, actor for the agent or system initiating the action, and externalRequestId as your durable retry key.
Verify the webhook locally
For local development, expose your webhook with a tunnel and set that URL in the integrator console, for example https://your-tunnel.ngrok-free.app/webhooks/nuvouch.
import { Nuvouch } from "@nuvouch/node";
const nuvouch = new Nuvouch({ apiKey: process.env.NUVOUCH_API_KEY });
app.post(
"/webhooks/nuvouch",
express.raw({ type: "application/json" }),
async (req, res) => {
const rawBody = req.body.toString("utf8");
const event = nuvouch.webhooks.verify({
rawBody,
signature: req.header("x-nuvouch-signature"),
secret: process.env.NUVOUCH_CALLBACK_SECRET!,
});
if (await hasProcessed(event.deliveryId)) {
return res.status(200).send("duplicate");
}
await saveEvent(event.deliveryId, event);
res.status(200).send("ok");
},
);Execute only after approval
const event = await nextSavedNuvouchEvent();
if (event.type !== "nuvouch.approval_request.approved") {
await markBusinessRequestBlocked(event.data.approvalRequest.externalRequestId);
return;
}
const requestId = event.data.approvalRequest.externalRequestId;
const paymentIntentId = event.data.approvalRequest.metadata?.paymentIntentId;
await runOnce(requestId, async () => {
await capturePayment(paymentIntentId);
});After this loop works, continue to getting started for production setup and integration guide for the full payment authorization walkthrough.