LionVoice API v1

基础 URL: https://api.lionvoice.app/api/v1。语音、Lion-AI 和电话 — 一个产品。大脑在产品里一律叫 Lion-AI;引擎标识是内部的,API 响应里可选。

Base URL: https://api.lionvoice.app/api/v1

API 没有模型选择参数 — 对外露出的大脑只有 Lion-AI。

5分钟开发者快速开始

1. 在控制台(API密钥)创建 API 密钥 — 密钥只显示一次。2. 创建坐席。3. 挂上电话号码(E.164)并映射到坐席。4. 打一通测试外呼。

export LV_KEY='lv_live_…'

# 1) who am I
curl -sS https://api.lionvoice.app/api/v1/tenant \
  -H "Authorization: Bearer $LV_KEY"

# 2) create an agent
curl -sS https://api.lionvoice.app/api/v1/agents \
  -H "Authorization: Bearer $LV_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name":"Reception",
    "language":"en",
    "voice":"Lion-AI Warm",
    "prompt":"You are a receptionist. Address the caller as you.",
    "first_message":"Hi, how can I help?",
    "max_duration_sec":600
  }'

# 3) attach a number
curl -sS https://api.lionvoice.app/api/v1/phone-numbers \
  -H "Authorization: Bearer $LV_KEY" \
  -H "Content-Type: application/json" \
  -d '{"number_e164":"+37052431010","label":"Reception"}'

# 4) test outbound (use your own test line)
curl -sS https://api.lionvoice.app/api/v1/calls \
  -H "Authorization: Bearer $LV_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to_number":"+447554522255","agent_id":1}'

认证

Create a key in the dashboard (API keys) or POST /keys. The secret is shown once. Send it as Bearer or X-LV-Api-Key. Ping does not need a key. A revoked key returns 401.

curl -sS https://api.lionvoice.app/api/v1/tenant \
  -H "Authorization: Bearer lv_live_…"
# or
  -H "X-LV-Api-Key: lv_live_…"

速率限制:每个 API 密钥每分钟 120 次。HTTP 429 可用指数退避重试。Header Retry-After 为 60 秒。

GET /ping

Headers: none. Auth: none.

# Response 200
{
  "ok": true,
  "service": "LionVoice API",
  "version": "v1",
  "time": "2026-09-07T09:00:00+00:00"
}

GET /tenant

Headers: Authorization: Bearer lv_live_…

# Response 200
{
  "ok": true,
  "tenant": {
    "id": 1,
    "name": "AURIUS INTERNATIONAL LTD",
    "email": "ops@example.invalid",
    "plan": "studio",
    "plan_included_minutes": 500,
    "overage_eur_per_min": 0.09,
    "balance_eur": 12.50,
    "webhook_signing": {
      "algorithm": "hmac-sha256",
      "header": "X-LV-Signature",
      "prefix": "269d7d4b"
    },
    "sip": {
      "server": "sip.example.com",
      "username": "200",
      "port": 5060,
      "transport": "udp",
      "caller_id": "+37052431010",
      "status": "registered"
    },
    "features": {
      "callback_memory": 1,
      "named_greeting": 1,
      "cli_identity": 1,
      "birthday_calls": 0,
      "crm_bridge": 0
    },
    "modules": {
      "voice": true,
      "email_ai": true,
      "chat_ai": true
    },
    "email_mailbox": "t1@email.lionvoice.app",
    "email_mailbox_status": "ready"
  }
}
FieldMeaning
planCurrent plan slug
plan_included_minutesMinutes included this month
balance_eurWallet
sipHost / user / port / transport / status — never the password
webhook_signing.prefixFirst 8 chars of the HMAC secret. Full secret is not on GET /tenant.
features.callback_memoryRemind why I already called this number
features.named_greetingGreet first + last name from billing
features.cli_identityAuthorise by caller number
features.birthday_callsBirthday / care campaigns
features.crm_bridgePaid CRM / accounting attach (+€79/mo)
modules.email_aiEmail AI entitled (manage via /email)
modules.chat_aiChat AI entitled (manage via /chat)
email_mailboxInbound forward address (no password)

