Cookbook
Multi-tenant SaaS
Scope every SDK call to the logged-in user with one line of code.
In a multi-tenant SaaS, each end-user may have connected their own integrations. The Vendo SDK provides a single method — forRequest / forUser — to scope all SDK calls to a specific user's context.
Architecture
Client → [X-Vendo-User-JWT header] → Your API → forRequest(headers) → Vendo credentials service
↓
User's OAuth tokensThe JWT is issued by Vendo when the user logs in. Pass it on every API request and the SDK extracts it automatically.
This pattern requires Vendo mode (VENDO_API_KEY must be set).
Request handler
from fastapi import FastAPI, Request
from vendo import Vendo
app = FastAPI()
_vendo = Vendo() # created once at startup
@app.post("/api/summarize")
async def summarize(request: Request, body: dict):
# Scope the client to the authenticated user
client = _vendo.for_request(request.headers)
# All subsequent calls use this user's connections
openai_key = client.token("openai")
google_token = client.token("google")
return {"openai_key": openai_key[:8] + "..."}import express from "express";
import { Vendo } from "@vendodev/sdk";
const app = express();
const vendo = new Vendo(); // created once at startup
app.post("/api/summarize", express.json(), async (req, res) => {
try {
// Scope the client to the authenticated user
const client = vendo.forRequest(req.headers);
// All subsequent calls use this user's connections
const openaiKey = await client.token("openai");
const googleToken = await client.token("google");
res.json({ status: "ok" });
} catch (e) {
res.status(400).json({ error: String(e) });
}
});import Vapor
import Vendo
let vendo = try Vendo() // created once at startup
func summarizeHandler(_ req: Request) async throws -> Response {
let headers = Dictionary(
uniqueKeysWithValues: req.headers.map { ($0.name.description, $0.value) }
)
// Scope the client to the authenticated user
let client = try vendo.forRequest(headers: headers)
// All subsequent calls use this user's connections
let openaiKey = try await client.token("openai")
let googleToken = try await client.token("google")
return Response(status: .ok)
}Background jobs
When the JWT comes from a queue message or job payload rather than live request headers:
from vendo import Vendo
_vendo = Vendo()
async def process_export_job(user_jwt: str, export_id: str):
client = _vendo.for_user(user_jwt)
google_token = client.token("google")
# Export data using user's Google token ...import { Vendo } from "@vendodev/sdk";
const vendo = new Vendo();
async function processExportJob(userJwt: string, exportId: string) {
const client = vendo.forUser(userJwt);
const googleToken = await client.token("google");
// Export data using user's Google token ...
}import Vendo
func processExportJob(userJwt: String, exportId: String) async throws {
let client = vendo.forUser(jwt: userJwt)
let googleToken = try await client.token("google")
// Export data using user's Google token ...
}Handling missing JWT
from vendo.errors import IdentityNotPresent
try:
client = _vendo.for_request(request.headers)
except IdentityNotPresent:
# Missing X-Vendo-User-JWT header — user is not authenticated
return {"error": "authentication required"}, 401import { IdentityNotPresent } from "@vendodev/sdk";
try {
const client = vendo.forRequest(req.headers);
} catch (e) {
if (e instanceof IdentityNotPresent) {
return res.status(401).json({ error: "authentication required" });
}
throw e;
}do {
let client = try vendo.forRequest(headers: headers)
} catch VendoError.identityNotPresent {
throw Abort(.unauthorized, reason: "authentication required")
}