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。
基础 URL: https://api.lionvoice.app/api/v1。语音、Lion-AI 和电话 — 一个产品。大脑在产品里一律叫 Lion-AI;引擎标识是内部的,API 响应里可选。
Base URL: https://api.lionvoice.app/api/v1
API 没有模型选择参数 — 对外露出的大脑只有 Lion-AI。
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 秒。
Headers: none. Auth: none.
# Response 200
{
"ok": true,
"service": "LionVoice API",
"version": "v1",
"time": "2026-09-07T09:00:00+00:00"
}
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"
}
}
| Field | Meaning |
|---|---|
plan | Current plan slug |
plan_included_minutes | Minutes included this month |
balance_eur | Wallet |
sip | Host / user / port / transport / status — never the password |
webhook_signing.prefix | First 8 chars of the HMAC secret. Full secret is not on GET /tenant. |
features.callback_memory | Remind why I already called this number |
features.named_greeting | Greet first + last name from billing |
features.cli_identity | Authorise by caller number |
features.birthday_calls | Birthday / care campaigns |
features.crm_bridge | Paid CRM / accounting attach (+€79/mo) |
modules.email_ai | Email AI entitled (manage via /email) |
modules.chat_ai | Chat AI entitled (manage via /chat) |
email_mailbox | Inbound 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}
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.
GET /schedules · DELETE /schedules/{id}. schedule_at is UTC.
GET /analytics?days=14 · GET /usage?year=&month= · GET /plans · POST /topup {"amount_eur"} · POST /checkout.
POST /keys {"label"} — full secret only on create. DELETE /keys?id=.
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(控制台或 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 的旧订阅者。
在控制台打开 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.
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"
}
}
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.
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
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
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
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
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
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
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.
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
Bring your own BotFather token. LionVoice never returns the token after save. Alerts for Email AI inbound/outbound and Chat AI replies.
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
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.
| Method | Path | Notes |
|---|---|---|
| GET | /integrations | Catalogue + 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}/test | Live ping to provider API |
| DELETE | /integrations/{provider} | Disconnect / wipe credentials |
| GET/POST | /billing/lookup | email and/or phone / caller_id → customer context |
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}'
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
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.
| Page | What it does |
|---|---|
?page=books&tab=dashboard | Income / expenses / profit, VAT threshold, monthly chart |
?page=books&tab=invoices | Issue, preview, PDF, email, mark paid (with bank + method), edit, create a PN from an invoice |
?page=books&tab=clients | Client list; open a client for totals, invoices, recurring services, edit, “View as client” |
?page=books&tab=expenses | Supplier invoices; smart scan (image/PDF) extracts supplier, VAT, lines and saves |
?page=books&tab=recurring | Recurring SF/PN schedules (interval, max count, contract, price after contract, notes) |
?page=books&tab=items | Product / service catalogue (edit included) |
?page=books&tab=receipts | Cash receipts (PPK), edit + email |
?page=books&tab=banks | Bank / Maxima till / Perlo terminal accounts, statement import, matching, collected totals |
?page=books&tab=settings | Seller details, VAT payer + company type, logo, invoice template, numbering |
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.
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=.
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.
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.
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
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.
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.
| Method | Path | Notes |
|---|---|---|
| GET / PATCH | /books/profile | Seller 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}/download | Streams the invoice PDF |
| POST | /books/invoices/{id}/mark-paid | Body: bank_id, method (bank/card/cash/other) |
| POST | /books/invoices/{id}/send | Emails the PDF to the buyer |
| POST | /books/invoices/{id}/make-pn | Creates a PN (payment notice) copy |
| GET / POST | /books/clients | List / create (payer code, personal code, client type, notes) |
| GET / PATCH / DELETE | /books/clients/{id} | Client + stats (month/year/unpaid/paid + invoices) |
| GET / POST | /books/expenses | Received (supplier) invoices |
| PATCH / DELETE | /books/expenses/{id} | Edit / delete |
| GET / POST | /books/items | Products / services catalogue |
| PATCH / DELETE | /books/items/{id} | Edit / delete |
| GET / POST | /books/receipts | Cash receipts (PPK) |
| PATCH / DELETE | /books/receipts/{id} | Edit / delete |
| GET | /books/recurring | Recurring schedules |
| PATCH / DELETE | /books/recurring/{id} | Edit (interval, max, contract, notes) / delete |
| GET / POST | /books/banks | Bank / Maxima till / Perlo accounts + collected totals |
| DELETE | /books/banks/{id} | Remove account |
| GET | /books/bank-tx | Imported statement payments (?limit=) |
| POST | /books/bank-tx/{id}/assign | Body: invoice_id — match + mark paid |
| POST | /books/bank-tx/{id}/ignore | Ignore a row |
| POST | /books/portal-link | Body: client_id, optional ttl_days, lang → returns a passwordless portal URL |
| POST | /books/invoices/{id}/payment-link | Creates a hosted payment link with the tenant’s connected provider (Paysera Checkout signed redirect) and stores it on the invoice; body: optional lang, test |
# 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."
}
| HTTP | Retry? | Typical error |
|---|---|---|
| 400 | No | valid_to_number_required |
| 401 | No | unauthorized |
| 403 | No | plan / cap |
| 404 | No | not_found |
| 409 | Usually no | conflict |
| 429 | Yes, exponential backoff | rate_limited |
| 500 | Yes | engine |
官方客户端在路线图上。今天:复制下面的 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,
]);