坐席

GET /agents · POST /agents · GET /agents/{id} · PATCH /agents/{id} · DELETE /agents/{id}

Headers: Authorization: Bearer lv_live_… · Content-Type: application/json

# POST /agents  Body
{
  "name": "Reception",
  "language": "en",
  "voice": "Lion-AI Warm",
  "prompt": "You are a receptionist. Address the caller as you.",
  "first_message": "Hi, how can I help?",
  "max_duration_sec": 600,
  "first_speaker": "assistant",
  "webhook_url": "https://example.com/lionvoice/hooks"
}

# Response 200
{
  "ok": true,
  "agent": {
    "id": 12,
    "name": "Reception",
    "language": "en",
    "voice": "Lion-AI Warm",
    "engine": "Lion-AI",
    "max_duration_sec": 600,
    "webhook_url": "https://example.com/lionvoice/hooks"
  }
}

知识

GET /files · POST /files {"filename","content","agent_id?"} · GET/PATCH/DELETE /files/{id}. Max a few pages per file (500 KB).

工具

GET /tools. Create in the dashboard. The engine POSTs to your url with the secret header you set. CRM bridge add-on €79/mo.

电话号码

POST /phone-numbers

{
  "number_e164": "+37052431010",
  "label": "Reception"
}

PATCH /phone-numbers/{id} {"agent_id","inbound_enabled":true}

SIP / VoIP

Not a public REST write (password stays in the vault). Dashboard → SIP / VoIP: host, port, username, password, transport. LionVoice registers like a softphone. Then map the DID under Phone numbers.

通话

分页: GET /calls 接受 limit(1–200,默认 25)和 offset(0+)。还没有游标。用更大的 offset 再请求即可翻页。

GET /calls?limit=25&offset=0&agent_id=

# Response
{ "ok": true, "calls": [
  {
    "call_uuid": "6c202718-…",
    "direction": "inbound",
    "from_number": "+447554522255",
    "to_number": "+37052431010",
    "status": "completed",
    "billable_seconds": 42,
    "cost_eur": 0.00
  }
]}

GET /calls/{uuid} — transcript + recording URL.

{
  "ok": true,
  "call": {
    "call_uuid": "6c202718-…",
    "transcript": "Lion-AI: Hi…\nCustomer: …",
    "summary": "Invoice balance question",
    "recording_url": "https://app.lionvoice.app/app/recording.php?uuid=…"
  }
}

POST /calls — outbound. Body field is to_number (E.164), plus agent_id and optional schedule_at (UTC).

curl -sS https://api.lionvoice.app/api/v1/calls \
  -H "Authorization: Bearer lv_live_…" \
  -H "Content-Type: application/json" \
  -d '{"to_number":"+447554522255","agent_id":1}'

POST /calls/{uuid}/transfer {"to"} E.164 or SIP URI.

Schedules

GET /schedules · DELETE /schedules/{id}. schedule_at is UTC.

Analytics / usage / billing

GET /analytics?days=14 · GET /usage?year=&month= · GET /plans · POST /topup {"amount_eur"} · POST /checkout.

API keys

POST /keys {"label"} — full secret only on create. DELETE /keys?id=.

POST /webhook-secret/regenerate

Headers: Authorization: Bearer lv_live_…. Rotates the HMAC key used for X-LV-Signature. The full secret is returned once (same pattern as POST /keys). GET /tenant never returns it. After rotate, the previous secret stops verifying immediately — update your receiver first.

curl -sS -X POST https://api.lionvoice.app/api/v1/webhook-secret/regenerate \
  -H "Authorization: Bearer $LV_KEY"

# Response 201
{
  "ok": true,
  "webhook_secret": "hex64…",
  "prefix": "269d7d4b",
  "note": "Save this secret now — it is not returned on GET /tenant."
}

Webhooks

租户 webhooks(控制台或 POST /v1/webhooks):https URL + 事件勾选。HMAC X-LV-Signature t=<unix>,v1=<hmac of timestamp + "." + raw body>。密钥只显示一次。返回 2xx。按 id(event_id)去重;重试用新的 delivery_id。坐席 webhook_url 仍可作为 call.ended 的旧订阅者。

