Example file
agent-tool-endpoint.mjs
Node: an endpoint for agent tools, with a policy lookup (GET) and a callback booking (POST), API key check and Idempotency-Key handling.
// An endpoint for a Subcontext agent tool, in Node 18 or later with no packages.
//
// It offers two operations you can add to a custom integration on Subcontext:
//
// GET /policies/{{ reference }} look up a policy (the agent sends date_of_birth too)
// POST /callbacks book a callback (the body comes from your body template)
//
// Subcontext sends your API key in the X-API-Key header (the integration's
// Auth type "Api key"). Writes carry an Idempotency-Key header that stays the
// same if the same tool call is sent again, so this file answers a repeat with
// the first answer instead of booking twice.
//
// Run it:
// SUBCONTEXT_TOOL_KEY=A_LONG_RANDOM_VALUE node agent-tool-endpoint.mjs
// Subcontext only calls https addresses on the public internet, so put it
// behind your usual HTTPS web server or load balancer.
import { createServer } from "node:http";
import { randomUUID, timingSafeEqual } from "node:crypto";
// The value you store as a secret variable on the integration in Subcontext.
const API_KEY = process.env.SUBCONTEXT_TOOL_KEY;
const PORT = Number(process.env.PORT || 4100);
if (!API_KEY) throw new Error("Set SUBCONTEXT_TOOL_KEY to the API key Subcontext sends.");
// Stand-ins for your own systems.
const POLICIES = {
"POL-1001": { date_of_birth: "1980-04-12", status: "active", renewal_date: "2027-03-01", monthly_premium: "18.40" },
};
const answeredWrites = new Map(); // Idempotency-Key -> the answer we gave
function send(res, status, body) {
res.writeHead(status, { "Content-Type": "application/json" });
res.end(JSON.stringify(body));
}
function keyMatches(given) {
const a = Buffer.from(String(given || ""));
const b = Buffer.from(API_KEY);
return a.length === b.length && timingSafeEqual(a, b);
}
async function readJson(req) {
let raw = "";
for await (const chunk of req) raw += chunk;
if (raw.length > 100_000) throw new Error("too large");
return raw ? JSON.parse(raw) : {};
}
const server = createServer(async (req, res) => {
// 1. Check the key. A 401 tells Subcontext the credentials are wrong.
if (!keyMatches(req.headers["x-api-key"])) {
return send(res, 401, { error: "Unknown API key." });
}
const url = new URL(req.url, "http://localhost");
// 2. A read: GET /policies/POL-1001?date_of_birth=1980-04-12
const lookup = url.pathname.match(/^\/policies\/([^/]+)$/);
if (req.method === "GET" && lookup) {
const reference = decodeURIComponent(lookup[1]).toUpperCase();
const policy = POLICIES[reference];
// Ask for something only the customer knows before giving anything away.
if (!policy || policy.date_of_birth !== url.searchParams.get("date_of_birth")) {
// The agent sees this status and message, so make the message useful.
return send(res, 404, { error: "No policy matches that reference and date of birth. Ask the customer to check both." });
}
// Small, flat and only what the agent needs to answer.
return send(res, 200, {
reference,
status: policy.status,
renewal_date: policy.renewal_date,
monthly_premium: policy.monthly_premium,
});
}
// 3. A write: POST /callbacks with the body your template builds.
if (req.method === "POST" && url.pathname === "/callbacks") {
const idempotencyKey = req.headers["idempotency-key"];
if (idempotencyKey && answeredWrites.has(idempotencyKey)) {
const first = answeredWrites.get(idempotencyKey);
return send(res, first.status, first.body);
}
let body;
try {
body = await readJson(req);
} catch {
return send(res, 400, { error: "The request body wasn't valid JSON." });
}
if (!body.phone) {
return send(res, 422, { error: "A phone number is needed to book a callback. Ask the customer for one." });
}
const answer = {
status: 201,
body: {
callback_id: randomUUID(),
message: `Callback booked for ${body.preferred_time || "the next available slot"}.`,
},
};
if (idempotencyKey) answeredWrites.set(idempotencyKey, answer);
return send(res, answer.status, answer.body);
}
send(res, 404, { error: "No such operation." });
});
server.listen(PORT, () => console.log(`Agent tool endpoint on http://localhost:${PORT}`));