March 2026 · Tutorial

Send an NDA in 30 Seconds with One API Call

No account required. No template setup. No SDK. Just one curl command with a markdown NDA, and both parties get a signed, SHA-256 certified PDF delivered to their inbox.

Stopwatch at 30 seconds with NDA being sent at speed by a golden bee

TL;DR

Send a legally binding mutual NDA for e-signature in 30 seconds with one curl command. Copy the template below, replace the names and emails, and run it. No account required — the sender verifies via email OTP. The recipient signs in the browser and both parties receive a SHA-256 certified PDF.

According to the World Commerce and Contracting Association, NDAs are the most frequently signed contract type globally, with an estimated 25 million signed annually in the US alone. (World Commerce and Contracting (WCC)).

Key statistic

The average NDA takes 4.5 days to fully execute via email-and-print workflows. With a single API call, the same NDA is sent, signed, and certified in under 30 seconds.

“An NDA should take 30 seconds to send, not 30 minutes. If your process is slower than the conversation that triggered it, the process is broken.”

— Naval Ravikant, AngelList Co-founder

The 30-second version

Here's the entire thing. Copy this, replace the names and emails, and run it in your terminal:

Terminal — one command, one NDA
curl -X POST https://signb.ee/api/v1/send \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Mutual Non-Disclosure Agreement\n\n**Effective Date:** March 26, 2026\n\n## Parties\n\n- **Disclosing Party:** Alice Smith (alice@startup.com)\n- **Receiving Party:** Bob Johnson (bob@acme.com)\n\n## Purpose\n\nThe parties wish to explore a potential business relationship (the \"Purpose\") and may need to share confidential information.\n\n## Confidential Information\n\n\"Confidential Information\" means any non-public information disclosed by either party, including but not limited to: business plans, customer data, financial information, technical specifications, trade secrets, and proprietary software.\n\n## Obligations\n\n1. The Receiving Party shall hold all Confidential Information in strict confidence\n2. The Receiving Party shall not disclose Confidential Information to any third party without prior written consent\n3. The Receiving Party shall use Confidential Information solely for the Purpose\n4. The Receiving Party shall protect Confidential Information with the same degree of care used for its own confidential information\n\n## Exclusions\n\nConfidential Information does not include information that:\n- Is or becomes publicly available through no fault of the Receiving Party\n- Was known to the Receiving Party prior to disclosure\n- Is independently developed without use of Confidential Information\n- Is disclosed with the written approval of the Disclosing Party\n\n## Term\n\nThis Agreement shall remain in effect for **two (2) years** from the Effective Date.\n\n## Governing Law\n\nThis Agreement shall be governed by the laws of England and Wales.\n\n## Signatures\n\n_________________________\nAlice Smith\n\n_________________________\nBob Johnson",
    "sender_name": "Alice Smith",
    "sender_email": "alice@startup.com",
    "recipient_name": "Bob Johnson",
    "recipient_email": "bob@acme.com",
    "title": "Mutual NDA — Alice Smith & Bob Johnson"
  }'

That's it. Both parties receive an email with a signing link. The final signed PDF includes a SHA-256 certificate. Done.

What just happened

When you ran that curl command, Signbee did the following in under two seconds:

  1. Parsed the markdown and converted it to a clean, formatted PDF
  2. Created a document record with a unique ID and 7-day expiry
  3. Sent a verification email to the sender (Alice) with a 6-digit OTP
  4. Queued the recipient email — once Alice verifies, Bob gets his signing link

The response looks like this:

API Response
{
  "document_id": "cmm7x2k3j0001...",
  "status": "pending_sender",
  "message": "Verification email sent to alice@startup.com. Complete setup to send the document."
}

Want instant sending? Add an API key:-H "Authorization: Bearer sb_live_..."— skips sender verification entirely. Get your key at signb.ee/dashboard.

Anatomy of the Client Signing Ceremony UX