Beginner — Create a webhook

在控制台打开 Webhooks,粘贴你的 https URL,勾选事件,点创建。复制一次签名密钥,然后测试 webhook。没有要维护的 ZIP。

Dashboard: app.lionvoice.app/app/?page=webhooks — paste https URL, tick events, Create, copy the secret once, then Test webhook.

Intermediate — Events, HMAC, retries

Events: call.started, call.answered, call.ended, call.failed, transcript.completed, recording.ready, tool.executed.

HTTPS only. HMAC header X-LV-Signature: t=<unix>,v1=<hex> over timestamp + "." + raw body. Reject timestamps older than five minutes. Return 2xx. Deduplicate on id (event_id). A retry is a new delivery_id. Delivery logs store status, HTTP, time, event_id, delivery_id — not the payload.

# Headers
X-LV-Event: call.ended
X-LV-Delivery-Id: del_01J…
X-LV-Timestamp: 1757232000
X-LV-Signature: t=1757232000,v1=hexhmac

# Body (no transcript / phone in test events)
{
  "id": "evt_01J…",
  "type": "call.ended",
  "created_at": "2026-09-07T09:00:00+00:00",
  "data": {
    "call_id": "6c202718-…",
    "duration_sec": 84,
    "status": "completed"
  }
}

Developer — Webhook API

POST   /v1/webhooks
GET    /v1/webhooks
DELETE /v1/webhooks/{id}
POST   /v1/webhooks/{id}/test
POST   /v1/webhooks/{id}/rotate-secret
GET    /v1/webhooks/{id}/deliveries
GET    /v1/webhooks/snippet?lang=php

Same engine as the dashboard. Agent webhook_url remains a legacy subscriber for call.ended.

Email AI

Control the Email AI mailbox from your own CRM / helpdesk. Requires modules.email_ai=true. Without the module → 403 module_not_enabled.

Dashboard: app.lionvoice.app/app/?page=email

Endpoints

GET    /v1/email
GET    /v1/email/branding
PATCH  /v1/email/branding
GET    /v1/email/messages?limit=25&offset=0
GET    /v1/email/messages/{id}
GET    /v1/email/usage

Status + branding

curl -sS -H "Authorization: Bearer lv_live_…" \
  https://api.lionvoice.app/api/v1/email

# PATCH branding (logo, theme dark|light|neutral, font_key, header/footer HTML)
curl -sS -X PATCH -H "Authorization: Bearer lv_live_…" \
  -H "Content-Type: application/json" \
  -d '{"theme":"neutral","logo_url":"https://cdn.example.com/logo.png","footer_html":"<p>Thanks</p>"}' \
  https://api.lionvoice.app/api/v1/email/branding

Message history

List returns metadata only (has_body_in / has_body_out). Detail returns full body_in / body_out. Never stores or returns mailbox IMAP passwords.

curl -sS -H "Authorization: Bearer lv_live_…" \
  "https://api.lionvoice.app/api/v1/email/messages?limit=10"

curl -sS -H "Authorization: Bearer lv_live_…" \
  https://api.lionvoice.app/api/v1/email/messages/42

Chat AI

Configure the website chat widget and read session transcripts from your systems. Requires modules.chat_ai=true.

Public visitor endpoint (no API key — CORS / origin allowlist): POST https://lionvoice.app/api/lv-chat.php

Endpoints

GET    /v1/chat
GET    /v1/chat/widget
PATCH  /v1/chat/widget
GET    /v1/chat/sessions?limit=20
GET    /v1/chat/sessions/{session_key}
GET    /v1/chat/usage

Widget

curl -sS -H "Authorization: Bearer lv_live_…" \
  https://api.lionvoice.app/api/v1/chat

curl -sS -X PATCH -H "Authorization: Bearer lv_live_…" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"primary_color":"#0abfdc","position":"br","launcher_text":"Chat","greeting":{"en":"Hi — how can I help?","lt":"Labas — kuo galiu padėti?"},"origins":["https://example.com"]}' \
  https://api.lionvoice.app/api/v1/chat/widget

