On this page

Examples

Ready-to-use functions. All of them are also templates in Studio → Edge Functions → New function.

#Read data as the calling user

TypeScript
import { createClient } from 'https://stitchdb.com/sdk/stitchdb-js.mjs'

Deno.serve(async (req) => {
  // Queries run as the caller: Row Level Security applies.
  const db = createClient(Deno.env.get('STITCHDB_URL')!, Deno.env.get('STITCHDB_ANON_KEY')!, {
    global: { headers: { Authorization: req.headers.get('Authorization') ?? '' } },
    auth: { persistSession: false },
  })
  const { data: { user } } = await db.auth.getUser()
  if (!user) return Response.json({ error: 'Sign in first' }, { status: 401 })
  const { data } = await db.from('todos').select('*')
  return Response.json(data)
})

#Trusted work with the service role key

TypeScript
import { createClient } from 'https://stitchdb.com/sdk/stitchdb-js.mjs'

// The service role key bypasses Row Level Security: use it only for trusted work.
const admin = createClient(Deno.env.get('STITCHDB_URL')!, Deno.env.get('STITCHDB_SERVICE_ROLE_KEY')!, {
  auth: { persistSession: false },
})

Deno.serve(async () => {
  const { count } = await admin.from('orders').select('*', { count: 'exact', head: true })
  return Response.json({ orders: count })
})

#Query Postgres directly

TypeScript
import postgres from 'npm:postgres@3'

// STITCHDB_DB_URL connects through the transaction pooler as the project owner.
const sql = postgres(Deno.env.get('STITCHDB_DB_URL')!, { prepare: false, max: 1 })

Deno.serve(async () => {
  const rows = await sql`select id, task from public.todos order by id desc limit 5`
  return Response.json(rows)
})

#Stripe webhook

Deploy with JWT verification off and add the secrets STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET; point the Stripe webhook at the function URL.

TypeScript
import Stripe from 'npm:stripe@17'

const stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!)
const crypto = Stripe.createSubtleCryptoProvider()

Deno.serve(async (req) => {
  const body = await req.text()
  try {
    const event = await stripe.webhooks.constructEventAsync(
      body, req.headers.get('stripe-signature')!, Deno.env.get('STRIPE_WEBHOOK_SECRET')!, undefined, crypto)
    console.log('Stripe event', event.type)
    return Response.json({ received: true })
  } catch (e) {
    return new Response(`Bad signature: ${(e as Error).message}`, { status: 400 })
  }
})

#Send an email

With a Resend API key in the secret RESEND_API_KEY:

TypeScript
Deno.serve(async (req) => {
  const { to, subject, html } = await req.json()
  const r = await fetch('https://api.resend.com/emails', {
    method: 'POST',
    headers: { Authorization: `Bearer ${Deno.env.get('RESEND_API_KEY')}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ from: 'My App <[email protected]>', to, subject, html }),
  })
  return new Response(await r.text(), { status: r.status, headers: { 'Content-Type': 'application/json' } })
})

#Keep an AI key on the server

With an Anthropic API key in the secret ANTHROPIC_API_KEY; your app calls the function instead of the AI provider:

TypeScript
import Anthropic from 'npm:@anthropic-ai/sdk'

const client = new Anthropic({ apiKey: Deno.env.get('ANTHROPIC_API_KEY') })

Deno.serve(async (req) => {
  const { prompt } = await req.json()
  const message = await client.messages.create({
    model: 'claude-opus-5-5',
    max_tokens: 16000,
    messages: [{ role: 'user', content: String(prompt ?? '') }],
  })
  if (message.stop_reason === 'refusal') return Response.json({ error: 'Declined' }, { status: 422 })
  const text = message.content.flatMap((b) => (b.type === 'text' ? [b.text] : [])).join('')
  return Response.json({ text })
})