§ Guide · Integration flow
End-to-end payment authorization walkthrough
This guide follows one payment authorization from subject linking to callback completion. IDs and payload fields are identical to the SDK and API reference pages so teams can compare approaches without rewriting integration logic.
scenario
business contextintegrator: Stripe
customer: Ada Lovelace
subjectId: cus_123
contextKey: merchant:acct_live_001
paymentIntent: pi_123
amount: $84.00
externalRequestId: payment_auth_001§ Step 0
Link the customer to Nuvouch once
Create connection session
node sdk
import { Nuvouch } from "@nuvouch/node";
const nuvouch = new Nuvouch({ apiKey: process.env.NUVOUCH_API_KEY });
const link = await nuvouch.links.create({
subject: {
id: "cus_123",
label: "Ada Lovelace",
},
source: {
key: "merchant:acct_live_001",
name: "Stripe Live Account",
},
});
await showConnectionPrompt({
url: link.url,
shortCode: link.shortCode,
expiresAt: link.expiresAt,
});§ Step 1
Create approval request
Create approval request
node sdk
const approval = await nuvouch.approvals.create({
subject: { id: "user_123" },
source: { key: "stripe:acct_123", name: "Stripe" },
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: "April 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" }
],
metadata: {
orderId: "ord_123"
},
externalRequestId: "payment_auth_001"
});§ Step 2
Read request state only when needed
Read current request state
node sdk
const current = await nuvouch.approvals.retrieveByExternalId("payment_auth_001");
if (current.status === "pending") {
// diagnostic or operator view only
}§ Step 3
Process signed callback safely
Verify and process webhook
sdk helper
const rawBody = await req.text();
const event = nuvouch.webhooks.verify({
rawBody,
signature: req.headers.get("x-nuvouch-signature"),
secret: process.env.NUVOUCH_CALLBACK_SECRET!,
});
const deliveryId = req.headers.get("x-nuvouch-delivery");
if (deliveryId && await alreadyProcessed(deliveryId)) {
return new Response("duplicate", { status: 200 });
}
if (nuvouch.webhooks.isApprovalEvent(event) && event.data.approvalRequest.externalRequestId === "payment_auth_001") {
if (event.data.approvalRequest.status === "approved") {
await capturePaymentIntent("pi_123");
} else if (event.data.approvalRequest.status === "denied") {
await markPaymentAuthorizationDenied("pi_123");
}
}
if (deliveryId) await markProcessed(deliveryId);
return new Response("ok");§ Step 4
Handle cancellation and retries
Cancel pending request
node sdk
await nuvouch.approvals.cancel("req_2f5cd6dbb6784b9ab2f7");- If callbacks are temporarily failing, Nuvouch retries automatically with backoff.
- Return 2xx only after persisting event and dedupe key.
- Use external payment authorization IDs as your reconciliation join key.
§ Next
Related references
Go deeper with SDK reference, HTTP API reference, and webhook reference.