Embed snippet is returned on GET /chat as embed_snippet. Positions: br bl tr tl.

Sessions

curl -sS -H "Authorization: Bearer lv_live_…" \
  https://api.lionvoice.app/api/v1/chat/sessions

curl -sS -H "Authorization: Bearer lv_live_…" \
  https://api.lionvoice.app/api/v1/chat/sessions/a1b2c3d4e5f67890

Telegram alerts (BYO bot)

Bring your own BotFather token. LionVoice never returns the token after save. Alerts for Email AI inbound/outbound and Chat AI replies.

Endpoints

GET    /v1/telegram
POST   /v1/telegram            {"bot_token":"123:AA…"}
PATCH  /v1/telegram            {"notify_email":true,"notify_chat":true}
DELETE /v1/telegram
POST   /v1/telegram/link       # after you tap Start in Telegram
POST   /v1/telegram/test
curl -sS -X POST -H "Authorization: Bearer lv_live_…" \
  -H "Content-Type: application/json" \
  -d '{"bot_token":"123456:AA…"}' \
  https://api.lionvoice.app/api/v1/telegram
# → open bot_link, tap Start, then:
curl -sS -X POST -H "Authorization: Bearer lv_live_…" \
  https://api.lionvoice.app/api/v1/telegram/link

Integrations (Stripe + accounting)

Paid module (billing_integrations, from Billing). Without it, API returns 403; the dashboard still shows Integrations with an upsell.

Custom connector: if your accounting app is not in the catalogue but has API docs — email hello@lionvoice.app the link. Same-day install when docs are clear.

Paste your Stripe secret and/or accounting API token in the dashboard (?page=integrations). LionVoice encrypts credentials and uses them so Voice, Chat and Email can look up your customers — who to serve, open invoices, payer codes — without inventing data.

Live today: Stripe (BYOK), Invoice123, F-sąskaita. Other majors (Xero, QuickBooks, Zoho Books, Exact, Sage, FreshBooks, Moneybird, FreeAgent, Holded, bexio, sevDesk, lexoffice, Wave, Saskaitos.lt, …) appear in the catalogue; OAuth / full sync ships next — you can already store keys where the provider uses a static token.

Platform Stripe (your LionVoice subscription) stays separate from tenant BYOK.

REST

MethodPathNotes
GET/integrationsCatalogue + connection status (secrets masked)
GET/integrations/{provider}One provider + connection
PUT/PATCH/POST/integrations/{provider}Body: credentials map or flat fields; optional enabled, test:true
POST/integrations/{provider}/testLive ping to provider API
DELETE/integrations/{provider}Disconnect / wipe credentials
GET/POST/billing/lookupemail and/or phone / caller_id → customer context

Save Stripe (example)

curl -sS -X PUT https://api.lionvoice.app/api/v1/integrations/stripe \
  -H "Authorization: Bearer lv_live_…" \
  -H "Content-Type: application/json" \
  -d '{"secret_key":"sk_live_…","enabled":true,"test":true}'

Customer lookup (example)

curl -sS "https://api.lionvoice.app/api/v1/billing/lookup?email=client@example.com" \
  -H "Authorization: Bearer lv_live_…"

Voice agents also get a customer_billing_lookup tool pointing at the same lookup. Call-config injects a short billing context when the CLI phone matches a connected provider.

Docs: Invoice123 · F-sąskaita Postman

Books &amp; invoicing

Mini accounting for tenants: invoices (SF), payment notices (PN), cash receipts (PPK), received (supplier) invoices, clients, products/services, recurring schedules, banks, statement import and a client self-service portal. Dashboard: app.lionvoice.app/app/?page=books.

All amounts are integer cents (*_cents). Documents use the tenant logo, company type (UAB / individual activity / public / budgetary institution), VAT-payer flag and one of three selectable templates; the footer always keeps the lionvoice.app credit.

Dashboard pages

