@nuvouch/node
v0.2.1
Published
A complete TypeScript Node SDK for Nuvouch.
Readme
@nuvouch/node
A complete TypeScript Node SDK for Nuvouch.
Install
npm install @nuvouch/nodeQuick Start
import { ApprovalActionTypes, Nuvouch, RiskSignals } from "@nuvouch/node";
const nuvouch = new Nuvouch({
apiKey: process.env.NUVOUCH_API_KEY,
});
const approval = await nuvouch.approvals.create(
{
subject: { id: 'user_123' },
source: { key: 'stripe:acct_live_001', name: 'Stripe' },
action: {
type: ApprovalActionTypes.PAYMENT_AUTHORIZATION,
title: 'Approve payment',
description: 'Allow Billing Agent to charge $84.00 for OpenAI API usage.',
},
amount: { value: 84, currency: 'USD' },
details: [
{ label: 'Merchant', value: 'OpenAI API' },
{ label: 'Billing period', value: 'April 2026' },
],
review: {
items: [
{
type: 'text',
title: 'Agent note',
body: 'Billing Agent found usage above the configured threshold and needs approval before charging the card.',
},
{
type: 'link',
label: 'Review checkout',
url: 'https://checkout.example.com/session/payment_auth_2026_0001',
description: 'Open the payment page before approving.',
purpose: 'payment',
requiredBeforeApproval: true,
},
],
},
actor: { type: 'ai_agent', id: 'agent_billing_001', name: 'Billing Agent' },
risk: {
level: 'medium',
summary: 'Automated payment above normal approval threshold.',
signals: [RiskSignals.AUTOMATED_ACTION, RiskSignals.USAGE_THRESHOLD_EXCEEDED],
},
decisions: [
{ label: 'Approve', value: 'approve' },
{ label: 'Deny', value: 'deny' },
],
postDecision: {
approved: {
message: 'Payment approved. Continue to checkout if confirmation is required.',
actions: [
{
type: 'open_url',
label: 'Continue checkout',
url: 'https://checkout.example.com/session/payment_auth_2026_0001',
},
],
},
},
metadata: { invoiceId: 'inv_123', orderId: 'ord_456' },
externalRequestId: 'payment_auth_2026_0001',
},
{ idempotencyKey: 'payment_auth_2026_0001' },
);
console.log("Approval created:", approval.id);Features
- Typed Requests & Responses: Full TypeScript support for all API resources.
- Webhook Verification: Securely verify Nuvouch webhook signatures.
- Idempotency: Built-in support for idempotency keys.
- Connection Sessions: Easy management of user connection sessions.
- Agent Auth: Pair agent runtimes, request tool-scoped delegation, and introspect opaque delegation tokens.
- Agent Payments: Build merchant manifests, sign checkout/payment intents, and submit Nuvouch payment reviews.
Agent Auth Runtime Example
import {
buildAgentAuthDelegationRequestPayload,
buildAgentAuthRuntimeClaimPayload,
createAgentAuthRuntimePairingRequest,
NuvouchAgentAuthRuntimeClient,
signAgentAuthRuntimePayload,
} from "@nuvouch/node";
const runtime = new NuvouchAgentAuthRuntimeClient();
const pairing = createAgentAuthRuntimePairingRequest({
applicationId: "app_openclaw",
runtimeDisplayName: "OpenClaw Desktop",
});
// Render pairing.qrData as a QR code. The user scans it in Nuvouch mobile
// and gives the generated code back to the runtime.
const code = "NVP1-...";
const claimPayload = buildAgentAuthRuntimeClaimPayload({ code });
const connection = await runtime.claimConnection({
code,
publicKeyFingerprint: pairing.publicKeyFingerprint,
signature: signAgentAuthRuntimePayload({
privateKey: pairing.keyPair.privateKey,
keyAlgorithm: pairing.keyPair.keyAlgorithm,
payload: claimPayload,
}),
});
const nonce = crypto.randomUUID();
const delegationPayload = buildAgentAuthDelegationRequestPayload({
runtimeConnectionId: connection.id,
audienceId: "aud_test_payments",
agentId: "agent_billing",
purpose: "Identify the user before preparing a payment approval",
scopes: ["payments.identity", "payments.prepare"],
nonce,
});
const delegation = await runtime.requestDelegation({
runtimeConnectionId: connection.id,
audienceId: "aud_test_payments",
agent: { id: "agent_billing", name: "Billing Agent" },
purpose: "Identify the user before preparing a payment approval",
scopes: ["payments.identity", "payments.prepare"],
nonce,
signature: signAgentAuthRuntimePayload({
privateKey: pairing.keyPair.privateKey,
keyAlgorithm: pairing.keyPair.keyAlgorithm,
payload: delegationPayload,
}),
});Agent Auth Provider Example
import { Nuvouch } from "@nuvouch/node";
const nuvouch = new Nuvouch({ apiKey: serverSideNuvouchApiKey });
const delegation = await nuvouch.agentAuth.provider.requireDelegation({
token: req.headers.authorization?.replace(/^Bearer\s+/i, "") ?? "",
audienceKey: "stripe:payments",
requiredScopes: ["payments.prepare"],
});
const localAccount = await mapScopedSubjectToLocalAccount(delegation.subject);
const approval = await nuvouch.approvals.create({
targetSubject: { subjectId: delegation.subject },
subject: { id: localAccount.id },
source: { key: "stripe:payments", name: "Stripe Payments" },
action: {
type: "payment.prepare",
title: "Approve payment",
description: "Allow Stripe Payments to prepare the requested payment.",
},
actor: { type: "ai_agent", id: delegation.agent.id, name: delegation.agent.name },
decisions: [
{ label: "Approve", value: "approve" },
{ label: "Deny", value: "deny" },
],
agentAuth: nuvouch.agentAuth.provider.buildAgentAuthApprovalContext(delegation),
});Agent Auth delegation proves identity and user-approved delegation for a tool audience. It does not authorize the final action; the tool provider still owns the final approval request and execution.
Provider MCPs can also run and upload the reusable conformance harness:
import { runAgentAuthProviderConformance } from "@nuvouch/node";
const run = await runAgentAuthProviderConformance({
checks: {
missingTokenDenied: async () => true,
inactiveTokenDenied: async () => true,
wrongScopeDenied: async () => true,
wrongAudienceDenied: async () => true,
activeDelegationAccepted: async () => true,
finalApprovalRequiredNotExecuted: async () => true,
scopedSubjectUsed: async () => true,
},
});
await nuvouch.agentAuth.provider.submitConformanceRun(run);Agent Payments Merchant Example
import {
Nuvouch,
buildPaymentJwks,
buildPaymentManifest,
buildSignedCheckoutIntent,
buildSignedPaymentIntent,
createPaymentSigningKeyPair,
verifyPaymentIntentCallback,
} from "@nuvouch/node";
const nuvouch = new Nuvouch({ apiKey: process.env.NUVOUCH_API_KEY });
const keyPair = createPaymentSigningKeyPair({ kid: "pay_live_2026_01" });
export const manifest = buildPaymentManifest({
merchantId: "mer_cloth_001",
displayName: "Cloth Store",
domain: "clothstore.com",
environment: "sandbox",
jwksUrl: "https://clothstore.com/.well-known/nuvouch-jwks.json",
checkoutIntentUrl: "https://clothstore.com/api/nuvouch/checkout-intents",
paymentIntentCallbackUrl: "https://clothstore.com/api/nuvouch/payment-intents",
});
export const jwks = buildPaymentJwks([{ kid: keyPair.kid, publicKey: keyPair.publicKey }]);
const signedCheckout = buildSignedCheckoutIntent({
id: "chk_123",
merchant: { id: manifest.merchantId, domain: "clothstore.com" },
orderReference: "ord_123",
previewUrl: "https://clothstore.com/checkout/preview/chk_123",
amount: { value: "42.00", currency: "USD" },
lineItems: [{ name: "Linen shirt", quantity: 1, amount: { value: "42.00", currency: "USD" } }],
cartHash: "sha256-cart-hash",
kid: keyPair.kid,
privateKey: keyPair.privateKey,
});
await nuvouch.payments.submitCheckoutIntentForReview(signedCheckout, {
idempotencyKey: signedCheckout.checkoutIntent.id,
});
const callback = verifyPaymentIntentCallback({
rawBody: req.rawBody,
signature: req.headers["x-nuvouch-signature"],
secret: process.env.NUVOUCH_PAYMENT_CALLBACK_SECRET,
});
const signedPaymentIntent = buildSignedPaymentIntent({
id: "pi_123",
checkoutIntentId: callback.checkoutIntentId,
amount: signedCheckout.checkoutIntent.amount,
cartHash: callback.approvedCartHash,
lineItems: signedCheckout.checkoutIntent.lineItems,
taxes: signedCheckout.checkoutIntent.taxes,
fees: signedCheckout.checkoutIntent.fees,
processor: { provider: "stripe", paymentId: "pi_processor_123" },
kid: keyPair.kid,
privateKey: keyPair.privateKey,
});The final payment intent should be created by the merchant server after Nuvouch has approved the checkout preview. Do not expose processor credentials or reusable payment credentials to the agent runtime.
Webhooks
import { Nuvouch } from "@nuvouch/node";
const nuvouch = new Nuvouch({ apiKey: "..." });
// In your webhook handler:
try {
const event = nuvouch.webhooks.verify({
rawBody: req.body, // Raw string or Buffer
signature: req.headers["x-nuvouch-signature"],
secret: process.env.NUVOUCH_WEBHOOK_SECRET,
});
console.log("Verified event:", event.type, event.deliveryId);
// Use type guards to safely access strongly-typed data payloads
if (nuvouch.webhooks.isApprovalEvent(event)) {
console.log("Approval Status:", event.data.approvalRequest.status);
} else if (nuvouch.webhooks.isPaymentEvent(event) && event.type === "nuvouch.payment.completed") {
console.log("Stripe payment:", event.data.processor?.paymentIntentId, event.data.amount);
}
} catch (err) {
console.error("Invalid signature:", err.message);
}Documentation
For more information, visit the Nuvouch Documentation.