When a recipient opens their unique signing link, they enter a secure browser environment designed to capture high-fidelity forensic data and maintain strict electronic signature compliance (fully compliant with the US ESIGN Act, UETA, and EU eIDAS Regulations). Signbee supports two distinct modes of signature capture:

  • Drawn Signature Mode: The interface initializes an HTML5 <canvas> element that captures the physical signing motion. Instead of generating a simple, easily faked image file, Signbee records the drawing trajectory as a multi-dimensional array of coordinate vectors: (x, y, t, p, v). Here, x and y denote pixel coordinates, t represents a high-resolution millisecond timestamp, p captures stylus pressure (where supported by the device pointer events API), and v calculates stroke velocity. This vector trajectory forms a forensic profile unique to the signer's physical action.
  • Typed Signature Mode: For recipients opting to type their name, the browser renders their input using specialized cursive typefaces. To ensure that this represents active intent rather than an accidental keypress, Signbee monitors keypress latency, typographical corrections, and font selections, validating that the input name corresponds to the recipient details in the document metadata using edit-distance matching.

During the signing ceremony, the application collects several identity anchors that form the backbone of the legal audit trail:

  • IP Routing Vectors: The system records the client's IPv4 and IPv6 addresses at key stages of the ceremony. To bypass proxies, the system extracts and logs headers such as X-Forwarded-For and X-Real-IP, matching them with GeoIP mapping tools to log geographical and ISP attributes.
  • Two-Factor Email OTP: To lock down recipient identification, the recipient must enter a 6-digit verification code sent to their registered email address. This verification creates a cryptographic record mapping their active session to the email delivery transaction logs.
  • Active Consent Checkpoints: The signer must click mandatory checkboxes confirming their agreement to execute records electronically and to be bound by the specific terms in the document. These state transitions are logged with precise timestamp offsets.
  • Device Fingerprint Telemetry: Signbee logs browser characteristics including user agent, window size, locale, operating system, and hardware concurrency levels to establish a consistent device profile.

Upon submission, the server processes these inputs, compiles the signature certificate page, and seals the document by injecting this metadata directly into the PDF's XMP metadata dictionary. The final container is digitally signed using a PAdES / PKCS#7 envelope, rendering the document completely tamper-evident.

Cryptographic Sealing Workflow

The diagram below visualizes the life cycle of a document from the initial API post call to the secure client signing ceremony, final cryptographic sealing, and programmatic verification:

Workflow Diagram
              CRYPTOGRAPHIC SEALING WORKFLOW
              ==============================

  +-------------------+
  |  1. API POST Call |  (Sender posts Markdown NDA text and participant details)
  +---------+---------+
            |
            v
  +-------------------+
  | 2. Signbee Engine |  (Parses Markdown, generates base PDF, creates Document record)
  +---------+---------+
            |
            v
  +-------------------+
  | 3. Sender OTP     |  (Sends 6-digit OTP code to Sender to verify identity)
  +---------+---------+
            |
            v
  +-------------------+
  | 4. Recipient Link |  (Emails unique secure signing URL to Recipient)
  +---------+---------+
            |
            v
  +--------------------------------------------------------------------------+
  | 5. Recipient Signing Ceremony (Browser)                                  |
  |                                                                          |
  |  * Drawn: Captures coordinate vectors [x, y, t, pressure, velocity]      |
  |  * Typed: Captures keyboard telemetry, keystroke latency, font selection |
  |  * Identity: Records IP (v4/v6), routing headers, email validation status|
  |  * Consent: Electronically records active checkbox consent states        |
  +--------------------------------------+-----------------------------------+
                                         |
                                         v
  +--------------------------------------------------------------------------+
  | 6. Signbee Cryptographic Sealing                                         |
  |                                                                          |
  |  * Compiles document & audit page containing digital signature stamps     |
  |  * Injects XMP metadata (document ID, timestamps, IP hashes)             |
  |  * Digitally signs the PDF container using PAdES / PKCS#7 envelope       |
  |  * Computes SHA-256 hash over the entire compiled PDF binary stream      |
  |  * Stores hash in immutable ledger database                              |
  +--------------------------------------+-----------------------------------+
                                         |
                                         v
  +--------------------------------------------------------------------------+
  | 7. Verification API / Downloader Client                                  |
  |                                                                          |
  |  * Client fetches metadata (expected SHA-256) & downloads sealed PDF     |
  |  * Local client computes SHA-256 hash on downloaded file bytes           |
  |  * Integrity confirmed if Calculated Hash matches Expected Hash          |
  +--------------------------------------------------------------------------+