PageWhat it does
?page=books&tab=dashboardIncome / expenses / profit, VAT threshold, monthly chart
?page=books&tab=invoicesIssue, preview, PDF, email, mark paid (with bank + method), edit, create a PN from an invoice
?page=books&tab=clientsClient list; open a client for totals, invoices, recurring services, edit, “View as client”
?page=books&tab=expensesSupplier invoices; smart scan (image/PDF) extracts supplier, VAT, lines and saves
?page=books&tab=recurringRecurring SF/PN schedules (interval, max count, contract, price after contract, notes)
?page=books&tab=itemsProduct / service catalogue (edit included)
?page=books&tab=receiptsCash receipts (PPK), edit + email
?page=books&tab=banksBank / Maxima till / Perlo terminal accounts, statement import, matching, collected totals
?page=books&tab=settingsSeller details, VAT payer + company type, logo, invoice template, numbering

Bank statement import

Upload CSV/TSV/TXT/XLS/PDF from a bank, Maxima till or Perlo terminals (?page=books&tab=banks). The system parses the rows, stores them in lv_books_bank_tx, and auto-matches incoming payments to unpaid invoices (amount + counterparty / invoice number); unmatched rows can be assigned manually. When matched, the invoice is marked paid with the chosen bank.

Client self-service portal

Passwordless magic link. The tenant’s client opens it and sees their summary, invoices (with online-pay buttons), payment history and recurring-service progress.

Magic link: GET /api/lv-client-portal.php?token=<48hex>&lang=lt — the token is stored hashed, valid 14 days. A tenant can open it directly from the client page via View as client (no password).

Email chooser (shared marketplace): GET /api/lv-client-portal.php?email=client@example.com lists every LionVoice vendor account for that email; choosing one emails a sign-in link. This is how a client who uses several vendors picks the right account.

Optional parameters: lang=lt|en. PDFs are streamed from /api/lv-books-pdf.php?doc=invoice|receipt&id=&format=pdf&lang=.

Invoice template preview

GET /api/lv-books-template-preview.php?tpl=tpl1|tpl2|tpl3&lang=lt&t=<tenant_id>&format=html|pdf renders a sample document with the tenant branding — used by the template picker’s “Preview sample” link.

Received-invoice smart scan

Dashboard ?page=books&tab=expenses&new=1 → upload an image or PDF; supplier name, codes, invoice number/dates, net/VAT/total and line items are extracted and saved without manual entry. Server-side only; provider name is never shown to clients.

Provider payment webhooks (BYOK)

Clients bring their own credentials. In ?page=integrations they pick a provider — Wise, URBO, Paysera, ContoQuick, Stripe, Invoice123, F-sąskaita and others — and paste their keys; credentials are encrypted per tenant. Providers using a static token or webhook secret are usable immediately; OAuth/full sync ships connector by connector.

Generic receiver (records an incoming payment and auto-matches an invoice):

POST /api/lv-integration-webhook.php?provider=wise&t=<tenant_id>&secret=<webhook_secret>
Header alternative: X-LV-Signature: <webhook_secret>
Body (JSON): { "amount": "120.00", "date": "2026-09-18",
               "sender_name": "Acme", "reference": "SF-202609-0001" }

Accepted amount fields: amount, amount_cents, value, sum, total, gross. Counterparty: counterparty, sender_name, payer_name, customer_name, name. Reference: reference, invoice_number, description, details. Wrong or missing secret → 403; missing amount → 422.

Wise connection is live-tested via GET /v1/profiles (BYOK token) and shows the profile count. Paysera Checkout generates a signed hosted-payment redirect (data + ss1 = md5(data + sign_password)); the callback returns to the generic webhook above and auto-matches the invoice.

Documentation: Wise · URBO · Paysera · ContoQuick

Email AI identity

The sender address is assigned by the system and shown read-only. From name and Signature are pulled from the tenant requisites; open ?page=email_ai and press Edit to change them. Changing the mailbox itself is support-only.

REST API (Books)

All paths are under https://api.lionvoice.app/api/v1 with Authorization: Bearer lv_live_…. Requires modules.books=true; otherwise 403 module_not_enabled. Amounts are integer cents.

