Contracts
Manage, Send and Sign Contracts in One Place
Draft contracts from templates, send them for signature with SMS or email identity verification, and track every signature and renewal.
Send your first contractFree account, no card needed.
CONTRACT OVERVIEW
Everything You Need to Stay Organized
Track every contract, signature, and renewal from one dashboard.
Every contract lives in one table you can filter and search, so nothing gets lost in email threads or shared drives.
Party details, categories, and related documents stay connected automatically, giving you the full context behind every agreement.
- Party details auto-populated from user profiles
- Categorize as core, amendment, supplement, or addendum
- Filter by direction, status, category, date, or party
- Download, reuse, edit, or delete in a click
-
Centralized dashboard
View every contract in one table, filtered by direction, status, category, dates, and parties. Never lose track of an agreement again.
-
Signature tracking
Mark which parties need to sign, follow signature status, and see at a glance which contracts are still waiting.
-
Contract relationships
Link amendments, supplements, and addenda to their parent contract, keeping a clear chain of related documents.
-
Important dates
Keep issue, end, renewal, and signing dates on every contract, and filter for what is coming up.
Which Version Did They Sign?
The email, print, scan, and rescan loop is still how most businesses handle contracts: delays, version confusion, and no reliable way to verify who actually signed.
-
Lost in email chains
Without Enlivy: Searching through endless emails to find that one contract version, never sure which is the final signed copy.
With Enlivy: Every contract lives in one searchable dashboard, with the signed copy always a click away.
-
Signature bottlenecks
Without Enlivy: Waiting days or weeks to track down who needs to sign what, while critical deals sit and wait.
With Enlivy: Send for signature with clear per-party rules and live status for each signer.
-
Missing renewal dates
Without Enlivy: Contracts expire without warning because renewal dates live in a spreadsheet somewhere, or nowhere at all.
With Enlivy: Issue, end, and renewal dates sit on every contract, so you can filter for what is coming up.
-
No clear audit trail
Without Enlivy: When a question comes up, there is no reliable way to trace a contract's history, parties, or amendments.
With Enlivy: Amendments stay linked to their parent contract, and every signature is logged with its verification and reading evidence.
BUILD OR IMPORT
Two Ways to Manage Contracts
Build contracts from scratch or bring in documents from anywhere, with the same control over both.
Write professional contracts directly in Enlivy using modular chapters, a Markdown editor, and reusable templates.
Or bring in contracts created outside Enlivy, PDFs or documents from any source, for centralized tracking, signing, and storage.
- Assign senders and receivers from your team or a third party
- Link amendments and supplements to a parent contract
- Generate professional PDFs automatically
- Set direction: sent by you or received from others
-
Build from scratch
Write contracts in-platform with modular chapters, a Markdown editor, reusable templates, and a signature disclaimer on every document.
-
Import from anywhere
Upload PDFs or documents from any source and bring them under centralized tracking, signing, and storage.
-
Automatic numbering
Every contract gets a unique number from your own series, with custom prefixes you control.
-
Signature rules per party
Set who has to sign and the identity verification each party needs before a contract goes out.
-
Draft to fully signed
Track every contract from draft through to fully signed, with clear signature status at each stage.
-
Instant search and retrieval
Filter and search contract details to find any document in seconds.
THE ENLIVY ADVANTAGE
Stop Switching Between Tools. Use One System.
| Requirement | Enlivy Contracts | Traditional Methods |
|---|---|---|
| Contract Creation | Built-in editor with templates | Separate word processor needed |
| Document Storage | Centralized dashboard with search | Scattered across email and drives |
| Signature Tracking | Automatic status updates per party | Manual follow-ups via email |
| Version Control | Clear parent-child relationships | File names like "final_v3_FINAL" |
| Renewal Dates | Stored on each contract, filterable | Calendar entries or nothing |
| Party Information | Auto-populated from user profiles | Manually typed each time |
| Search & Filter | Filter by status, date, party, category | Search file names and hope |
| Audit Trail | Signing evidence kept for each signature | Pieced together from emails |
CONFIGURE SIGNING RULES
You Decide How Each Party Verifies
Before sending, choose who needs to sign and the identity verification each signer needs: email, phone (SMS), or both. Match the level to the contract's sensitivity.
- Email verification The code is checked before the signature is accepted, not after: nobody signs the contract until we know who they are.
A unique 6-digit code is sent to the signer's registered email and expires after 10 minutes. Good for standard and internal agreements.
- Phone verification
A 6-digit code is sent by SMS to the signer's registered phone number and expires after 5 minutes, adding a device factor for higher-security requirements.
- Combined verification Both channels must pass. Used where the signature has to stand up later, such as a guarantor or a witness.
The signer verifies via email first, then via phone. Both must pass before the contract can be signed. Use it for high-value or legally sensitive agreements.
How Signing Works
-
Signers receive their link
You send each signer a personalized email with an individual signing link. No Enlivy account needed. No software to install. Signers click, verify their identity using the configured method, and proceed.
-
Read, then sign
After verifying identity, the signer reads the full contract. A reading progress bar is displayed at the bottom of the screen; the Sign button only activates once the contract has been fully read. The signer then draws their signature and checks the box: “I understand this is a legally binding agreement.” Only when both conditions are met does Sign Contract become active.
-
A link to the signed contract
Once signed, the signer receives an email with a link to view the contract in your client portal. Once all parties have signed, everyone receives an email with a link to the final version. The signature status and the final document are updated in Enlivy, no manual filing required.
Offers, contracts, invoices and payments
Ready to Get Your Contracts in Order?
Join teams who've simplified their contract management with Enlivy.
Free to start · No credit card required · ANAF e-Factura for Romanian companies invoicing Romanian clients
The Signing Experience
Walk through what your signer actually sees
The real signing journey, start to finish: consent, email and SMS verification, reading the document, then signing it. Try it yourself, nothing is sent and nothing is stored.
Get Started in Minutes
Everything you need to organize contracts, in one quick flow.
-
Access Contracts Dashboard
Navigate to Contracts from your left menu. You’ll see all existing contracts in a clean, organized table view.
-
Choose Your Method
Click “Add Contract +” and select either Create Using Enlivy for new contracts, or Uploaded for documents created outside the platform.
-
Fill in Details
Enter contract information, select parties, set dates, and add content using our intuitive tabs: Information, Parties, General, Content Introduction, and Chapter Details.
-
Track and Manage
Once added, your contract appears in the dashboard. Monitor signature status, track deadlines, edit details, or reuse as templates for future contracts.
CONNECTED RECORDS
See what refers to a contract
The contract view can show connected records when you have permission to open them. Follow the relationship back to the relevant commercial document without searching through separate lists.
API Reference
Contract Management from the API
Draft, send, sign, and track contracts end-to-end, without your users ever leaving your product. The Contracts API covers the whole lifecycle: assemble a contract from chapters and parties, move it through your own status pipeline, open a legally-binding signing session per signer, and pull the signed document plus its tamper-evident audit evidence back out.
Everything is organized around four resources: contracts (the document, its chapters and its parties), contract statuses (your configurable pipeline stages), signing sessions (one per party, with email / SMS verification), and the audit trail (delivery logs and signing evidence). The examples below walk the entire flow.
Query your contracts with pagination, rich filtering, and full-text search. Filter by status, sender, receiver, direction (inbound / outbound), category (core, amendment, addenda, supplement), source (internal / uploaded), locale, parent contract, or any of the date ranges (issued_at, ends_at, created_at, updated_at). Expand related records inline.
/organizations/<organization_id>/contracts # filters are optional and combinable
# pass a q=... param instead of ids to run a full-text search
curl -G 'https://api.enlivy.com/organizations/<organization_id>/contracts' \
--data-urlencode 'page=1' \
--data-urlencode 'limit=20' \
--data-urlencode 'direction=outbound' \
--data-urlencode 'category=core' \
--data-urlencode 'include=contract_status,sender_user,receiver_user,contract_parties' \
--data-urlencode 'include_meta=navigation' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
// filters are optional and combinable
// pass a q=... param instead of ids to run a full-text search
const query = new URLSearchParams({
page: "1",
limit: "20",
direction: "outbound",
category: "core",
include: "contract_status,sender_user,receiver_user,contract_parties",
include_meta: "navigation",
});
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contracts?${query}` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());Retrieve a single contract with everything attached: its chapters, its parties, the current pipeline status, the linked file, and the sender / receiver.
/organizations/<organization_id>/contracts/<contract_id> # available includes: organization, parent_contract, sender_user, receiver_user,
# file, contract_status, contract_chapters, contract_parties, contract_prefix
curl -G 'https://api.enlivy.com/organizations/<organization_id>/contracts/<contract_id>' \
--data-urlencode 'include=contract_chapters,contract_parties,contract_status' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const contractId = "<contract_id>";
// available includes: organization, parent_contract, sender_user, receiver_user,
// file, contract_status, contract_chapters, contract_parties, contract_prefix
const query = new URLSearchParams({
include: "contract_chapters,contract_parties,contract_status",
});
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contracts/${contractId}?${query}` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());Build a contract in one call: its metadata, its body as ordered chapters, and its parties. A party can be an individual or an organization, and each carries how it should be referenced in the document and whether its signature is required.
/organizations/<organization_id>/contracts curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/contracts' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"category": "core",
"source": "internal",
"direction": "outbound",
"organization_sender_user_id": "<org_user_sender_id>",
"organization_receiver_user_id": "<org_user_receiver_id>",
"organization_contract_status_id": "<contract_status_id>",
"organization_contract_prefix_id": "<contract_prefix_id>",
"title": "Master Services Agreement",
"sub_title": "2026 Engagement",
"locale": "en",
"issued_at": "2026-07-03 09:00:00",
"ends_at": "2027-07-03 09:00:00",
"content_introduction": "This agreement is entered into between the parties below.",
"content_signature_disclaimer": "By signing, each party agrees to the terms above.",
"chapters": [
{
"title": "Scope of Work",
"content": "<p>The Provider will deliver…</p>",
"order": 1
},
{
"title": "Payment Terms",
"content": "<p>Fees are due within 14 days…</p>",
"order": 2
}
],
"parties": [
{
"party_type": "organization",
"party_country_code": "RO",
"organization_name": "Acme Studio SRL",
"organization_type": "srl",
"first_name": "Jane",
"last_name": "Doe",
"role_in_organization": "Administrator",
"referenced_as_within_document": "the Provider",
"appears_as_party": true,
"is_signature_required": true,
"contact_email_address": "jane@acme.example",
"order": 0
},
{
"party_type": "individual",
"party_country_code": "RO",
"first_name": "John",
"last_name": "Smith",
"referenced_as_within_document": "the Client",
"appears_as_party": true,
"is_signature_required": true,
"contact_email_address": "john@example.com",
"order": 1
}
]
}' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contracts` , {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
// core | amendment | addenda | supplement.
// amendment/addenda/supplement REQUIRE organization_contract_id -> a "core" parent contract.
category: "core",
// internal -> auto-numbered from a prefix (organization_contract_prefix_id required below)
// uploaded -> you supply `number`, and may set `signed_by_all_parties_at`
source: "internal",
// outbound | inbound
direction: "outbound",
organization_sender_user_id: "<org_user_sender_id>",
organization_receiver_user_id: "<org_user_receiver_id>",
organization_contract_status_id: "<contract_status_id>",
// required only for internal + core; omit it for any other source/category
organization_contract_prefix_id: "<contract_prefix_id>",
title: "Master Services Agreement",
sub_title: "2026 Engagement",
locale: "en",
issued_at: "2026-07-03 09:00:00",
ends_at: "2027-07-03 09:00:00",
content_introduction: "This agreement is entered into between the parties below.",
content_signature_disclaimer: "By signing, each party agrees to the terms above.",
chapters: [
{
title: "Scope of Work",
content: "<p>The Provider will deliver…</p>" ,
order: 1,
},
{
title: "Payment Terms",
content: "<p>Fees are due within 14 days…</p>" ,
order: 2,
},
],
parties: [
// country-specific `information` (person) and `organization_information` (company)
// JSON blocks are also accepted; their shape is validated against the country schema.
{
// party_type, party_country_code, first_name, last_name are required on every party
// organization | individual
party_type: "organization",
party_country_code: "RO",
// organization parties additionally REQUIRE organization_name + organization_type
organization_name: "Acme Studio SRL",
// value comes from reference data
organization_type: "srl",
first_name: "Jane",
last_name: "Doe",
role_in_organization: "Administrator",
referenced_as_within_document: "the Provider",
appears_as_party: true,
is_signature_required: true,
contact_email_address: "jane@acme.example",
order: 0,
},
{
party_type: "individual",
party_country_code: "RO",
first_name: "John",
last_name: "Smith",
referenced_as_within_document: "the Client",
appears_as_party: true,
is_signature_required: true,
contact_email_address: "john@example.com",
order: 1,
},
],
}),
}).then((response) => response.json());Update a contract’s metadata, move it to another status, adjust its chapters, or refine its parties. Send only what you want to change.
/organizations/<organization_id>/contracts/<contract_id> curl -X PUT 'https://api.enlivy.com/organizations/<organization_id>/contracts/<contract_id>' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"organization_contract_status_id": "<next_status_id>",
"sub_title": "2026 Engagement (revised)",
"ends_at": "2027-12-31 23:59:59"
}'const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const contractId = "<contract_id>";
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contracts/${contractId}` , {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
// partial update, only the fields you send are touched
organization_contract_status_id: "<next_status_id>",
sub_title: "2026 Engagement (revised)",
ends_at: "2027-12-31 23:59:59",
}),
}).then((response) => response.json());Render and download the contract as a PDF, the same document your counterparties see.
/organizations/<organization_id>/contracts/<contract_id>/download # returns a file stream, read it as a blob, not JSON
curl 'https://api.enlivy.com/organizations/<organization_id>/contracts/<contract_id>/download' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
--remote-name --remote-header-nameconst baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const contractId = "<contract_id>";
// returns a file stream, read it as a blob, not JSON
const pdf = await fetch(`${baseUrl}/organizations/${organizationId}/contracts/${contractId}/download` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
}).then((response) => response.blob());Soft-delete a contract. It can be restored later.
/organizations/<organization_id>/contracts/<contract_id> # soft delete, restore via POST /contracts/restore/{contractId}
curl -X DELETE 'https://api.enlivy.com/organizations/<organization_id>/contracts/<contract_id>' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const contractId = "<contract_id>";
// soft delete, restore via POST /contracts/restore/{contractId}
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contracts/${contractId}` , {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());Contracts move through your pipeline, not a fixed one. Each status maps to a lifecycle state (draft, action_required, accepted, breach, or terminated), carries localized labels, a color, and an order, and applies to inbound, outbound, or any direction. List them to build a board or drive automation.
/organizations/<organization_id>/contract-statuses curl -G 'https://api.enlivy.com/organizations/<organization_id>/contract-statuses' \
--data-urlencode 'page=1' \
--data-urlencode 'limit=50' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const query = new URLSearchParams({
page: "1",
limit: "50",
});
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contract-statuses?${query}` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());Define a new pipeline stage. Labels and descriptions are per-locale language maps, contract_state ties the stage to a lifecycle state, and you can auto-advance to another status once an action succeeds.
/organizations/<organization_id>/contract-statuses curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/contract-statuses' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"title_lang_map": {
"en": "Awaiting Signature",
"ro": "În așteptarea semnării"
},
"description_lang_map": {
"en": "Sent to all parties for signing.",
"ro": "Trimis către toate părțile pentru semnare."
},
"contract_state": "action_required",
"direction": "any",
"order": 3,
"rgba_color_code": "rgba(59, 130, 246, 1)"
}'const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contract-statuses` , {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
// per-locale maps, not plain strings
title_lang_map: {
en: "Awaiting Signature",
ro: "În așteptarea semnării",
},
description_lang_map: {
en: "Sent to all parties for signing.",
ro: "Trimis către toate părțile pentru semnare.",
},
// draft | action_required | accepted | breach | terminated
contract_state: "action_required",
// inbound | outbound | any
direction: "any",
// order is unique per organization, pick a free slot,
// or reorder existing stages via PUT /contract-statuses/reorder
order: 3,
rgba_color_code: "rgba(59, 130, 246, 1)",
}),
}).then((response) => response.json());A signing session is created per party that needs to sign. Choose the accepted signature types (draw, checkbox, classic file, electronic file), which confirmations are required (email, phone, legally-binding acknowledgement), and an expiry. With signature_source user_flow, Enlivy hosts the guided signer experience and returns a tokenized signing URL.
/organizations/<organization_id>/contract-signatures curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/contract-signatures' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"organization_contract_id": "<contract_id>",
"organization_contract_party_id": "<party_id>",
"signature_source": "user_flow",
"sign_session_signature_types": [
"draw",
"checkbox"
],
"sign_session_required_confirmations": [
"email",
"legally_binding"
],
"expires_at": "2026-07-17 23:59:59"
}'const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contract-signatures` , {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
organization_contract_id: "<contract_id>",
// one active session per party, organization_contract_party_id is unique
organization_contract_party_id: "<party_id>",
// user_flow -> Enlivy hosts the signer experience (get the link via sign_session_url)
// admin_panel -> you record the signature yourself and may send is_signed / signature_drawing / signed_contract
signature_source: "user_flow",
sign_session_signature_types: [
"draw",
// draw | checkbox | file_classic | file_electronic
"checkbox",
],
sign_session_required_confirmations: [
"email",
// email | phone | legally_binding
"legally_binding",
],
expires_at: "2026-07-17 23:59:59",
}),
}).then((response) => response.json());Deliver the signing session to the party by email or SMS, with an optional custom message. Every send is recorded in the notification log for audit.
/organizations/<organization_id>/contract-signatures/<contract_signature_id>/send curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/contract-signatures/<contract_signature_id>/send' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "email",
"message": "Please review and sign the agreement by Friday."
}'const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const contractSignatureId = "<contract_signature_id>";
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contract-signatures/${contractSignatureId}/send` , {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
// email | sms
method: "email",
message: "Please review and sign the agreement by Friday.",
}),
}).then((response) => response.json());Poll a session for its status, whether it’s signed, its expiry, and which evidence artifacts exist. Include sign_session_url to get the hosted signing link to hand to the signer.
/organizations/<organization_id>/contract-signatures/<contract_signature_id> # sign_session_url returns the hosted link to give to the signer.
# status is one of: pending | sent | completed | expired | void
curl -G 'https://api.enlivy.com/organizations/<organization_id>/contract-signatures/<contract_signature_id>' \
--data-urlencode 'include=sign_session_url,organization_contract' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const contractSignatureId = "<contract_signature_id>";
// sign_session_url returns the hosted link to give to the signer.
// status is one of: pending | sent | completed | expired | void
const query = new URLSearchParams({
include: "sign_session_url,organization_contract",
});
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contract-signatures/${contractSignatureId}?${query}` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());List every signing session, optionally scoped to a single contract, the quickest way to see who has signed and who is still pending across all parties.
/organizations/<organization_id>/contract-signatures # omit organization_contract_id to list sessions across every contract
curl -G 'https://api.enlivy.com/organizations/<organization_id>/contract-signatures' \
--data-urlencode 'organization_contract_id=<contract_id>' \
--data-urlencode 'include=sign_session_url' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
// omit organization_contract_id to list sessions across every contract
const query = new URLSearchParams({
organization_contract_id: "<contract_id>",
include: "sign_session_url",
});
const result = await fetch(`${baseUrl}/organizations/${organizationId}/contract-signatures?${query}` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());Pull the tamper-evident evidence package (authentication, consent, and signature biometrics captured during signing) for compliance and dispute handling.
/organizations/<organization_id>/contracts/<contract_id>/download-evidence # also available per session: /contract-signatures/{signatureId}/download-evidence
curl 'https://api.enlivy.com/organizations/<organization_id>/contracts/<contract_id>/download-evidence' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
--remote-name --remote-header-nameconst baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const contractId = "<contract_id>";
// also available per session: /contract-signatures/{signatureId}/download-evidence
const evidence = await fetch(`${baseUrl}/organizations/${organizationId}/contracts/${contractId}/download-evidence` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
}).then((response) => response.blob());Where it fits
Part of these setups
- Agencies and studios Core part Generated from your template with the client's details, signed online, with an email or text-message code when you ask for one. See the setup
- Course authors Core part Enrollment contracts signed online, with amendments in the same place. See the setup
- Sales teams Core part Generated from the accepted offer and signed online, with an email or text-message code when you ask for one. See the setup
- Monthly billing Optional Adds a signed contract before the first charge. The signed version stays on the client's record. See the setup
Works together with
- Proposals Quote the work in detail, share it with the customer and follow its progress through acceptance, signature and payment when those steps apply.
- Sales Pipeline See which opportunities are moving forward, review the conversation before you follow up and keep proposals close to the deal.
- Document Intake Start with a document, choose where it belongs and review the form; an AI reading you request can suggest its details.
- Tasks Keep team work beside the invoices, prospects and projects it concerns. Tasks are included for every organization at no extra charge, with no separate Tasks subscription or task-count quota.
- Users Easily customize roles and permissions in Enlivy for clients, partners, accountants, and administrators, ensuring secure and efficient access.
- Customer Portal A branded, self-service portal, on your own domain if you add one, where clients accept proposals, pay invoices, manage subscriptions and sign contracts themselves. Every action lands on the client's record in Enlivy.
- MCP Connect Enlivy to Claude, ChatGPT, Cursor, or any AI assistant through MCP. Ask about your invoices, contracts, and pipeline, and get real work done, safely scoped to exactly what your own account can already do.