your database e-sign webhook pipeline

---

title: your database e-sign webhook pipeline

description: Integrate your database e-sign webhook pipeline through Atlas REST or MCP: PDF or DOCX upload, party binding, and signed PDF delivery.

date: 2026-06-09

updated: 2026-06-09

---

your database Postgres plus Edge Functions is a common backend for Vercel frontends. Atlas webhooks land in your database through an Edge Function that verifies HMAC, writes rows, and triggers Realtime updates to your app.

Share: "Atlas signs. your database stores envelope state. Your app subscribes to changes."

Schema

create table contracts (
  id uuid primary key default gen_random_uuid(),
  atlas_envelope_id text unique not null,
  external_id text,
  status text not null default 'draft',
  review_url text,
  signed_pdf_url text,
  signer_email text,
  created_at timestamptz default now(),
  signed_at timestamptz
);

create index contracts_atlas_envelope_id on contracts (atlas_envelope_id);
create index contracts_external_id on contracts (external_id);

Store external_id from Atlas metadata for CRM correlation.

Create from your database Edge Function

supabase/functions/create-contract/index.ts:

import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';

serve(async (req) => {
  const { documentUrl, signerEmail, signerName, externalId } = await req.json();
  const atlasKey = Deno.env.get('ATLAS_API_KEY')!;

  const res = await fetch('https://atlaswork.ai/api/envelope', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${atlasKey}`,
      'Content-Type': 'application/json',
      'Idempotency-Key': crypto.randomUUID(),
    },
    body: JSON.stringify({
      document_url: documentUrl,
      webhook_url: `${Deno.env.get('SUPABASE_URL')}/functions/v1/atlas-webhook`,
      metadata: { external_id: externalId, client_reference_id: externalId },
      parties: [{ email: signerEmail, name: signerName, role: 'Customer' }],
    }),
  });

  const data = await res.json();
  if (!res.ok) return new Response(JSON.stringify(data), { status: res.status });

  const supabase = createClient(/* service role */);
  await supabase.from('contracts').insert({
    atlas_envelope_id: data.envelope_id,
    review_url: data.review_url,
    signer_email: signerEmail,
    external_id: externalId,
    status: 'draft',
  });

  return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } });
});

Webhook Edge Function

Atlas POSTs JSON events. Verify signature before writing:

async function verify(raw: string, header: string, key: string): Promise<boolean> {
  const enc = new TextEncoder();
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    enc.encode(key),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign'],
  );
  const sig = await crypto.subtle.sign('HMAC', cryptoKey, enc.encode(raw));
  const hex = Array.from(new Uint8Array(sig), (b) => b.toString(16).padStart(2, '0')).join('');
  return header === `sha256=${hex}`;
}

serve(async (req) => {
  const raw = await req.text();
  const sig = req.headers.get('x-atlas-signature') ?? '';
  if (!verify(raw, sig, Deno.env.get('ATLAS_API_KEY')!)) {
    return new Response('Unauthorized', { status: 401 });
  }

  const event = JSON.parse(raw);
  const supabase = createClient(/* service role */);

  if (event.event === 'envelope.signed') {
    await supabase.from('contracts').update({
      status: 'signed',
      signed_at: new Date().toISOString(),
      signed_pdf_url: event.signed_download_url ?? null,
    }).eq('atlas_envelope_id', event.envelope_id);
  }

  return new Response('ok');
});

Use your database service role in the webhook function. Row Level Security on contracts should block client writes; server functions bypass RLS with service role.

Realtime UI

Enable Realtime on contracts. Your Next.js dashboard subscribes:

supabase
  .channel('contracts')
  .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'contracts' }, payload => {
    setStatus(payload.new.status);
  })
  .subscribe();

Users see "Signed" without polling Atlas.

Storage option

Download signed PDF from Atlas API and upload to your database Storage bucket signed-contracts. Store storage_path on the row for private signed URLs.

Auth model

Atlas dashboard uses password auth. Your your database app may use your database Auth for customers. Keep Atlas API key only in Edge secrets. End users never see it.

Idempotency

Atlas may retry webhooks. Use atlas_envelope_id plus event type as idempotency key in a webhook_events table before mutating state.

Row Level Security pattern

Example RLS: authenticated users read contracts where org_id = auth.jwt()->>'org_id'. Only service role inserts or updates from Edge Functions. Never expose service role key to browser clients.

pg_net alternative

Some teams call Atlas create from Postgres via pg_net extension instead of Edge Functions. That keeps logic close to data but makes HMAC webhook verification harder inside SQL. Edge Functions remain the default recommendation for verify-then-write flows.

Backup signed artifacts

Replicate your database Storage bucket holding signed PDFs to secondary region if counsel requires geographic redundancy. Atlas also serves signed downloads via API after sign for re-fetch jobs.

Local supabase start

Developers running your database locally can point Edge Functions at Atlas production or a dedicated test org. Use separate API keys per developer to trace envelope noise during debugging.

FAQ

Edge Function timeout? Respond 2xx fast. Queue heavy PDF downloads with your database background job or separate worker.

Can your database Auth users create envelopes? Your Edge Function maps JWT user to create call. Review URL still gates Send.

402 credits? Surface billing link to org admin. Credits live on Atlas org, not your database.

MCP + your database? Agents create via MCP; your database syncs via the same webhook function if you also set webhook_url on those envelopes.

DOCX? Supported on Atlas create when URL serves DOCX.

Extended FAQ

your database Auth vs Atlas Auth? Separate systems. Edge Functions bridge them with service role.

Can RLS block webhooks? Service role bypasses RLS. Do not use anon key in webhook function.

Realtime latency? Postgres change events typically sub-second after webhook update.

Storage vs external URL? Either works for signed artifact retention policy.

Local Edge Function secrets? Use supabase secrets set for Atlas key in remote projects.

API reference

Full route list and request schemas live at /dev. Start with E-signature API for the mental model, then use this guide for copy-paste examples.