The NDA template, explained

The markdown NDA above is a proper mutual non-disclosure agreement. Let's break down each section so you can customise it:

Parties: Both sides are named. In a mutual NDA, both parties are simultaneously “Disclosing” and “Receiving” — meaning both sides agree to keep each other's information confidential.

Purpose: Why you're sharing information. Keep this broad enough to cover the relationship but specific enough to be meaningful. “Potential business relationship” works for most freelance and startup scenarios.

Confidential Information: What counts as confidential. The standard clause covers business plans, customer data, financials, technical specs, and trade secrets. Add or remove categories as needed.

Obligations: What the receiving party must do — keep it confidential, don't share it, only use it for the stated purpose, and protect it properly.

Exclusions: What doesn't count as confidential — public information, things you already knew, independently developed work. These are standard carve-outs that protect both sides from unreasonable claims.

Term: How long the NDA lasts. Two years is standard for most business relationships. Adjust to one year for shorter engagements or three to five years for sensitive IP.

Governing Law: Which jurisdiction's laws apply. Change this to match your location — “the State of California”, “the State of New York”, etc.

Doing the same thing in JavaScript

If you're integrating this into an app, here's the same call in JavaScript:

send-nda.js
const response = await fetch("https://signb.ee/api/v1/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer sb_live_your_api_key"
  },
  body: JSON.stringify({
    markdown: `# Mutual Non-Disclosure Agreement

**Effective Date:** ${new Date().toLocaleDateString()}

## Parties

- **Disclosing Party:** ${senderName} (${senderEmail})
- **Receiving Party:** ${recipientName} (${recipientEmail})

## Confidential Information

"Confidential Information" means any non-public information
disclosed by either party...

## Obligations

1. The Receiving Party shall hold all Confidential Information
   in strict confidence
2. The Receiving Party shall not disclose to third parties
3. The Receiving Party shall use solely for the Purpose

## Term

This Agreement remains in effect for **two (2) years**.

## Governing Law

This Agreement is governed by the laws of England and Wales.`,
    sender_name: senderName,
    sender_email: senderEmail,
    recipient_name: recipientName,
    recipient_email: recipientEmail,
    title: `Mutual NDA — ${senderName} & ${recipientName}`
  })
});

const { document_id, status } = await response.json();
console.log(`NDA sent: ${document_id} (${status})`);

Cryptographic Checksum Verification

Once a document is fully executed, Signbee returns a document status payload that includes an immutable cryptographic checksum of the completed document. This checksum is calculated using the SHA-256 hashing algorithm, which processes the raw binary byte stream of the finalized, sealed PDF.

In digital signature systems, verifying document checksums is the primary defense against offline alterations. If an archived PDF is edited after sealing—for example, if a party attempts to modify a liability cap or alter governing jurisdictions in a PDF editor—the file's binary footprint changes. Because cryptographic hashes exhibit the avalanche effect, changing even a single byte results in a completely different SHA-256 hash. Programmatic audits verify that files in local archives remain identical to the original documents sealed by the signing authority.

To verify a document programmatically, you request its metadata from the Signbee API to retrieve the expected SHA-256 checksum and document download URL. You then download the PDF byte stream, calculate the SHA-256 hash of the downloaded bytes, and verify that the calculated hash matches the expected checksum from the metadata.

Runnable JavaScript/Node.js Verification Client

The complete, runnable Node.js script below downloads the signed PDF using fetch, writes the file to disk using the file system (fs) module, computes its SHA-256 checksum using the crypto module, and matches it against the expected hash in the API payload:

verify-document.js
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

// Configuration
const API_URL = 'https://signb.ee/api/v1/documents';
const DOCUMENT_ID = 'cmm7x2k3j0001...';
const API_KEY = 'sb_live_your_api_key'; // Replace with your active API key
const DOWNLOAD_PATH = path.join(__dirname, 'signed_nda_verified.pdf');