MethodPathNotes
GET / PATCH/books/profileSeller details, bank, VAT payer, company type, template (tpl1|tpl2|tpl3)
GET / POST/books/invoices?limit=; POST body: buyer_name, buyer_email, client_id, bank_id, notes, issue_date, due_date, lang, items[]
GET / PATCH / DELETE/books/invoices/{id}Read, edit (buyer, dates, notes, status, bank), delete
GET/books/invoices/{id}/downloadStreams the invoice PDF
POST/books/invoices/{id}/mark-paidBody: bank_id, method (bank/card/cash/other)
POST/books/invoices/{id}/sendEmails the PDF to the buyer
POST/books/invoices/{id}/make-pnCreates a PN (payment notice) copy
GET / POST/books/clientsList / create (payer code, personal code, client type, notes)
GET / PATCH / DELETE/books/clients/{id}Client + stats (month/year/unpaid/paid + invoices)
GET / POST/books/expensesReceived (supplier) invoices
PATCH / DELETE/books/expenses/{id}Edit / delete
GET / POST/books/itemsProducts / services catalogue
PATCH / DELETE/books/items/{id}Edit / delete
GET / POST/books/receiptsCash receipts (PPK)
PATCH / DELETE/books/receipts/{id}Edit / delete
GET/books/recurringRecurring schedules
PATCH / DELETE/books/recurring/{id}Edit (interval, max, contract, notes) / delete
GET / POST/books/banksBank / Maxima till / Perlo accounts + collected totals
DELETE/books/banks/{id}Remove account
GET/books/bank-txImported statement payments (?limit=)
POST/books/bank-tx/{id}/assignBody: invoice_id — match + mark paid
POST/books/bank-tx/{id}/ignoreIgnore a row
POST/books/portal-linkBody: client_id, optional ttl_days, lang → returns a passwordless portal URL
POST/books/invoices/{id}/payment-linkCreates a hosted payment link with the tenant’s connected provider (Paysera Checkout signed redirect) and stores it on the invoice; body: optional lang, test

Examples

# Create an invoice
curl -sS -X POST https://api.lionvoice.app/api/v1/books/invoices \
  -H "Authorization: Bearer " -H "Content-Type: application/json" \
  -d '{"buyer_name":"Acme","buyer_email":"billing@acme.example","notes":"Thanks!",
       "items":[{"description":"AI calls pack","qty":1,"unit_cents":15000}]}'

# Mark it paid via a bank
curl -sS -X POST https://api.lionvoice.app/api/v1/books/invoices/12/mark-paid \
  -H "Authorization: Bearer " -H "Content-Type: application/json" \
  -d '{"bank_id":1,"method":"bank"}'

# Passwordless client portal link
curl -sS -X POST https://api.lionvoice.app/api/v1/books/portal-link \
  -H "Authorization: Bearer " -H "Content-Type: application/json" \
  -d '{"client_id":5,"ttl_days":14,"lang":"lt"}'

错误

形状: {"ok":false,"error":"code","message":"…"}。可重试: 429 和 5xx。不可重试: 400、401、403、404。409 通常不可。

{
  "ok": false,
  "error": "insufficient_balance",
  "message": "Your wallet balance is too low."
}

# Email / Chat when module off
{
  "ok": false,
  "error": "module_not_enabled",
  "module": "email_ai",
  "hint": "Enable this module in the dashboard Billing / Modules, then retry."
}
HTTPRetry?Typical error
400Novalid_to_number_required
401Nounauthorized
403Noplan / cap
404Nonot_found
409Usually noconflict
429Yes, exponential backoffrate_limited
500Yesengine

SDKs

官方客户端在路线图上。今天:复制下面的 curl、PHP、JavaScript 和 Python 示例。把 OpenAPI 文件(/openapi.json)导入 Postman。

# JavaScript
const r = await fetch('https://api.lionvoice.app/api/v1/tenant', {
  headers: { Authorization: 'Bearer lv_live_…' }
});

# Python
import requests
requests.get('https://api.lionvoice.app/api/v1/ping').json()

# PHP
$ch = curl_init('https://api.lionvoice.app/api/v1/tenant');
curl_setopt_array($ch, [
  CURLOPT_HTTPHEADER => ['Authorization: Bearer lv_live_…'],
  CURLOPT_RETURNTRANSFER => true,
]);