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,
]);