May 1, 2026 · Templates
Contract Signature Page Template: Add a Sign-Here Block via API
Need a professional signature page for your contract? Here's a ready-to-use template — and how to send it for e-signature with one API call.
Founder, Signbee
TL;DR
A signature page needs: party names, titles, dates, and an acknowledgment statement. Copy the template below, customize it, and send it for e-signature with one API call. The signed PDF includes a SHA-256 signing certificate for legal validity.
Signature page template
This markdown template serves as the foundation for clean signature blocks. It is easily parsed by rendering engines and integrates smoothly with dynamic variable bindings during contract dispatch.
# Signature Page This signature page is an integral part of the [AGREEMENT NAME] dated [DATE] (the "Agreement") between the undersigned parties. ## Acknowledgment By signing below, each party acknowledges that: 1. They have read and understood the Agreement 2. They are authorized to sign on behalf of their respective organization 3. They agree to be bound by the terms set forth in the Agreement ## Party A **Company:** [COMPANY_A_NAME] **Name:** [SIGNER_A_NAME] **Title:** [SIGNER_A_TITLE] **Date:** [DATE] ## Party B **Company:** [COMPANY_B_NAME] **Name:** [SIGNER_B_NAME] **Title:** [SIGNER_B_TITLE] **Date:** [DATE]
Structural Anatomy of Programmatic Contract Templates
Generating contracts at scale requires a clear division between styling, layout structural components, and variables. In traditional PDF generation architectures, developers had to position signature boxes using absolute coordinates (e.g., x: 120, y: 450). This approach breaks down as soon as dynamic variables change the length of the document text, pushing the signature lines onto the next page and creating either overlaps or awkward orphans.
Modern e-signature systems resolve this by rendering semantic layouts (like markdown or HTML structure) where signature elements behave as flow components. Under this architecture, the e-signature engine reads the document sequentially. It locates standard tokens or designated signature layout structures (such as header hierarchies, party blocks, or sign-here shortcodes) and inserts the signature collection fields dynamically directly within the document flow.
Using markdown as the source format provides several advantages:
- Portability: Plain text markdown can easily be stored in database fields, sent in JSON bodies, and version-tracked with Git.
- Dynamic Reflow: The layout automatically calculates page breaks and wraps text properly regardless of font size or word length.
- Separation of Concerns: Developers focus on content and variables, while the API engine handles margins, headers, page numbering, and signature widget placement.
Programmatic Multi-Signer Flows and JSON Context Construction
To trigger an automated signature collection process, you must construct a structured payload detailing the document text, the variable context to merge, the individual signing parties, and transaction options. This JSON payload forms the context used by the API parser to orchestrate the signing workflow.
The payload is built around three primary sections:
- Document Markdown and Variables: The base contract text containing variable placeholders (like
[SIGNER_A_NAME]or[DATE]) is passed alongside a flat JSON object of key-value pairs representing the actual data. - Parties Configuration: An array of signing parties. Each party object defines their email, name, role, and most importantly, their signing order. The engine uses
signing_orderto determine sequential workflows (e.g., party 2 cannot sign until party 1 has completed theirs). - Redirect and Callback URIs: Mappings for where to redirect signers once they finish or decline the signing ceremony, alongside webhook URLs for real-time transaction event callbacks.
By constructing clear variables and mapping signer parameters in JSON, developers can programmatic control the workflow. Here is a typical structure of the API payload showing the JSON context configuration:
{
"document": {
"title": "Master Services Agreement (2026)",
"markdown": "# AGREEMENT\n\nThis contract is made between [COMPANY_A_NAME] and [COMPANY_B_NAME]...",
"variables": {
"agreement_date": "2026-05-29",
"company_a_name": "Acme Corporation",
"company_b_name": "Globex Industries",
"payment_terms": "Net 30"
}
},
"parties": [
{
"name": "Jane Doe",
"email": "jane@acme.com",
"role": "Party A Signer",
"signing_order": 1,
"redirect_url": "https://acme.com/contracts/complete?signer=jane",
"decline_redirect_url": "https://acme.com/contracts/declined"
},
{
"name": "John Smith",
"email": "john@globex.com",
"role": "Party B Signer",
"signing_order": 2,
"redirect_url": "https://globex.com/contracts/complete?signer=john",
"decline_redirect_url": "https://globex.com/contracts/declined"
}
],
"webhooks": {
"completed_url": "https://api.acme.com/v1/webhooks/signatures"
},
"settings": {
"require_otp": true,
"audit_trail_level": "verbose",
"strict_variable_validation": true
}
}Workflow Architecture and API Data Flow
To understand how the e-signature request moves through the system, consider the data flow tracing the journey from context injection to the generation of the signing links:
+------------------------+ +-------------------------+
| JSON Context Data | | Markdown Template |
| (Signer info & variables) | | (Static text + fields) |
+-----------+------------+ +------------+------------+
| |
+---------------+----------------+
|
v
+--------------+--------------+
| Variable Merging |
| (Regex interpolation/binds) |
+--------------+--------------+
|
v
+--------------+--------------+
| Payload Assembly |
| (JSON structures, validation)|
+--------------+--------------+
|
v
+--------------+--------------+
| API Dispatch |
| (Secure POST to Signbee) |
+--------------+--------------+
|
v
+--------------+--------------+
| E-Signature URL Output |
| (Unique URL links returned) |
+-----------------------------+This lifecycle traces five major phases: (1) Inputs are loaded via JSON context and markdown templates; (2) The compiler processes the markdown and merges the variables; (3) The engine validates variables, settings, and signer roles; (4) The client dispatches the payload via a secure HTTPS POST; (5) The API returns the transaction record containing signing links for the parties.
Comprehensive SDK and API Code Implementations
The following complete, runnable code examples demonstrate how to assemble the JSON payload, execute the request, capture any API errors, and extract the resulting signing URL using modern HTTP client implementations in both Node.js and Python.
const fs = require('fs');
async function sendContractForSignature() {
const apiKey = process.env.SIGNBEE_API_KEY;
const apiUrl = process.env.SIGNBEE_API_URL || "https://signb.ee/api/v1/send";
if (!apiKey) {
console.error("Missing SIGNBEE_API_KEY environment variable.");
process.exit(1);
}
// Define our contract template containing dynamic placeholders
const markdownContract = `
# MASTER SERVICES AGREEMENT
This Master Services Agreement ("Agreement") is entered into on [AGREEMENT_DATE].
## Parties:
1. **Client**: [CLIENT_COMPANY_NAME]
2. **Provider**: B2bee Ltd (d/b/a Signbee)
## Engagement:
The Provider will deliver software development and API integration services as outlined in the Statement of Work.
## Fees and Payment:
The Client agrees to pay [FEES_AMOUNT] USD within [PAYMENT_TERMS_DAYS] days of invoice receipt.
---
# SIGNATURE PAGE
By signing below, the parties agree to all terms of this Agreement.
## Client Signatory
- **Authorized Representative**: [CLIENT_SIGNER_NAME]
- **Designated Email**: [CLIENT_SIGNER_EMAIL]
- **Title**: [CLIENT_SIGNER_TITLE]
## Provider Signatory
- **Authorized Representative**: Michael Beckett
- **Designated Email**: michael@signb.ee
- **Title**: Founder, Signbee
`;
// Construct the payload structure
const payload = {
markdown: markdownContract,
variables: {
"AGREEMENT_DATE": "2026-05-29",
"CLIENT_COMPANY_NAME": "Acme Innovations Inc.",
"FEES_AMOUNT": "15,000",
"PAYMENT_TERMS_DAYS": "30",
"CLIENT_SIGNER_NAME": "Sarah Jenkins",
"CLIENT_SIGNER_EMAIL": "sarah.jenkins@acmeinnovations.com",
"CLIENT_SIGNER_TITLE": "Chief Technology Officer"
},
parties: [
{
name: "Sarah Jenkins",
email: "sarah.jenkins@acmeinnovations.com",
role: "Client Signatory",
signing_order: 1,
redirect_url: "https://acmeinnovations.com/contracts/success?transaction_id=tx_99831a",
decline_redirect_url: "https://acmeinnovations.com/contracts/declined"
},
{
name: "Michael Beckett",
email: "michael@signb.ee",
role: "Provider Signatory",
signing_order: 2,
redirect_url: "https://signb.ee/dashboard/contracts/complete",
decline_redirect_url: "https://signb.ee/dashboard/contracts/declined"
}
],
webhook_url: "https://api.acmeinnovations.com/v1/webhooks/signbee",
options: {
require_otp: true,
strict_variable_validation: true
}
};
try {
console.log("Dispatching signature request to Signbee API...");
const response = await fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
"Accept": "application/json"
},
body: JSON.stringify(payload)
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Signbee API returned error status ${response.status}: ${errorText}`);
}
const data = await response.json();
console.log("Transaction successfully initialized!");
console.log("Initial Signing URL for first party:", data.signing_url);
console.log("Transaction Reference ID:", data.transaction_id);
return data;
} catch (error) {
if (error instanceof Error) {
console.error("An error occurred while sending the contract:", error.message);
} else {
console.error("An unknown error occurred:", error);
}
throw error;
}
}
module.exports = { sendContractForSignature };import os
import requests
import json
def send_contract_for_signature():
api_key = os.environ.get("SIGNBEE_API_KEY")
api_url = os.environ.get("SIGNBEE_API_URL", "https://signb.ee/api/v1/send")
if not api_key:
print("Error: SIGNBEE_API_KEY environment variable is not set.")
return None
# Load contract markdown structure
contract_markdown = """
# MUTUAL NON-DISCLOSURE AGREEMENT
This Agreement is dated [AGREEMENT_DATE] and is made between:
1. **Disclosing Party**: [DISCLOSING_PARTY_NAME]
2. **Receiving Party**: [RECEIVING_PARTY_NAME]
## Purpose:
The parties wish to exchange confidential business and technical information for the purpose of [DISCLOSURE_PURPOSE].
---
# SIGNATURE PAGE
Each party agrees to the terms of this Mutual NDA.
## Disclosing Party Signatory
- **Authorized Representative**: [DISCLOSING_SIGNER_NAME]
- **Title**: [DISCLOSING_SIGNER_TITLE]
## Receiving Party Signatory
- **Authorized Representative**: [RECEIVING_SIGNER_NAME]
- **Title**: [RECEIVING_SIGNER_TITLE]
"""
# Populate signer detail configuration
payload = {
"markdown": contract_markdown,
"variables": {
"AGREEMENT_DATE": "2026-05-29",
"DISCLOSING_PARTY_NAME": "Signbee Inc.",
"RECEIVING_PARTY_NAME": "Globex Digital Systems LLC",
"DISCLOSURE_PURPOSE": "evaluating mutual SaaS collaboration options",
"DISCLOSING_SIGNER_NAME": "Michael Beckett",
"DISCLOSING_SIGNER_TITLE": "Founder",
"RECEIVING_SIGNER_NAME": "David Vance",
"RECEIVING_SIGNER_TITLE": "VP of Partnerships"
},
"parties": [
{
"name": "Michael Beckett",
"email": "michael@signb.ee",
"role": "Disclosing Party Signer",
"signing_order": 1,
"redirect_url": "https://signb.ee/signing/complete",
"decline_redirect_url": "https://signb.ee/signing/declined"
},
{
"name": "David Vance",
"email": "d.vance@globexdigital.com",
"role": "Receiving Party Signer",
"signing_order": 2,
"redirect_url": "https://globexdigital.com/complete",
"decline_redirect_url": "https://globexdigital.com/declined"
}
],
"webhook_url": "https://api.signb.ee/webhook-receiver",
"options": {
"require_otp": False,
"strict_variable_validation": True
}
}
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
"Accept": "application/json"
}
try:
print("Sending request to Signbee API...")
response = requests.post(
api_url,
headers=headers,
data=json.dumps(payload),
timeout=10
)
# Raise HTTPError for bad responses (4xx, 5xx)
response.raise_for_status()
response_data = response.json()
print("Contract sent successfully!")
print(f"Transaction ID: {response_data.get('transaction_id')}")
print(f"First signing link: {response_data.get('signing_url')}")
return response_data
except requests.exceptions.HTTPError as http_err:
print(f"HTTP Error occurred: {http_err} - Response: {response.text}")
except requests.exceptions.RequestException as req_err:
print(f"Request Error occurred: {req_err}")
except json.JSONDecodeError as json_err:
print(f"Failed to decode response JSON: {json_err}")
return None
if __name__ == "__main__":
send_contract_for_signature()Types of signature pages
Different agreement types require different layout formats and legal terminology. The table below lists standard patterns and refers to available API templates.
| Type | Used for | Template available |
|---|---|---|
| Standard contract | Service agreements, SOWs | Above ↑ |
| NDA | Confidentiality agreements | NDA template |
| Freelance contract | Independent contractor work | Freelance template |
| Lease agreement | Rental contracts | Real estate template |
| Liability waiver | Events, sports, gyms | Waiver template |
Frequently Asked Questions
What should a contract signature page include?
Agreement title and date, signature lines for all parties, printed names and titles, company names, dates of signing, and an acknowledgment that the signer has read and agrees to the terms.
Is an electronic signature page legally binding?
Yes — under the ESIGN Act and eIDAS. Electronic signature pages are legally equivalent to wet-ink signatures for virtually all commercial contracts.
What are the payload size and structure limits for dynamic contract templates via the Signbee API?
The Signbee API accepts standard JSON payloads up to 10MB in size, which provides ample space for extremely long, multi-page markdown agreements (a typical markdown file of 2,000 lines is less than 100KB). If you are attaching files, any external documents referenced via URL or encoded as raw binary base64 must fit within this 10MB limit. For variables, there is no technical limit to the number of key-value pairs you can include in the context object, but nesting variables inside multi-level structures is not supported; variables must be a flat object. For the number of signers, a single API payload can support up to 50 signer records, each with unique roles and routing parameters. If you exceed these bounds, the API will return a 413 Payload Too Large error.
How does Signbee map and handle redirect URLs for the signing ceremony across multiple signers?
Signbee allows you to configure individual redirect paths for each signer in a multi-party workflow. Within the party array of your JSON payload, you can assign unique redirect_url and decline_redirect_url properties to each signer. Once a signer completes their signing action, the Signbee UI automatically redirects their browser to their specific URL, appending transaction parameters (such as transaction_id and signer_email) as query parameters to allow your system to trace their session state. In sequential signing workflows, once the first signer finishes and redirects, Signbee automatically dispatches the signing invitation to the next signer via email. Webhook notifications are also fired asynchronously, ensuring your backend is notified of progress even if the user closes their browser instead of completing the redirect.
What happens if a contract template references a variable that is missing or undefined in the JSON context payload?
Signbee handles missing or undefined template variables based on the strict_variable_validation option passed in your payload settings. By default, if this option is disabled or omitted, the rendering engine treats the missing variable gracefully, leaving the placeholder in the document bracket format (e.g., leaving [SIGNER_B_TITLE] as plain text in the final PDF) so it is clear that it was unresolved. However, if you set strict_variable_validation to true in the request options, the Signbee API parser will validate all placeholders against the provided JSON context before executing the transaction. If any variables referenced in your markdown are missing from the variables dictionary, the API will return a 400 Bad Request error specifying the exact missing keys, allowing you to intercept validation errors before signing.
Send contracts for signature — 5 free/month, SHA-256 certified.
Last updated: May 29, 2026 · Michael Beckett is the founder of Signbee and B2bee Ltd.