Naijacloud
Docs

Examples

Four functions that cover what most frontends need a backend for. Each one is a single file you can deploy as it is, once you've set the variables it reads.

6 min read

Each example reads its secrets from variables. Set them once per project with naijacloud env set NAME --service functions-runtime --project <your-project> --secret, then deploy. If it is the project's first function, deploy it once first: that creates the functions-runtime service the variables belong to. See Secrets and variables.

A Paystack webhook

Paystack signs every webhook with your secret key. This function checks the signature before trusting the event, so nobody can fake a payment by calling your URL.

paystack-webhook.ts
ts
import { createHmac, timingSafeEqual } from "node:crypto"; export default async function handler(req: Request) { if (req.method !== "POST") return new Response("Method not allowed", { status: 405 }); // Sign the raw body exactly as it arrived; parsing it first changes it. const raw = await req.text(); const expected = createHmac("sha512", process.env.PAYSTACK_SECRET_KEY ?? "") .update(raw) .digest("hex"); const given = req.headers.get("x-paystack-signature") ?? ""; const valid = given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected)); if (!valid) return new Response("Bad signature", { status: 401 }); const event = JSON.parse(raw); if (event.event === "charge.success") { const { reference, amount, customer } = event.data; console.log(`paid: ${reference} ${amount / 100} NGN from ${customer.email}`); // Mark the order paid in your database here. } // Answer 200 quickly, or Paystack retries the event. return new Response("ok"); }
Terminal
bash
naijacloud env set PAYSTACK_SECRET_KEY --service functions-runtime --project shop --secret naijacloud functions deploy paystack-webhook --project shop

Paste the URL the CLI prints into Paystack → Settings → API Keys & Webhooks → Webhook URL.

Call an AI API with your key

Your frontend calls this function, and the function calls the AI API with a key the browser never sees. This one uses the Anthropic API; any provider with an HTTPS API works the same way.

ask.ts
ts
export default async function handler(req: Request) { if (req.method !== "POST") return new Response("Method not allowed", { status: 405 }); const { question } = await req.json(); if (typeof question !== "string" || question.length > 2000) { return Response.json({ error: "Send a question under 2,000 characters" }, { status: 400 }); } const res = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "x-api-key": process.env.ANTHROPIC_API_KEY ?? "", "anthropic-version": "2023-06-01", "content-type": "application/json", }, body: JSON.stringify({ model: "claude-sonnet-5-5", max_tokens: 500, messages: [{ role: "user", content: question }], }), }); if (!res.ok) { console.error("AI API error", res.status, await res.text()); return Response.json({ error: "The AI service did not answer" }, { status: 502 }); } const data = await res.json(); return Response.json({ answer: data.content[0].text }); }
Terminal
bash
naijacloud env set ANTHROPIC_API_KEY --service functions-runtime --project shop --secret naijacloud functions deploy ask --project shop

Anyone with the URL can call it and spend your API credit, so check who is calling before you put it in production: a token from your own sign-in, or a rate limit in your database.

Send an email

This sends a receipt through Naijamail, using a workspace API key with the Email send scope. The from address must be on a domain you have verified for email.

send-receipt.ts
ts
export default async function handler(req: Request) { if (req.method !== "POST") return new Response("Method not allowed", { status: 405 }); if (req.headers.get("authorization") !== `Bearer ${process.env.INTERNAL_TOKEN}`) { return new Response("Unauthorized", { status: 401 }); } const { to, orderId, total } = await req.json(); const res = await fetch("https://api.naijacloud.com/v1/emails", { method: "POST", headers: { Authorization: `Bearer ${process.env.NC_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": `receipt-${orderId}`, }, body: JSON.stringify({ from: "Shop <receipts@shop.ng>", to: [to], subject: `Your receipt for order ${orderId}`, text: `Thanks for your order. Total: ₦${total}.`, }), }); if (!res.ok) { console.error("email failed", res.status, await res.text()); return Response.json({ sent: false }, { status: 502 }); } return Response.json({ sent: true }); }
Terminal
bash
naijacloud env set NC_API_KEY --service functions-runtime --project shop --secret naijacloud env set INTERNAL_TOKEN --service functions-runtime --project shop --secret naijacloud functions deploy send-receipt --project shop

The Idempotency-Key means a retried call for the same order sends one email, not two.

Call a function from your frontend

A function is public: anyone with the URL can call it. A browser page on another domain also needs CORS headers, or the browser blocks the response. Answer the preflight OPTIONS request and add the headers to every response:

hello.ts
ts
const cors = { "Access-Control-Allow-Origin": "https://your-site.example", "Access-Control-Allow-Methods": "GET, POST, OPTIONS", "Access-Control-Allow-Headers": "content-type, authorization", }; export default async function handler(req: Request) { if (req.method === "OPTIONS") return new Response(null, { headers: cors }); return Response.json({ ok: true }, { headers: cors }); }
From your site
js
const res = await fetch("https://<your-project>-fn.naijacloud.app/functions/v1/hello", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ name: "Ada" }), }); const data = await res.json();

Use your site's real origin rather than *, so other sites can't call the function from their visitors' browsers.