Developers
Build on Vantra
Vantra is a governed backend for clinic communication — so a practice-management system, a website form, or an agency tool can integrate Vantra rather than the other way round. The public API is deliberately small: push leads in, read appointments back, and drop the agent onto any website with one line. Every request is authenticated with a per-clinic API key, and everything below is live today.
Quickstart
1. Create an API key
A clinic manager mints a key in the dashboard under Settings → API keys. The key (vk_ followed by 64 hex characters) is shown once at creation — store it in a secret manager, never in client-side code. Revoking is immediate.
2. Install the SDK
The official TypeScript/JavaScript client wraps auth, retries and typed errors. Or call the REST API directly with any HTTP client.
npm install @vantra/sdk3. Make your first call
Push a lead into the clinic's pipeline — the same pipeline every channel feeds. Creating a lead never places a call; outbound stays behind the clinic's own settings.
import { VantraClient } from "@vantra/sdk";
const vantra = new VantraClient({ apiKey: process.env.VANTRA_API_KEY! });
await vantra.leads.create({
phone: "+905551112233",
name: "Jane Doe",
note: "Asked about whitening",
});Authentication
- Every request carries the header Authorization: Bearer vk_… — one key per clinic.
- Keys are minted in the dashboard (Settings → API keys). The plaintext is shown exactly once; only its SHA-256 hash is stored.
- Creation and revocation are written to the tamper-evident audit log. Revoking is a tombstone — an old key stops working immediately but stays auditable.
| Rate limit | Allowance |
|---|---|
| Lead writes (POST /leads) | 120 requests / minute / key |
| Appointment reads (GET /appointments) | 60 requests / minute / key |
API reference
/api/public/v1/leadsCreate a lead
Push a lead into the clinic's pipeline (the same leads collection the dashboard, dossier and reactivation all read). Idempotent — leads are keyed by phone. This never queues a call; outbound stays behind the clinic's own settings, calling windows and Call List.
| Body | Type | Required | Notes |
|---|---|---|---|
phone | string | Yes | E.164 preferred (+905551112233); national formats are normalized server-side. |
name | string | — | Full name. |
email | string | — | Email address. |
note | string | — | Free text; stored as the lead summary (truncated to 500 chars). |
curl -X POST https://www.vantra.xyz/api/public/v1/leads \
-H "Authorization: Bearer $VANTRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"+905551112233","name":"Jane Doe","note":"Asked about whitening"}'{ "ok": true }/api/public/v1/appointmentsList appointments
Read the clinic's appointment rows for reconciliation against an external system of record. The window defaults to the next 14 days, is capped at 92 days, and returns at most 1000 rows. Patient fields are included by design — the caller is the clinic's own system, holding the clinic's own data (treat it as PHI).
| Query | Type | Required | Notes |
|---|---|---|---|
from | ISO datetime | — | Window start. Defaults to now. |
to | ISO datetime | — | Window end. Defaults to from + 14 days. Windows over 92 days are clamped. |
curl "https://www.vantra.xyz/api/public/v1/appointments?from=2026-07-01T00:00:00Z&to=2026-07-14T00:00:00Z" \
-H "Authorization: Bearer $VANTRA_API_KEY"{
"clinic_id": "clinic_123",
"from": "2026-07-01T00:00:00.000Z",
"to": "2026-07-14T00:00:00.000Z",
"appointments": [
{
"id": "appt_1",
"start": "2026-07-02T09:00:00.000Z",
"end": "2026-07-02T09:30:00.000Z",
"status": "scheduled",
"service": "Cleaning",
"patient_name": "Jane Doe",
"patient_phone": "+905551112233",
"doctor_id": "doc_7",
"source": "ai_whatsapp"
}
]
}Official SDK — @vantra/sdk
The official TypeScript/JavaScript client. Fully typed, zero runtime dependencies, and runs anywhere fetch does — Node 18+, browsers, and edge runtimes. It handles bearer auth, retries transient failures (429/5xx) with backoff, and throws typed errors you can branch on (VantraAuthError, VantraRateLimitError, VantraValidationError).
npm install @vantra/sdkimport { VantraClient, VantraRateLimitError } from "@vantra/sdk";
const vantra = new VantraClient({ apiKey: process.env.VANTRA_API_KEY! });
// Push a lead
await vantra.leads.create({ phone: "+905551112233", name: "Jane Doe" });
// Read upcoming appointments (defaults to the next 14 days)
const { appointments } = await vantra.appointments.list();
for (const appt of appointments) {
console.log(appt.start, appt.status, appt.patientName);
}
// Errors are typed
try {
await vantra.leads.create({ phone: "+15551230000" });
} catch (err) {
if (err instanceof VantraRateLimitError) {
console.warn(`Retry in ${err.retryAfterSeconds ?? "?"}s`);
}
}Embeddable chat widget
Drop Vantra's real agent onto any website with one line. The widget runs the clinic's actual text agent — the same orchestrator, tools and safety gates as WhatsApp and Instagram — for visitors of the clinic's own site. An admin opts the clinic in (widget_enabled); the snippet injects a floating chat button ("Powered by Vantra"). It is rate-limited per visitor IP and per clinic, and carries no API key.
<script
src="https://www.vantra.xyz/api/widget/embed.js"
data-clinic="CLINIC_ID"
async
></script>Versioning & support
The public API is versioned: /api/public/v1/* is additive-only, so new optional fields won't break you. Any breaking change ships under a new version path (/v2). The embeddable widget is a separate, self-serve integration and is intentionally not part of the SDK.
Need an API key, higher limits, or a walkthrough? Write to info@vantra.xyz or talk to us.
The public API returns the clinic's own data, including patient-identifying fields, by design — the integrator is the clinic's system of record. Handle it as PHI under your signed agreement.