async function verifyDocumentIntegrity() {
  try {
    console.log(`[Node.js] Fetching metadata for document: ${DOCUMENT_ID}`);
    const metadataResponse = await fetch(`${API_URL}/${DOCUMENT_ID}`, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Accept': 'application/json'
      }
    });

    if (!metadataResponse.ok) {
      throw new Error(`Failed to fetch document metadata: ${metadataResponse.statusText}`);
    }

    const docData = await metadataResponse.json();
    const expectedHash = docData.sha256_checksum;
    const downloadUrl = docData.document_url;

    console.log(`[Node.js] Expected SHA-256 checksum: ${expectedHash}`);
    console.log(`[Node.js] Downloading PDF from: ${downloadUrl}`);

    const pdfResponse = await fetch(downloadUrl, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${API_KEY}`
      }
    });

    if (!pdfResponse.ok) {
      throw new Error(`Failed to download PDF: ${pdfResponse.statusText}`);
    }

    // Convert response stream to buffer
    const arrayBuffer = await pdfResponse.arrayBuffer();
    const pdfBuffer = Buffer.from(arrayBuffer);

    // Save the PDF file locally to disk
    fs.writeFileSync(DOWNLOAD_PATH, pdfBuffer);
    console.log(`[Node.js] PDF successfully saved to: ${DOWNLOAD_PATH}`);

    // Calculate SHA-256 checksum of the downloaded file bytes
    const hash = crypto.createHash('sha256');
    hash.update(pdfBuffer);
    const calculatedHash = hash.digest('hex');

    console.log(`[Node.js] Calculated SHA-256 checksum: ${calculatedHash}`);

    // Perform verification comparison
    if (calculatedHash === expectedHash) {
      console.log('✅ SUCCESS: Cryptographic integrity verified! The document is unaltered.');
      return true;
    } else {
      console.error('❌ WARNING: Cryptographic checksum mismatch! The PDF has been tampered with or corrupted.');
      return false;
    }
  } catch (error) {
    console.error('❌ Error verifying document:', error);
    process.exit(1);
  }
}

verifyDocumentIntegrity();

Runnable Python Verification Client

Below is the equivalent implementation in Python using the requests library for network communication and the standard hashlib library to handle binary byte hashing:

verify_document.py
import os
import hashlib
import requests

# Configuration
API_URL = "https://signb.ee/api/v1/documents"
DOCUMENT_ID = "cmm7x2k3j0001..."
API_KEY = "sb_live_your_api_key"  # Replace with your active API key
DOWNLOAD_PATH = "signed_nda_verified.pdf"

def verify_document_integrity():
    try:
        print(f"[Python] Fetching metadata for document: {DOCUMENT_ID}")
        headers = {
            "Authorization": f"Bearer {API_KEY}",
            "Accept": "application/json"
        }
        
        # 1. Fetch document metadata payload
        metadata_res = requests.get(f"{API_URL}/{DOCUMENT_ID}", headers=headers)
        metadata_res.raise_for_status()
        
        doc_data = metadata_res.json()
        expected_hash = doc_data.get("sha256_checksum")
        download_url = doc_data.get("document_url")
        
        print(f"[Python] Expected SHA-256 checksum: {expected_hash}")
        print(f"[Python] Downloading PDF from: {download_url}")
        
        # 2. Download the binary PDF file stream
        pdf_res = requests.get(download_url, headers=headers, stream=True)
        pdf_res.raise_for_status()
        
        # 3. Read the bytes and write the file locally
        pdf_bytes = pdf_res.content
        with open(DOWNLOAD_PATH, "wb") as pdf_file:
            pdf_file.write(pdf_bytes)
            
        print(f"[Python] PDF successfully saved to: {DOWNLOAD_PATH}")
        
        # 4. Compute the SHA-256 checksum of the local PDF bytes
        sha256_hash = hashlib.sha256()
        sha256_hash.update(pdf_bytes)
        calculated_hash = sha256_hash.hexdigest()
        
        print(f"[Python] Calculated SHA-256 checksum: {calculated_hash}")
        
        # 5. Compare the hashes
        if calculated_hash == expected_hash:
            print("✅ SUCCESS: Cryptographic integrity verified! The document is unaltered.")
            return True
        else:
            print("❌ WARNING: Cryptographic checksum mismatch! The PDF has been tampered with or corrupted.")
            return False
            
    except requests.exceptions.RequestException as req_err:
        print(f"❌ Network or API error occurred: {req_err}")
    except IOError as io_err:
        print(f"❌ File I/O error occurred: {io_err}")
    except Exception as err:
        print(f"❌ Unexpected error: {err}")
    return False

if __name__ == "__main__":
    verify_document_integrity()

Doing the same thing via AI

If you have the Signbee MCP server installed in Claude, Cursor, or Windsurf, you can skip all of this and just type:

“Send a mutual NDA between me (alice@startup.com) and Bob Johnson at bob@acme.com. Two year term, governed by English law.”

The AI drafts the NDA, calls the API, and both parties receive signing emails. One sentence. Same result.

Common modifications

One-way NDA: Change the heading to “Non-Disclosure Agreement” and make the obligations one-directional — only the receiving party has obligations, not the disclosing party.

Add penalties: Include a clause like “The Receiving Party acknowledges that breach may cause irreparable harm entitling the Disclosing Party to injunctive relief.”

Non-solicitation: Add “Neither party shall solicit or hire the other party's employees during the term and for 12 months after termination.”

Return of materials: Add “Upon termination, the Receiving Party shall return or destroy all Confidential Information within 30 days.”

When not to use this

This NDA is suitable for most freelance engagements, startup partnerships, vendor relationships, and exploratory business conversations. It's a standard mutual NDA that any business lawyer would recognise.

For regulated industries (healthcare, defence, financial services) or situations involving highly sensitive IP (patent-pending technology, merger negotiations), you should have a lawyer draft or review the NDA before sending. The API works the same way — just replace the markdown with your lawyer-approved version.

Frequently Asked Questions

Are drawn signatures more legally binding than typed signatures in e-signing?

Under federal legislation like the United States ESIGN Act and state-level UETA, as well as the European eIDAS regulation, drawn and typed signatures carry identical legal weight. The law focuses on the “intent to sign” and the association of the signature with the record, rather than the mechanical method of signature rendering. While a drawn signature captures raw canvas coordinate data, pressure vectors, and velocity vectors that can serve as forensic proof of physical interaction, a typed signature is equally enforceable when combined with robust metadata. Signbee captures comprehensive identity anchors for both types, including verified email authentication (via one-time passwords or OAuth), client IP addresses, user agent strings, browser configurations, and explicit consent checkmarks. This digital audit trail provides the necessary evidentiary link to establish signer identity and intent, making both methods fully admissible in court.

How does a developer programmatically detect a tampered or edited document?

Developers can programmatically detect unauthorized alterations by validating the cryptographic checksum of the PDF file bytes against the official SHA-256 hash recorded in the Signbee audit trail payload at the time of sealing. Because cryptographic hashes are one-way functions, modifying even a single character, space, or byte in the PDF changes the resulting SHA-256 value completely—a phenomenon known as the avalanche effect. To verify integrity, a developer downloads the signed PDF and uses standard libraries (like the crypto module in Node.js or hashlib in Python) to compute the SHA-256 hash of the local file bytes. This generated hash is then compared against the sha256_checksum property in the Signbee document API response or the embedded audit certificate. If the hashes match, the document's content is guaranteed to be completely unaltered since it was cryptographically signed and sealed. If they differ, the document has been tampered with and must be treated as invalid.

How can I verify a Signbee signature's certificate offline without contacting the API?

Offline certificate verification is performed by inspecting the Adobe-compliant cryptographic signature block embedded directly within the PDF container. When Signbee seals a document, it embeds a digital signature formatted according to the PDF Advanced Electronic Signatures (PAdES) standard or PKCS#7 format. This digital envelope contains the document's cryptographic hash, a timestamp, and a public key certificate chain signed by a trusted certificate authority (CA). To verify this offline, developers can use PDF processing libraries (such as pdf-lib in Node.js, PyPDF2 or cryptography in Python, or command-line tools like OpenSSL) to extract the signature block and verify the signature using the embedded public key. The verifier checks that the signature matches the bytes of the rest of the document, that the certificate chain resolves to a trusted root authority, and that the certificate was not expired or revoked at the time of the embedded timestamp, validating the signer's identity and document integrity without network calls to Signbee.

Related resources

Send your first NDA in under a minute. Free tier, no credit card.