TL;DR
Instead of email threads with scans and "which Word version is current": generate a contract from a template, send the client a unique link, they sign in the browser, the system saves a PDF with audit trail, sends a transactional email, and updates status in the database. For B2B IT service contracts in the EU, a simple electronic signature (intent + logs + archive) is usually enough — qualified (eIDAS) signatures are only required in selected regulated sectors. Below: API architecture, security, and an honest legal disclaimer.
Who this is for
- Software houses, agencies, and consultancies selling projects under service or work contracts
- Teams with templates (Word/Google Docs) but wanting one source of truth (HTML → PDF)
- B2B clients expecting project start in days, not weeks waiting for "please send a stamped scan"
- Companies building a custom panel instead of paid SaaS with per-user limits
Keywords (SEO)
online contract signing, electronic contract business, client signature website, b2b contract workflow, electronic signature service agreement, contract archive pdf
The problem you solve
Typical B2B chaos looks like: offer PDF → negotiation by email → Word v3_final_FINAL2.docx → scan without a clear date → no record of who accepted which GDPR clause when. Every day of delay risks losing the project and administrative cost.
An online system organizes this in five steps with one contract identifier in the database.
B2B workflow — from template to archive
1. Contract template
The template holds variable fields: company name, tax ID, scope, amount, schedule, IP, GDPR clauses, version number in the PDF footer. At DevStudio, templates are handled by the contract-templates layer — content generated programmatically, not pasted from Word on every sale.
2. Create record and link
POST /api/contracts (and related flow /api/create-contract-link) creates a unique contract ID, initial status, and client metadata. Admin does not send a file — they send a link to /contract/[contractId].
3. Send to client
POST /api/contracts/[id]/send emails the link (with rate limiting and IP logging). Status moves to sent_to_client. The client sees content, consent checkboxes, and a signature field (canvas or typed name).
4. Client signature
POST /api/contracts/[id]/sign accepts signedData, verifies the contract is in sent_to_client, stores signature, IP (getClientIp), timestamp, and generates PDF via pdf-lib. After signing, a second step may follow — /api/contracts/[id]/admin-sign — when the company counter-signs after the client.
5. Archive and notifications
GET /api/contracts/[id]/download-pdf— download version with both copies / full PDFPOST /api/generate-contract— PDF generation from preview (also rate limited)POST /api/send-contract-email— confirmation email to client (endpoint protected by admin —requireAdminApi)
Client and company share the same contract number, signature date, and audit path in the database — not "someone had a file on the desktop."
API map — what each endpoint does
| Endpoint | Role |
|---|---|
/api/contracts |
List / create contracts |
/api/contracts/[id] |
Read and update metadata |
/api/contracts/[id]/send |
Email with signing link |
/api/contracts/[id]/sign |
Client signature + PDF + status |
/api/contracts/[id]/admin-sign |
Company signature (optional step) |
/api/contracts/[id]/download-pdf |
PDF archive |
/api/generate-contract |
PDF generation (pdf-lib) |
/api/send-contract-email |
Post-signature confirmation email |
/api/contract-templates |
Templates in admin panel |
Stack: Next.js 15, Prisma, pdf-lib, nodemailer / transactional SMTP layer. This is not a "form with attachment" — it is a small workflow application embedded next to the marketing site.
Simple vs qualified signature (eIDAS) — without legal jargon
| Aspect | Simple signature (click + consent + log + PDF) | Qualified signature (eIDAS) |
|---|---|---|
| Typical B2B IT, NDA, work contracts | Usually enough as proof of intent | Rarely required |
| Banks, some authorities, regulated tenders | May be insufficient | Often required |
| Cost and implementation time | Low — days / 1–2 weeks | Higher — certificate, provider integration |
| Evidence in dispute | Logs, IP, timestamp, PDF version, email | Stronger legal presumption in EU |
Legal disclaimer (important)
This article is not legal advice. Rules and court practice depend on contract value, industry, and parties. For high-value or regulated contracts, consult a lawyer on contract text and signature form. Technical implementation provides audit trail and process — it does not replace assessment of whether that signature form is required in your case.
For a typical IT services agreement between businesses, a sensible package is: clear clause on document form and electronic signature, consent to submit statements through the system, version number on the document, and archive for both parties.
What the signing page / app must have
HTTPS and roles
The entire flow only over HTTPS. Two roles: client (public link with token/ID) vs admin (panel, company signature, sending emails). Admin endpoints must not be anonymously accessible.
Audit trail
On signature, store at least:
- contract ID and template version number,
- date and time (UTC in DB, local format in PDF),
- client IP (as in
sign/route.ts), - hash or text of accepted checkboxes (GDPR, terms).
This is not "spying" — it is evidence of process in a dispute over "I did not sign this version."
PDF versioning
Every scope or price change = new template version and new record / new link. PDF footer: Template version 2026-05-28 / Contract no. DS-2026-0142.
Transactional email
After signed: email to client with contract number, date, and PDF link (or attachment — per storage policy). Separate notification to sales (buildContractAdminSignedNotificationEmail).
Security — minimum that is not optional
Token and contract ID
Link /contract/[contractId] should use a long random ID (UUID), not sequential id=123. Guessing the URL = access to contract content before signing.
Rate limiting
At DevStudio, signing, send, and PDF generation endpoints use checkEmailRateLimit(ip) — 429 with Retry-After on abuse. Protects against signature spam and brute force on public APIs.
Expiry and one-time use
After signing, status ≠ sent_to_client — repeat sign returns an error. The link should not allow unlimited edits without logging. Optional: link validity 7–14 days in expiresAt.
No Google indexing
Contract page layout sets X-Robots-Tag: noindex, nofollow, noarchive — contracts and client data do not enter search indexes. Standard for confidential documents.
Admin endpoint protection
/api/send-contract-email requires requireAdminApi — a random POST from the internet cannot send mail on behalf of the company.
Integrations worth adding later
- CRM / Notion / Slack — webhook on
signedstatus (start project in #delivery channel) - Invoicing — invoice only after
signed, not after "verbal agreement" - Accounting / e-invoicing — export contract metadata (number, amount, tax ID)
- Dropbox / S3 — long-term PDF archive off the app server
A simple MVP without CRM is still a huge time saving vs. email with scans.
Most common implementation mistakes
- Sending Word instead of one PDF generator — five versions of legal truth.
- Missing clause that clicking "I sign" is a will statement in electronic form.
- Same link reused without status change and logs.
- No PDF copy in client inbox — "where is the contract?" a week later.
- Indexable contract URLs — metadata leak in Google.
- Signature before accepting scope (checkboxes below signature instead of above).
- Missing counter-sign when the client expects a two-sided PDF immediately.
How long does implementation take?
| Scope | Rough time |
|---|---|
| One template + link + signature + PDF + email | 1–2 weeks |
| Multiple templates, roles, admin-sign, CRM | 4–6 weeks |
| Qualified signature + certificate provider | separate project (integration + legal) |
Times assume a ready legal template from counsel — clause editing is often longer than code.
FAQ
Is a signature on screen legal?
For B2B contracts between businesses — in market practice often yes, as expression of will with system logs and PDF. Exceptions and high contract value → lawyer. This article does not replace consultation.
Does this replace DocuSign / Autenti?
For internal B2B IT flow — often functionally yes (link, sign, PDF, mail). For legal ecosystem with qualified signature and enterprise scale — compare SaaS TCO vs. custom module on Next.js.
What if the client has no mouse for handwriting?
A checkbox + typed full name / title saved in signedData is enough — process consistency matters more than a pretty SVG signature.
Where to store PDFs for years?
Database + object storage with backups and retention policy aligned with GDPR (purpose, deletion after retention). Client email alone is too weak as the only archive.
Are chatbot and contact form the same contract?
No — a website lead is a lead. A contract is a separate record after offer acceptance. Mixing them in one email blurs marketing and legal.
Admin panel — what sales sees
After rollout, have a contract list view: status (draft, sent_to_client, signed, …), send date, client, amount, PDF link. Admin should not edit content after sending to client without a new version — otherwise the signature covers a different document than in the archive. At DevStudio, sensitive operations (e.g. resend email) go through admin-authorized endpoints, not the public link.
PDF content normalization (pdf-lib)
Special characters in PDF sometimes need normalization or embedded fonts — signing code may map characters to ASCII-compatible text in generated PDF to avoid "empty squares" for the client. A technical detail, but it affects professional look of documents sent to the client's accountant.
Comparison with SaaS (DocuSign, Autenti, etc.)
| Criterion | Custom Next.js module | SaaS |
|---|---|---|
| Cost at many contracts/year | Fixed dev cost, low marginal | Per user / envelope license |
| CRM and site integration | Full | API + often manual bridge |
| Qualified signature | Requires provider integration | Often built in |
| Time to MVP | 1–2 weeks (simple flow) | Hours config, weeks compliance |
For dozens of contracts per year in IT, custom module pays off; for one contract a year — SaaS or even signed PDF by email may suffice.
GDPR and administrator role
Contracts contain personal data (client representative, email, phone). In privacy policy describe purpose (contract conclusion), legal basis (e.g. contract performance / legitimate interest), retention for PDF and logs. After retention ends — deletion or anonymization procedure in the database. Signing links should not be indexed — noindex mentioned above — and access only for URL holders.
Summary
Online contract signing at a service business is a workflow: template → API → link → signature → PDF → email → signed status. Technically: Next.js API routes (contracts, sign, generate-contract, send-contract-email), pdf-lib, rate limit, noindex. Legally: for typical B2B IT, simple signature with good audit is usually enough — when in doubt, a lawyer, not a blog. Start with one template and one happy path — extend with admin-sign and CRM when the process works.
Want a signing system for your business?
- Contact us — we discuss templates and integrations
- Web applications — custom B2B modules in Next.js
- See our work — projects with process automation