Search documentation

Search documentation

Framework Integration

Pillar Cloud sends tool calls to your server via HTTP POST. The SDK provides built-in adapters for popular frameworks — each adapter reads the request body and headers, delegates to pillar.handle(), and sends back the response.

TypeScript frameworks

Express

server.ts
import express from 'express';
import { pillar } from './pillar-tools';
const app = express();
app.use(express.json());
app.post('/pillar', pillar.expressHandler());
app.listen(3000, () => {
console.log('Pillar webhook listening on port 3000');
});

Express must parse the raw JSON body. Make sure express.json() middleware is applied before the Pillar route.

Fastify

server.ts
import Fastify from 'fastify';
import { pillar } from './pillar-tools';
const fastify = Fastify();
fastify.post('/pillar', pillar.fastifyHandler());
fastify.listen({ port: 3000 }, () => {
console.log('Pillar webhook listening on port 3000');
});

Hono

server.ts
import { Hono } from 'hono';
import { pillar } from './pillar-tools';
const app = new Hono();
app.post('/pillar', pillar.honoHandler());
export default app;

Next.js (App Router)

app/api/pillar/route.ts
// app/api/pillar/route.ts
import { pillar } from '@/lib/pillar-tools';
export const POST = pillar.nextHandler();

The nextHandler() adapter works with the standard Web Request / Response API used by Next.js App Router route handlers.

Standalone

If you don't use a framework, the SDK can start its own HTTP server:

server.ts
import { Pillar, defineTool } from '@pillar-ai/server';
import { z } from 'zod';
const pillar = new Pillar({
secret: process.env.PILLAR_SECRET!,
endpointUrl: 'https://api.myapp.com/pillar',
});
const ping = defineTool({
name: 'ping',
description: 'Health check',
input: z.object({}),
execute: async () => ({ pong: true }),
});
await pillar.registerTools([ping]);
pillar.serve({ port: 8787 });

This starts a plain Node.js HTTP server on the specified port. All POST requests are dispatched to pillar.handle().

Python frameworks

Django

urls.py
# urls.py
from django.urls import path
from myapp.pillar_tools import pillar
urlpatterns = [
path("pillar/", pillar.django_view()),
]

The Django adapter returns a CSRF-exempt async view. It reads request.body and the X-Pillar-Signature header automatically.

Flask

app.py
# app.py
from flask import Flask
from myapp.pillar_tools import pillar
app = Flask(__name__)
app.route("/pillar", methods=["POST"])(pillar.flask_handler())

The Flask adapter wraps the async handle() method in asyncio.run() so it works with Flask's synchronous request handling.

FastAPI

main.py
# main.py
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from myapp.pillar_tools import pillar
app = FastAPI()
@app.post("/pillar")
async def pillar_endpoint(request: Request):
body = await request.body()
headers = {"X-Pillar-Signature": request.headers.get("x-pillar-signature", "")}
result, status_code = await pillar.handle(body, headers)
return JSONResponse(result, status_code=status_code)

FastAPI doesn't have a built-in adapter method — call pillar.handle() directly in your route handler. This gives you full control over the request/response lifecycle.

Standalone

server.py
from pillar import Pillar, ToolContext
pillar = Pillar(secret="plr_...")
@pillar.tool(description="Health check")
async def ping(ctx: ToolContext) -> dict:
return {"pong": True}
pillar.serve(port=8787)

This starts a blocking HTTP server using Python's standard library. All POST requests are dispatched to pillar.handle().

Custom integration

If your framework isn't listed, you can call pillar.handle() directly. It accepts a raw body (string or bytes) and a headers dict, and returns a tuple of [result, statusCode]:

typescript
// TypeScript
const [result, statusCode] = await pillar.handle(rawBody, {
'x-pillar-signature': signatureHeader,
});
// Send `result` as JSON with `statusCode`
python
# Python
result, status_code = await pillar.handle(raw_body, {
"X-Pillar-Signature": signature_header,
})
# Return result as JSON with status_code

Next steps