Backend functions reference
Write, call and secure server functions with the server SDK.
Write, call and secure server functions with the server SDK.
A function is a Next.js route handler at app/api/functions/<name>/route.ts exporting POST.
import { createServiceClient, getUser, json } from "@/lib/draftship-server";
export async function POST(req: Request) {
const user = await getUser(req);
if (!user) return json({ error: "Sign in first" }, 401);
const { orderId } = await req.json();
const ds = createServiceClient(); // admin access, ignores security rules
const order = await ds.entities.Order.get(orderId);
if (order.created_by !== user.email) return json({ error: "Not your order" }, 403);
await ds.entities.Order.update(orderId, { status: "cancelled" });
ds.log(`Order ${orderId} cancelled`, "info", { by: user.email });
return json({ ok: true });
}
Call it from a client component:
const result = await ds.functions.invoke("cancelOrder", { orderId });
| Export | Purpose |
|---|---|
createServiceClient() |
entities (all methods incl. updateMany, deleteMany), integrations.Core, log(). |
getUser(req) |
The calling app user, or null. |
isAutomation(req) |
true when an automation is calling. |
json(data, status?) |
JSON response helper. |
Functions receive DRAFTSHIP_APP_ID, DRAFTSHIP_API_URL, DRAFTSHIP_SERVICE_KEY and your secrets. Never send the service key to the browser.
Automations POST { "event": "schedule" | "manual" | "create" | "update" | "delete", "entity"?, "record"? }. Responses are logged; non-2xx responses mark the run as failed. Functions have 60 seconds per automation run.
Accounts the owner linked in Dashboard → Connectors are available to backend functions through the server SDK:
import { createServiceClient, getUser, json } from "@/lib/draftship-server";
export async function POST(req: Request) {
const user = await getUser(req);
if (!user) return json({ error: "Sign in first" }, 401);
const { title, start, end } = await req.json();
const ds = createServiceClient();
const res = await ds.connectors.fetch("google_calendar", "/calendars/primary/events", {
method: "POST",
body: JSON.stringify({ summary: title, start: { dateTime: start }, end: { dateTime: end } }),
});
if (!res.ok) return json({ error: "Couldn't add the event" }, 502);
return json(await res.json());
}
ds.connectors.fetch(id, path, init) adds the owner's token and resolves relative paths against the service's API (https://www.googleapis.com/calendar/v3 for google_calendar). Full URLs are used as they are. For SDKs that need the raw token, use ds.connectors.getAccessToken(id), which returns { access_token, expires_at, account, api_base }.
Connector ids: google_calendar, gmail, google_sheets, google_drive, slack, notion, github, hubspot, linear. A connector that isn't linked returns 404, and one whose access was revoked returns 401.
The token endpoint (GET /connectors/<id>/token on the apps API) only accepts the app's service key, so tokens can't be fetched from the browser.