DEV Community

Cover image for I Built Docusign for AI Agents — Here's How
Michael Beckett
Michael Beckett

Posted on

I Built Docusign for AI Agents — Here's How

AI agents can negotiate deals, draft contracts, manage entire business relationships.

But the moment they need someone to actually sign something? The whole flow breaks.

DocuSign needs a browser. HelloSign needs OAuth. Adobe Sign needs... well, Adobe Sign. None of them were designed for a world where the sender isn't human.

So I built signb.ee — document signing infrastructure built for AI agents.

The Problem

I was building AI agent workflows and kept hitting the same wall. The agent could:

  • ✅ Draft an NDA based on a conversation
  • ✅ Negotiate terms back and forth
  • ✅ Agree on final language

But then what? Copy-paste into DocuSign? Open a browser? That's not how agents work.

I needed a single API call that takes markdown (which every LLM outputs natively) and handles the entire signing ceremony — verification, signatures, certificates, delivery.

The Solution: One Endpoint

curl -X POST https://signb.ee/api/v1/send \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Mutual NDA\n\nTerms here...",
    "sender_name": "Alice",
    "sender_email": "alice@company.com",
    "recipient_name": "Bob",
    "recipient_email": "bob@acme.com"
  }'
Enter fullscreen mode Exit fullscreen mode

That's it. Signbee:

  1. Converts the markdown to a clean PDF
  2. Verifies the sender (API key or email OTP)
  3. Emails the recipient a signing link
  4. Both parties choose a signature style and sign
  5. Both receive a SHA-256 certified PDF with a tamper-proof signing certificate

No SDK. No OAuth dance. No browser automation.

Tech Decisions That Matter

PDF Generation: pdf-lib, not Puppeteer

My first instinct was Puppeteer — render HTML, screenshot to PDF. It works locally but is a nightmare on serverless. Chromium binaries are 50MB+, cold starts are brutal, and Vercel's function size limits kill it.

I switched to pdf-lib — a pure JavaScript PDF library. Zero native dependencies. Works everywhere. The signing certificate page (with both signatures, timestamps, IPs, and SHA-256 hash) is built programmatically:

import { PDFDocument, rgb, StandardFonts } from "pdf-lib";

const pdfDoc = await PDFDocument.load(originalPdfBytes);
const page = pdfDoc.addPage([595, 842]); // A4

const helveticaBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold);

page.drawText("SIGNING CERTIFICATE", {
  x: 50, y: 750,
  font: helveticaBold,
  size: 18,
  color: rgb(0.1, 0.1, 0.1),
});

// ... signatures, timestamps, SHA-256 hash
Enter fullscreen mode Exit fullscreen mode

Cold starts went from 8s to <500ms. Bundle size dropped by 95%.

Authentication: No API Key Required

Most developer APIs gate everything behind API keys. I wanted agents to be able to send documents without any prior setup. Here's how it works:

  • Without API key: Sender gets an email OTP to verify their identity. Slight friction, but zero setup.
  • With API key: Sender is pre-verified, recipient gets the signing link immediately. Zero friction.

This means any agent can call the API right now — no registration, no dashboard, no key management. Just POST and go.

The Cookie Bug That Nearly Killed Launch

The most painful bug was invisible. Everything worked on localhost. Login, signing, dashboard — perfect.

In production? Users logged in successfully (200 response) but got immediately bounced back to the login page.

The culprit: BetterAuth prefixes cookies with __Secure- on HTTPS. My middleware was checking for better-auth.session_token but production was setting __Secure-better-auth.session_token. One-line fix:

// Before (broken in production)
const session = request.cookies.get("better-auth.session_token");

// After (works everywhere)
const session =
  request.cookies.get("__Secure-better-auth.session_token") ||
  request.cookies.get("better-auth.session_token");
Enter fullscreen mode Exit fullscreen mode

Classic "works on my machine" bug. If you're using BetterAuth with HTTPS, check your cookie names.

The Signing Flow

Here's what happens end-to-end when an agent sends a contract:

Agent calls POST /api/v1/send
  → Markdown converted to PDF, uploaded to blob storage
  → Sender gets OTP email (or skipped with API key)

Sender clicks verification link
  → Creates account + chooses signature style
  → Signs the document
  → Recipient gets email with signing link

Recipient clicks signing link
  → Reviews the PDF
  → Chooses signature style + signs
  → Both parties get the final PDF with signing certificate
Enter fullscreen mode Exit fullscreen mode

The signing certificate includes:

  • Both parties' names and signatures
  • Timestamps (UTC) for each signature
  • IP addresses
  • SHA-256 hash of the complete document
  • Verification URL

What I'd Build Differently

An MCP server from day one. Right now, agents need to know about the API to use it. An MCP server would let Claude, Cursor, and Windsurf discover Signbee automatically — no docs required. The agent would just see a send_document tool available. That's next on the list.

Webhook notifications. Currently, both parties get emails. But an agent can't check email. A webhook that fires when the document is fully signed would close the loop for automated workflows.

Try It

The API is live at signb.ee with a free tier (5 docs/month). No credit card required.

If you're using agent skills, install it with:

npx skills add signbee/skill --skill signbee -g
Enter fullscreen mode Exit fullscreen mode

The OpenAPI spec and llms.txt are both available for agent consumption.

I'd love feedback on the API design — especially from anyone building agent workflows. What's missing? What would make this more useful for your agents?


Built by Michael Beckett. Follow @signbee for updates.

Top comments (0)