Integrate Your Systems and Automate Workflows with the Enlivy API
Integrate Enlivy smoothly with other tools and platforms through our robust API, facilitating a connected and scalable ecosystem for your business operations.
Start TodayAPI-FIRST BY DESIGN
Built for Developers. Ready for Business.
Everything you can do in Enlivy, you can do through the API.
Every action available in the interface, from creating invoices to syncing contracts or updating records, can be done via API. Automate repetitive tasks, connect Enlivy with your existing systems, and build workflows that match how your business runs.
Clean, reliable endpoints with clear documentation and no vendor lock-in. Whether you are a startup or an enterprise, you ship automations and integrations in days, not months.
-
Modular by design
Connect just what you need, invoices, customers, contracts, and more, without locking into a rigid system.
-
Build faster, scale smarter
A fast, stable API lets your team build automations and integrations in days, not months.
-
Integrates with your stack
Plug Enlivy into the HR, finance, and CRM systems you already run.
-
No vendor lock-in
Clean, documented endpoints you stay in control of, with total flexibility.
SOUND FAMILIAR?
The Challenges Holding Your Business Back
Brittle integrations and manual busywork, the things that keep a business from scaling. Here is what that costs you, and how an API-first platform changes it.
- The problem
Systems that will not talk
Connecting your HR, finance, and CRM is a frustrating tangle of manual work and unreliable integrations.
Every record is reachable through one clean API, so your systems finally connect and stay in sync.
- The problem
Manual busywork that will not scale
Repetitive manual tasks drain productivity, increase errors, and block your ability to scale with confidence.
Script the repetitive work, invoicing and data syncing, and let automation carry it, error-free, as you grow.
API Reference
Invoice Management from the API
Integrate directly with Enlivy through our public API for programmatic access to your account data: invoices, receipts, transactions, products, users, contracts, and more.
The examples below cover the most common invoicing operations: listing invoices, retrieving a single invoice, creating a new one, and updating existing invoice data.
Display a list of recent invoices in your dashboard. Query invoices for your organization with pagination, filters, and metadata. You can also expand invoice details such as line items and taxes.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/invoices?page=1&limit=20&include=invoice_prefix,tag_ids,line_items,taxes&include_meta=navigation`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}); Retrieves detailed information about a specific invoice within your organization. Use this to access invoice data such as totals, line items, status, taxes, tags, and more.
const organizationId = "your_org_id";
const invoiceId = "your_invoice_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/invoices/${invoiceId}?include=invoice_prefix,tag_ids,line_items,taxes`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}); Creates a new invoice under your organization. You can include detailed data such as sender and receiver users, invoice prefix, currency, line items, and more.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/invoices`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: 'your_payload'
}); Update an existing invoice’s content such as its status (e.g. issued, paid, canceled), payment method, due date, number, tags, notes, and product lines.
const organizationId = "your_org_id";
const invoiceId = "existing_invoice_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/invoices/${invoiceId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: 'your_payload'
}); API Reference
Billing Schedules from the API
Automate recurring revenue end-to-end. An app-managed billing schedule is run entirely by Enlivy: it generates invoices on the cadence you define, charges the saved payment method, retries failures, and moves through its own lifecycle: pending, active, paused, cancelling, completed. You define the composition once; the engine bills it on schedule.
This reference covers app-managed schedules only. Enlivy also supports Stripe-hosted schedules, where Stripe owns the subscription and runs the billing. Those are managed on Stripe’s side, so their creation and modification aren’t covered here. You can compose an app-managed schedule two ways: from raw phases (your own recurring line items and cadence) or from a subscription billing package (a reusable template). The examples below cover both, plus listing, editing, reconfiguring, and cancelling.
Query your schedules with pagination, filtering, and full-text search. Filter by status, direction (outbound / inbound), sender, receiver, contract, bank account, or any of the date ranges (starts_at, ends_at, created_at, updated_at). Expand the phases and generated payments inline.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/billing-schedules?page=1&limit=20` +
// status: pending | active | payment_method_required | paused | cancelling | completed | cancelled
`&status=active&direction=outbound` +
`&include=receiver_user,phases,payments` +
`&include_meta=navigation`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Retrieve a single schedule with everything attached: its phases and line items, the payments generated so far, the counterparties, and the linked package or contract. Read next_payment_create_at to see when the engine bills next, and total / paid_total for progress.
const organizationId = "your_org_id";
const scheduleId = "your_schedule_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/billing-schedules/${scheduleId}` +
// includes: sender_user, receiver_user, contract, billing_package,
// subscription_term, phases, payments, deleted_by_user
`?include=phases,payments,receiver_user,billing_package`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); The most direct way to bill: define one or more phases, each with its own cadence and line items. The engine issues an invoice per phase occurrence and charges it. Phases are exclusive to app-managed schedules.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/billing-schedules`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
management_type: "app_managed", // this reference only covers app_managed
direction: "outbound", // outbound = you bill a customer; inbound = you are billed
status: "active", // start billing right away
organization_sender_user_id: "org_user_sender_id", // the biller (you)
organization_receiver_user_id: "org_user_receiver_id", // the customer (required for outbound)
currency: "EUR",
payment_method: "stripe_card_payment", // bank_transfer | card_payment | stripe_card_payment | paypal | cash | paid_by_personal_funds
organization_user_payment_method_id: "payment_method_id", // saved card to auto-charge (must belong to the receiver)
name_lang_map: { en: "Monthly Retainer" }, // per-locale maps, not plain strings
note_lang_map: { en: "Includes support and hosting." },
is_email_notifications_active: true,
email_notifications_to: "billing@acme.example",
// customer self-service toggles (what the recipient may do from the portal)
customer_can_reconfigure: false,
customer_can_cancel: true,
customer_can_pause: false,
// totals + dates (total, paid_total, starts_at, ends_at, next_payment_create_at)
// are computed by the engine, do NOT send them.
// phases are valid ONLY for app_managed (stripe_hosted rejects them). Max 20.
phases: [
{
frequency: "monthly", // weekly | biweekly | monthly | yearly
execute_after: "2026-08-01", // first run date for this phase
max_occurrences: 12, // stop after N invoices (omit for open-ended)
due_date_type: "custom_days", // immediate | end_of_month | custom_days
due_date_days: 14, // required only when due_date_type = custom_days
order: 0,
line_items: [
{
name_lang_map: { en: "Retainer" }, // required unless organization_product_id is set
quantity: 1,
price: 500.00, // money: signed decimal in MAJOR units (not cents)
organization_tax_class_id: "tax_class_id"
},
{
organization_product_id: "product_id", // pulls name / tax defaults from the product
quantity: 2,
price: 49.90
}
]
}
]
})
}); Instead of hand-building phases, materialize the schedule from a reusable subscription billing package. The package owns the composition, you just pick the cadence variant and which group items to include.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/billing-schedules`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
management_type: "app_managed", // package-managed requires app_managed
direction: "outbound", // package-managed requires outbound
status: "active",
organization_sender_user_id: "org_user_sender_id",
organization_receiver_user_id: "org_user_receiver_id",
organization_user_payment_method_id: "payment_method_id",
// attach a SUBSCRIPTION package, it defines the phases & line items
organization_billing_package_id: "billing_package_id",
// optional: pick the cadence variant; omit to use the package default
organization_billing_package_subscription_term_id: "subscription_term_id",
// optional: choose which package group items (and quantities) to include
selected_group_items: [
{ id: "group_item_id_1", quantity: 1 },
{ id: "group_item_id_2", quantity: 3 }
]
// NOTE: mutually exclusive with `phases`, the package supplies them.
})
}); Update metadata (name, notes, notification settings, self-service toggles) and drive the lifecycle by moving status: pause an active schedule, resume a paused one, or set it to cancel. Send only what you want to change.
const organizationId = "your_org_id";
const scheduleId = "your_schedule_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/billing-schedules/${scheduleId}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
// lifecycle: active <-> paused; set "cancelling" to stop at the end of the cycle
status: "paused",
note_lang_map: { en: "Paused at customer request." },
is_email_notifications_active: false,
customer_can_cancel: true
// to change WHAT gets billed on a package-managed schedule,
// use /reconfigure below rather than editing here.
})
}); Change what a package-managed schedule bills: swap the package, change the term, adjust selected items and quantities, override prices, or add one-off custom line items. Always preview first: the preview endpoint returns the resulting composition and any proration before a cent is charged.
const organizationId = "your_org_id";
const scheduleId = "your_schedule_id";
const token = "YOUR_TOKEN_HERE";
const headers = {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
};
const changes = {
organization_billing_package_id: "billing_package_id",
organization_billing_package_subscription_term_id: "subscription_term_id",
selected_group_items: [
// price_override + pricing_currency let you deviate from the package price
{ id: "group_item_id", quantity: 2, price_override: 39.00, pricing_currency: "EUR" }
],
custom_line_items: [
{ name_lang_map: { en: "One-off setup" }, quantity: 1, price: 150.00 }
],
// how the switch is billed: none | prorate_immediately | prorate_next_invoice
// (prorate_immediately requires an active schedule)
proration_mode: "prorate_next_invoice"
};
// 1. Preview, no changes are applied; returns the new composition + proration
await fetch(
`https://api.enlivy.com/organizations/${organizationId}/billing-schedules/${scheduleId}/preview-reconfigure`,
{ method: "POST", headers, body: JSON.stringify(changes) }
);
// 2. Apply
await fetch(
`https://api.enlivy.com/organizations/${organizationId}/billing-schedules/${scheduleId}/reconfigure`,
{ method: "PUT", headers, body: JSON.stringify(changes) }
); Read aggregate recurring-revenue analytics across your schedules: a point-in-time summary (with forward projection) or a history_monthly breakdown, to power MRR dashboards without pulling every schedule yourself.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/billing-schedules/analytics/summary` +
// analyticsType: summary | history_monthly
`?direction=outbound&convert_to_currency=EUR`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Soft-delete a schedule. Prefer setting status to cancelling (stops future billing at the end of the cycle) when you want to keep the record; delete when you want it gone. It can be restored later.
const organizationId = "your_org_id";
const scheduleId = "your_schedule_id";
const token = "YOUR_TOKEN_HERE";
// soft delete, restore via POST /billing-schedules/restore/{scheduleId}
fetch(`https://api.enlivy.com/organizations/${organizationId}/billing-schedules/${scheduleId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}); API Reference
Network Exchanges from the API
Send and receive legally-compliant e-invoices over the PEPPOL and tax-authority networks, programmatically. A network exchange is a single transmission of an invoice to (or from) an institution, such as Romania’s ANAF. Enlivy builds the compliant UBL document, signs it, submits it, and tracks the response through its lifecycle so you always know whether a document was accepted, rejected, or still processing.
Exchanges are outbound (you submit an invoice you issued) or inbound (you pull documents addressed to you). This reference starts with the key action, pushing an invoice onto the network, then covers listing, inspecting, pulling inbound documents, and downloading the signed files. Every exchange carries a live status you can poll.
Submit an issued invoice to a network institution. The invoice is the payload; there is no request body. Enlivy generates the compliant UBL, signs it, transmits it, and returns the resulting network-exchange record with its initial status. Which institutions an invoice can go to is exposed on the invoice itself.
const organizationId = "your_org_id";
const invoiceId = "your_invoice_id";
const token = "YOUR_TOKEN_HERE";
const headers = {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
};
// 1. Discover eligible institutions for this invoice.
// invoice.peppol_exchange_push_options lists the institution ids you may push to;
// invoice.peppol_exchanges_pushed lists the ones already sent.
const invoice = await fetch(
`https://api.enlivy.com/organizations/${organizationId}/invoices/${invoiceId}`,
{ method: "GET", headers }
).then((r) => r.json());
// 2. Push to a specific institution. The id is a string, e.g. "anaf" (Romania / ANAF).
const institution = "anaf";
const exchange = await fetch(
`https://api.enlivy.com/organizations/${organizationId}/invoices/${invoiceId}/peppol/${institution}`,
{ method: "POST", headers } // no request body, the invoice is the document
).then((r) => r.json());
// The response is the network-exchange record. Poll its `status`:
// pending | processing | success | success_in_exchange_queue | success_pending_archive
// | change_required | rejected | rejected_at_exchange | failed | failed_credentials_expired
// A transport/connectivity failure to the institution returns HTTP 503. List every exchange with pagination and filtering: scope to one invoice, filter by exchange status or by the linked invoice’s state, and bound by date. This is how you build a compliance dashboard of what’s been sent and where each document stands.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/invoices/network-exchanges?page=1&limit=20` +
// filters: status, organization_invoice_id, invoice_state (the linked invoice's state),
// created_at_from/to, updated_at_from/to, ids
`&status=success` +
`&include=invoice`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Retrieve a single exchange: its status, the institution’s exchange and message identifiers, the raw institution response_json, and the names of the generated files. Include parsed_data to get the parsed contents of the exchanged document, or invoice for the source invoice.
const organizationId = "your_org_id";
const exchangeId = "your_exchange_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/invoices/network-exchanges/${exchangeId}` +
// includes: organization, invoice, parsed_data (the parsed UBL as structured data), tag_ids
`?include=parsed_data,invoice`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Fetch documents that were sent to you over an institution’s network, supplier invoices delivered through ANAF, for example. Enlivy retrieves and ingests them as inbound exchanges. Bound the sync with date_from.
const organizationId = "your_org_id";
const institutionId = "anaf";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/invoices/network-exchanges/${institutionId}/pull` +
`?date_from=2026-07-01`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Pull the artifacts of an exchange: the compliant UBL/XML document, its digital signature, and the human-readable PDF. Each returns a file stream.
const organizationId = "your_org_id";
const exchangeId = "your_exchange_id";
const token = "YOUR_TOKEN_HERE";
const authOnly = { Authorization: `Bearer ${token}` };
const url = `https://api.enlivy.com/organizations/${organizationId}/invoices/network-exchanges/${exchangeId}`;
// the signed UBL / XML document
const xml = await fetch(`${url}/download`, { headers: authOnly }).then((r) => r.blob());
// the detached digital signature
const signature = await fetch(`${url}/download-signature`, { headers: authOnly }).then((r) => r.blob());
// the human-readable PDF rendering
const pdf = await fetch(`${url}/download-pdf`, { headers: authOnly }).then((r) => r.blob()); Retrieve the institution-side status and validation details for an exchange, useful when a document comes back as change_required or rejected and you need the reasons to correct and resubmit.
const organizationId = "your_org_id";
const exchangeId = "your_exchange_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/invoices/network-exchanges/${exchangeId}/information`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); API Reference
Bank Transactions from the API
Bring every movement through your accounts into one ledger, then make sense of it. Bank transactions land in Enlivy from bank sync, Stripe payouts, or manual entry, and the API lets you classify them by cost type and reconcile them against the invoices, receipts, and payslips they settle. Each transaction tracks its own state, from backlog to fully connected.
Two resources work together: cost types (your reusable classification vocabulary like “Payroll”, “Client Payment”, “Software”, each declaring what it may be linked to) and bank transactions, the movements themselves. The examples below cover both, plus listing, filtering, reconciling, and analytics.
List the cost types you classify transactions with. Each carries a localized label, whether a link to a business entity is required, and which entity types it may connect to.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/bank-transaction-cost-types?page=1&limit=50`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Define a classification category. Set whether transactions of this type must be reconciled, and, if so, which entity types they may be connected to. Cost types can be nested under a parent for a hierarchy.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/bank-transaction-cost-types`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
title_lang_map: { en: "Client Payment", ro: "Încasare client" }, // per-locale map
// does a transaction of this type have to be linked to a business entity?
connection_required: true,
// which entity types it may be connected to (required when connection_required = true)
// options: invoice | receipt | payslip | bank_transaction | user
connection_types: ["invoice", "receipt"],
// optional: parent cost type for a nested / hierarchical category
organization_bank_transaction_cost_type_id: null
})
}); Query transactions with pagination, search, and filters. Filter by classification state, direction, or by a specific connected entity, and bound by date. Expand the assigned cost type and the connected entities inline.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/bank-transactions?page=1&limit=20` +
// state: backlog | classified | connected | connected_partially | danger | trashed
`&state=backlog&direction=inbound` +
// find transactions connected to a specific entity, send BOTH params together:
// `&connection_entity_type=invoice&connection_entity_id=invoice_id` +
// free-text search with q=... (min 3 chars) instead of ids
`&include=cost_type,connection_entities,bank_account`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Retrieve a single transaction: its amount and currency, direction, the assigned cost type, the entities it’s connected to, and any Stripe payout / reporting metadata for synced transactions.
const organizationId = "your_org_id";
const transactionId = "your_transaction_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/bank-transactions/${transactionId}` +
// includes: organization, bank_account, cost_type, connection_entities, deleted_by_user, tag_ids
`?include=cost_type,connection_entities,bank_account`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Record a transaction manually (most transactions arrive automatically via bank sync or Stripe). You can classify it in the same call by passing a cost type and its connections.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/bank-transactions`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
hash: "unique-dedupe-key", // required; unique within a bank account (import de-dup key)
title: "Incoming transfer from Acme Studio",
amount: 1200.00, // money: signed decimal in MAJOR units (not cents)
// direction is DERIVED from the sign (positive = inbound, negative = outbound)
currency: "EUR",
organization_bank_account_id: "bank_account_id",
sender_label: "ACME STUDIO SRL", // free-text counterpart name from the bank feed
note: "Invoice #2026-0142 settlement"
// state is managed by classification (defaults to "backlog"), no need to set it.
// optionally classify inline with organization_bank_transaction_cost_type_id + connection_entities (see below).
})
}); The heart of the workflow. Assign a cost type to classify the transaction, then connect it to the entities it settles. Enlivy advances the transaction’s state as you go: assigning a cost type marks it classified; connecting entities marks it connected (or connected_partially if the linked amounts don’t cover the full transaction).
const organizationId = "your_org_id";
const transactionId = "your_transaction_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/bank-transactions/${transactionId}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
// 1. Classify, assign a cost type. Moves state: backlog -> classified.
organization_bank_transaction_cost_type_id: "cost_type_id",
// 2. Reconcile, link the transaction to what it pays for.
// connection_entity_type must be one of the cost type's allowed connection_types.
// The array is an UPSERT:
// { connection_entity_type, connection_entity_id, amount } -> create a link
// { id } -> keep an existing link
// { id, _deleted: true } -> remove a link
// (omitting an existing link does NOT delete it)
// Amounts covering the full transaction -> "connected"; partial -> "connected_partially".
connection_entities: [
{ connection_entity_type: "invoice", connection_entity_id: "invoice_id", amount: 1000.00 },
{ connection_entity_type: "receipt", connection_entity_id: "receipt_id", amount: 200.00 }
]
})
}); Read aggregate cash-flow analytics across your transactions: a point-in-time summary or a history_monthly breakdown, scoped by account, direction, state, and date range, and convertible to a single reporting currency.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/bank-transactions/analytics/summary` +
// analyticsType: summary | history_monthly
`?start_date=2026-01-01&end_date=2026-12-31` +
`&direction=outbound&entity_state=connected&convert_to_currency=EUR`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Soft-delete a transaction (its state becomes trashed). It can be restored later.
const organizationId = "your_org_id";
const transactionId = "your_transaction_id";
const token = "YOUR_TOKEN_HERE";
// soft delete, restore via POST /bank-transactions/restore/{transactionId}
fetch(`https://api.enlivy.com/organizations/${organizationId}/bank-transactions/${transactionId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}); API Reference
Tax Management from the API
Enlivy models tax the way Stripe models product tax codes, not one class per country. A tax class is a semantic product category (Standard goods & services, Books, Foodstuffs, Digital services, Exempt), and you tag each product with the category it is, never a percentage by hand. Underneath each class sits a set of tax rates, one per country or selling scenario, and at invoice time Enlivy resolves the single applicable rate from the buyer's country and tax status, taking the highest-priority match.
The examples below cover both layers: the class (the category) and the rates (the country rows that resolve underneath it).
List your product-tax categories. Include tax_rates_overview for a summary of the rate set resolving under each class.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/tax-classes` +
// filters: name, description, ids
`?page=1&limit=20` +
// include tax_rates_overview for a per-class summary of the rate set
`&include=tax_rates_overview`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Create one class per product category you sell. A class is a category, not a country and not a single rate; the country rows live underneath it. Products then point their organization_tax_class_id at the category they belong to.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
// Create one class per product CATEGORY you sell (Standard goods & services, Books,
// Foodstuffs, Accommodation, Digital services / SaaS, Exempt). A class is a category,
// not a country and not a single rate; the country rows live underneath it.
fetch(`https://api.enlivy.com/organizations/${organizationId}/tax-classes`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
// the category, not a rate: per-locale maps
name_lang_map: { en: "Books & publications", ro: "Cărți și publicații" },
description_lang_map: { en: "Reduced-rate category for books and periodicals." }
})
}); Update a category''s labels, or soft-delete it (restore later). Deleting a class removes the category its rate rows resolve under, so remove or reassign those rows first.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
const taxClassId = "your_tax_class_id";
const headers = { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
const url = `https://api.enlivy.com/organizations/${organizationId}/tax-classes/${taxClassId}`;
// Update a category's labels
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify({ name_lang_map: { en: "Books & publications (2026)" } })
});
// soft delete; restore via POST /tax-classes/restore/{taxClassId}
fetch(url, { method: "DELETE", headers }); List the rate rows. Expand the parent class and the locations each row applies to. For a per-class summary, use the class''s tax_rates_overview include instead.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/tax-rates` +
`?page=1&limit=50` +
// includes: organization, organization_tax_class, locations
`&include=organization_tax_class,locations`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); A tax rate is one row in a class''s rate set, not a standalone tax. Each row declares a scope, an EN16931 VAT category, and a priority; at invoice time Enlivy takes the highest-priority matching row. The canonical set: home-country domestic, EU B2B reverse charge, per-country OSS, and a rest-of-world catch-all.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
const headers = { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
const classId = "standard_goods_class_id";
// A tax rate is ONE ROW in a class's rate set, not a standalone tax. Each row declares a
// scope (locations and/or buyer conditions), an EN16931 VAT category (eu_vat_class), and a
// priority. At invoice time Enlivy takes the highest-priority row whose scope + buyer match.
const common = {
organization_tax_class_id: classId,
has_eu_vat_properties: true,
is_compound: false,
is_shipping: false,
is_inclusive: false
};
// The canonical rate set for one category (home country = Romania): four archetypes.
const rateSet = [
{
// Home-country domestic: the default when selling within Romania
name: "RO Domestic 21%", rate: 21, priority: 1000,
eu_vat_class: "S", // Standard-rated, stamped on the invoice line
has_locations: true, locations: [{ country_code: "RO" }]
},
{
// EU B2B reverse charge: 0%, matches ONLY VAT-registered businesses in other EU states
name: "EU B2B Reverse Charge", rate: 0, priority: 900,
eu_vat_class: "AE", vatex_code: "VATEX-EU-AE", // exemption reason (PEPPOL)
is_business_entity: true, is_eu_vat_registered: true, // buyer-qualification gates
has_locations: true, locations: [{ country_code: "DE" }, { country_code: "FR" }]
},
{
// Per-country EU domestic (B2C digital / OSS): charge the buyer's own country rate
name: "DE Domestic 19%", rate: 19, priority: 800,
eu_vat_class: "S",
has_locations: true, locations: [{ country_code: "DE" }]
},
{
// Rest of world: outside scope, 0%, no locations = catch-all fallback
name: "Rest of World (Outside Scope)", rate: 0, priority: 100,
eu_vat_class: "O", vatex_code: "VATEX-EU-O",
has_locations: false
}
];
for (const row of rateSet) {
await fetch(`https://api.enlivy.com/organizations/${organizationId}/tax-rates`, {
method: "POST",
headers,
body: JSON.stringify({ ...common, ...row })
});
} Adjust a single row: change its percentage, VAT category, scope, or priority in the resolution ladder. Send only the fields you are changing.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
const taxRateId = "your_tax_rate_id";
// Adjust a single row: its percentage, VAT category, scope, or priority in the ladder.
// Send only the fields you are changing.
fetch(`https://api.enlivy.com/organizations/${organizationId}/tax-rates/${taxRateId}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
rate: 20, // e.g. the RO domestic rate changes
display_name: "VAT 20%"
})
}); Soft-delete a single row from a class''s set, for example to retire a country you no longer sell into. It can be restored later.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
const taxRateId = "your_tax_rate_id";
// soft delete; restore via POST /tax-rates/restore/{taxRateId}
fetch(`https://api.enlivy.com/organizations/${organizationId}/tax-rates/${taxRateId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}); API Reference
Prospect Management from the API
Wire your lead capture, CRM, and sales automation straight into Enlivy. The Prospects API gives you programmatic control over your pipeline: create leads from any source, move them through your stages, and log every touchpoint as it happens.
The examples below cover the most common prospecting operations: listing and filtering prospects, creating a lead, advancing it through your pipeline, and recording prospect activities like calls, meetings, and status changes, so your timeline always stays in sync.
Pull your pipeline into any dashboard or sync job. Query prospects with pagination, filter by stage, owner, source, or date range, and full-text search by name, company, or email. Expand related records such as the current stage and the assigned team member.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/prospects?page=1&limit=20&source_type=inbound&include=organization_prospect_status,assigned_organization_user&include_meta=navigation`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Retrieve a single prospect with everything attached to it: contact details, source attribution, budget, current pipeline stage, and lifecycle timestamps such as qualified, won, and lost.
const organizationId = "your_org_id";
const prospectId = "your_prospect_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/prospects/${prospectId}?include=organization_prospect_status,assigned_organization_user`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Capture a lead from any source: a landing page, an ad campaign, an outbound list, or your own app. Send a person, a company, or both, tag where it came from, and drop it straight onto your pipeline.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/prospects`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
first_name: "Jane",
last_name: "Doe",
company_name: "Acme Studio",
email: "jane@acme.example",
source_type: "inbound",
source_channel: "website",
source_campaign: "summer-launch",
summary: "Requested a demo from the pricing page.",
budget: "5000",
budget_currency: "EUR"
})
}); Update a prospect’s contact details, owner, budget, summary, or lifecycle state (qualified, disqualified, won, lost). You only send the fields you want to change.
const organizationId = "your_org_id";
const prospectId = "your_prospect_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/prospects/${prospectId}`,
{
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
summary: "Budget confirmed, decision expected next week.",
budget: "8000",
budget_currency: "EUR"
})
}
); Move a prospect one step along your pipeline by following a configured status path. Each advance records who performed it, an optional outcome and note, can link a report, and automatically writes an entry to the prospect’s timeline.
const organizationId = "your_org_id";
const prospectId = "your_prospect_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/prospects/${prospectId}/advance`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
organization_prospect_status_path_id: "status_path_id_here",
outcome: "Qualified, budget and timeline confirmed.",
description: "Moved from New to Qualified after the discovery call."
})
}
); Record a touchpoint on a prospect: a call, a meeting, an email, a note. Activities build the prospect’s timeline and give your team a shared, chronological history of every interaction.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/prospect-activities`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
organization_prospect_id: "prospect_id_here",
title: "Discovery call",
description: "Walked through pricing and the onboarding timeline.",
outcome: "Positive, sending a proposal next week.",
activity_at: "2026-07-03 15:30:00"
})
}
); Read the activity feed across your organization. Expand each entry with the prospect it belongs to, the team member who performed it, and any linked report or status change.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/prospect-activities?page=1&limit=20&include=organization_prospect,performed_by_organization_user&include_meta=navigation`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); 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.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/contracts?page=1&limit=20` +
// filters are optional and combinable
`&direction=outbound&category=core` +
// pass a q=... param instead of ids to run a full-text search
`&include=contract_status,sender_user,receiver_user,contract_parties` +
`&include_meta=navigation`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Retrieve a single contract with everything attached: its chapters, its parties, the current pipeline status, the linked file, and the sender / receiver.
const organizationId = "your_org_id";
const contractId = "your_contract_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/contracts/${contractId}` +
// available includes: organization, parent_contract, sender_user, receiver_user,
// file, contract_status, contract_chapters, contract_parties, contract_prefix
`?include=contract_chapters,contract_parties,contract_status`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/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.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/contracts`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"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",
direction: "outbound", // outbound | inbound
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: [
{
// party_type, party_country_code, first_name, last_name are required on every party
party_type: "organization", // organization | individual
party_country_code: "RO",
// organization parties additionally REQUIRE organization_name + organization_type
organization_name: "Acme Studio SRL",
organization_type: "srl", // value comes from reference data
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
// country-specific `information` (person) and `organization_information` (company)
// JSON blocks are also accepted; their shape is validated against the country schema.
},
{
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
}
]
})
}); Update a contract’s metadata, move it to another status, adjust its chapters, or refine its parties. Send only what you want to change.
const organizationId = "your_org_id";
const contractId = "your_contract_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/contracts/${contractId}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"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"
})
}); Render and download the contract as a PDF, the same document your counterparties see.
const organizationId = "your_org_id";
const contractId = "your_contract_id";
const token = "YOUR_TOKEN_HERE";
// returns a file stream, read it as a blob, not JSON
const pdf = await fetch(
`https://api.enlivy.com/organizations/${organizationId}/contracts/${contractId}/download`,
{
method: "GET",
headers: { Authorization: `Bearer ${token}` }
}
).then((r) => r.blob()); Soft-delete a contract. It can be restored later.
const organizationId = "your_org_id";
const contractId = "your_contract_id";
const token = "YOUR_TOKEN_HERE";
// soft delete, restore via POST /contracts/restore/{contractId}
fetch(`https://api.enlivy.com/organizations/${organizationId}/contracts/${contractId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/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.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/contract-statuses?page=1&limit=50`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/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.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/contract-statuses`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"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."
},
contract_state: "action_required", // draft | action_required | accepted | breach | terminated
direction: "any", // inbound | outbound | 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)"
})
}); 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.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/contract-signatures`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"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", "checkbox"], // draw | checkbox | file_classic | file_electronic
sign_session_required_confirmations: ["email", "legally_binding"], // email | phone | legally_binding
expires_at: "2026-07-17 23:59:59"
})
}); 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.
const organizationId = "your_org_id";
const signatureId = "your_signature_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/contract-signatures/${signatureId}/send`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
method: "email", // email | sms
message: "Please review and sign the agreement by Friday."
})
}
); 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.
const organizationId = "your_org_id";
const signatureId = "your_signature_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/contract-signatures/${signatureId}` +
// sign_session_url returns the hosted link to give to the signer.
// status is one of: pending | sent | completed | expired | void
`?include=sign_session_url,organization_contract`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/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.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/contract-signatures` +
// omit organization_contract_id to list sessions across every contract
`?organization_contract_id=contract_id&include=sign_session_url`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Pull the tamper-evident evidence package (authentication, consent, and signature biometrics captured during signing) for compliance and dispute handling.
const organizationId = "your_org_id";
const contractId = "your_contract_id";
const token = "YOUR_TOKEN_HERE";
// also available per session: /contract-signatures/{signatureId}/download-evidence
const evidence = await fetch(
`https://api.enlivy.com/organizations/${organizationId}/contracts/${contractId}/download-evidence`,
{
method: "GET",
headers: { Authorization: `Bearer ${token}` }
}
).then((r) => r.blob()); API Reference
Product Management from the API
Keep your catalog in sync from your own systems. The Products API gives you programmatic control over the reusable line items you sell (services, digital goods, physical products, and bonuses), each with multi-currency pricing, per-locale names, tax class, and the metadata needed for compliant e-invoicing. Products created here drop straight into invoices, proposals, and billing schedules.
The examples below cover the core operations: listing and searching products, creating one, editing it, and removing it.
Query your catalog with pagination, filtering, and full-text search. Filter by name or description, fetch specific ids, and expand the tax class inline.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/products` +
// filters: name, description, ids (or q=... for full-text search)
`?page=1&limit=20&name=Consulting` +
// includes: organization, tax_class, tag_ids, deleted_by_user
`&include=tax_class`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Add a product to your catalog. A product needs a type and a price_map; everything else (localized names, tax class, barcodes, and e-invoicing metadata) is optional.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/products`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
type: "service", // required: digital | physical | service | bonus
// required: a { currency: amount } map (amounts max 2 decimals).
// With 2+ currencies, primary_currency becomes required.
price_map: { EUR: "49.90", USD: "54.00" },
primary_currency: "EUR",
// per-locale maps (not plain strings)
name_lang_map: { en: "Consulting Hour", ro: "Oră de consultanță" },
unit_lang_map: { en: "hour", ro: "oră" },
description_lang_map: { en: "One hour of advisory services." },
alias: "consulting-hour", // optional; unique per organization (alpha-dash)
organization_tax_class_id: "tax_class_id",
is_sold: true, // whether it is actively offered
// optional e-invoicing metadata (used when the product lands on an invoice line)
invoice_schema_map: {
classification_identifier_cpv: "79411000-8", // CPV code
peppol_billing_unit_code: "HUR" // PEPPOL unit code
},
// optional identifiers
ean_number: null,
upc_number: null,
stripe_product_id_list: ["prod_XXXXXXXX"] // each id must start with "prod_"
})
}); Update any part of a product: reprice it, relabel it, change its tax class, or toggle whether it is sold. Send only the fields you want to change.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
const productId = "your_product_id";
fetch(`https://api.enlivy.com/organizations/${organizationId}/products/${productId}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
// reprice: the price_map replaces the stored one
price_map: { EUR: "59.90", USD: "64.00" },
primary_currency: "EUR",
name_lang_map: { en: "Consulting Hour, Senior" },
is_sold: false
})
}); Soft-delete a product so it is no longer offered. It can be restored later.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
const productId = "your_product_id";
// soft delete; restore via POST /products/restore/{productId}
fetch(`https://api.enlivy.com/organizations/${organizationId}/products/${productId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}); API Reference
Authentication Sessions from the API
Create and retrieve customer-portal authentication sessions for your users, straight from the admin API. A session grants one of your organization’s users scoped, time-boxed access to the customer application (the portal), authenticated by email, phone, or a magic link. Find the user, open a session (by id or by email), then read it back.
Retrieve the users you can open a session for. Filter by email, run a free-text search, or page through the full list to find the right person.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/users?page=1&limit=20` +
// filters: email, created_at_from/to, updated_at_from/to, ids, or q=... for free-text search
`&email=jane@acme.example`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
); Open a session for a specific user by referencing their organization_user_id. This targets exactly one identity, so the session proceeds straight to authentication with no ambiguity.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/user-client-portal-sessions`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
// reference the exact user identity
organization_user_id: "org_user_id",
name: "Jane Doe", // required: display name for the session
// how the user proves identity: email | phone | magic_authentication
authentication_method: "email",
// scope what the session may access in the portal
// options: invoices | receipts | network_exchanges | contracts | reports | payment_methods
permissions: ["invoices", "receipts", "payment_methods"],
// lifetime: set validity_hours OR expires_at (bounded by the server maximum)
validity_hours: 72
})
});
// Response includes: token, status, magic_authentication_url (for magic_authentication),
// authentication_verification_code (for email / phone), permissions, expires_at. Open a session by email instead of a specific id, handy when you only know the address. If the email maps to a single user, the session proceeds directly. If the same email belongs to multiple identities, the session is created in the awaiting_user_selection state and the user is prompted in the portal to choose which identity to authenticate as before continuing.
const organizationId = "your_org_id";
const token = "YOUR_TOKEN_HERE";
fetch(`https://api.enlivy.com/organizations/${organizationId}/user-client-portal-sessions`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
// reference the user by email
email: "jane@acme.example",
name: "Jane Doe", // required: display name for the session
// how the user proves identity: email | phone | magic_authentication
authentication_method: "email",
// scope what the session may access in the portal
// options: invoices | receipts | network_exchanges | contracts | reports | payment_methods
permissions: ["invoices", "receipts", "payment_methods"],
// lifetime: set validity_hours OR expires_at (bounded by the server maximum)
validity_hours: 72
})
});
// Single match -> the session proceeds to authentication.
// Multiple matches -> status "awaiting_user_selection"; the user picks which
// identity to authenticate as in the portal before continuing. Read a session back: its current status, when it was last used, when it expires, and the user it belongs to. Poll the status to see the user move through authentication (including identity selection when the session was opened by email).
const organizationId = "your_org_id";
const sessionId = "your_session_id";
const token = "YOUR_TOKEN_HERE";
fetch(
`https://api.enlivy.com/organizations/${organizationId}/user-client-portal-sessions/${sessionId}` +
// includes: organization_user, organization
`?include=organization_user`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
}
);
// status: pending | email_verification_sent | awaiting_user_selection | success | expired Works together with
- Bank Account Data See every connected account, balance, and transaction in one dashboard. Synced securely, kept current, and linked to the rest of your records.
- Bank Transactions Bring every transaction into one place: synced from your bank, imported from a file, or entered by hand. Then tie each one to the invoice, receipt, or payslip it belongs to, so your records are always connected and reconciled.
- Billing Packages Build a plan once and offer it weekly, monthly, yearly, or anything in between. Customers subscribe, switch cycle, change tier, manage their card, pause, and cancel from a branded portal, with every change previewed, prorated, and collected automatically.
- Billing Schedules Manage every recurring billing relationship in one place. Set up a subscription, retainer, or payment plan, link its invoices and receipts, and see exactly how much has been paid, what is pending, and where each relationship stands.
- Contracts Draft contracts from templates, send them for signature with SMS or email identity verification, and track every signature and renewal. Signed copies are delivered automatically.
- Customer Portal A branded, self-service portal on your own domain where clients accept proposals, pay invoices, manage subscriptions, sign contracts, and submit reports themselves. Every action syncs back to Enlivy in real time.
- Data Export Export your invoices, receipts, payslips, contracts, and transactions in the format and folder structure your accountant expects, for any date range. Built in, no extra cost, ready in seconds.
- Guidelines Document best practices and policies in one place. Keep your team aligned with clear, accessible guidelines.
- Invoices Create a compliant invoice in seconds, send it, and watch it link itself to the contract, payment, and bank transaction it belongs to. EU e-invoicing is built in, so the work between issuing and getting paid happens in one place.
- 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.
- Network Exchanges Send and receive e-invoices automatically, straight through ANAF eFactura today, with PEPPOL and other EU platforms on the same rails. Incoming invoices pull in on their own, outgoing ones push out on your schedule, and every exchange keeps a full history. No XML files, no manual uploads.
- Payslips Build a payslip template once with the fields your business needs, then generate payslips for every employee in minutes. Each one links to its contract, payment, and bank transaction, so the whole record stays connected and traceable.
- Playbooks Design, execute, and refine step-by-step procedures for any workflow. Ensure consistency, reduce errors, and guide your team through repeatable tasks with built-in structure and clarity.
- Products Build a reusable catalog of everything you sell, services or goods, with pricing, units, tax settings, and descriptions set once. Every product is ready to drop into a quote or invoice in seconds.
- Prospects Track every opportunity from first contact to paid invoice, with a complete activity history, automatic status-driven emails, and client collaboration built in.
- Receipts Receipts gives you a structured record of every payment, money in and money out: linked to your invoices and contracts, with your cashflow always up to date.
- Reports Replace scattered updates in chat and email with structured reports your team fills in on schedule. You define the questions once with a reusable schema, the right people get the right report at the right time, and every answer lands in one place, ready to compare.
- Slack Integration Stop checking dashboards to find out what changed. Enlivy brings the important moments from your business directly into Slack, from payments and proposals to contracts and customer activity. Connect once, choose your events, route them to the right channels, and keep your team aligned in real time.
- Taxes Stop picking VAT rates by hand. Assign a tax class to a product or invoice line and Enlivy resolves the correct rate automatically, based on who the customer is and where they are, with the right EU codes for e-invoicing built in.
- Users Easily customize roles and permissions in Enlivy for clients, partners, accountants, and administrators, ensuring secure and efficient access with full audit trails for compliance.
- Webhooks The moment something happens in Enlivy, an invoice is paid, a transaction lands, a user changes, a webhook fires to your system. React in real time instead of polling for changes or waiting on reports.