HTTP API
The web app, the CLI and the MCP server all use this API. Paths are relative to your server, for example https://convert.example.com/api/leads.
Authentication
Section titled “Authentication”Send the workspace key as a bearer token:
curl -H "Authorization: Bearer $VISICONVERT_API_KEY" https://convert.example.com/api/leadsOn a self-hosted install the key is VISICONVERT_API_KEY. Hosted workspaces use short-lived session tokens that start with vc_session_.
Errors
Section titled “Errors”Errors return a JSON body with a message:
{ "error": "This record changed, or its identifier is already in use. Refresh and retry." }| Status | Meaning |
|---|---|
400 |
The request failed validation; the message says why |
401 |
Missing or wrong key |
403 |
The key is valid but cannot do this, such as a non-owner connecting Twilio |
404 |
No such lead, number or booking in this workspace |
409 |
A version or revision check failed; re-read and try again |
429 |
Too many requests |
| Method | Path | Description |
|---|---|---|
GET |
/api/leads |
All leads in the workspace |
POST |
/api/leads |
Add a lead |
PATCH |
/api/leads/{id} |
Set qualification and notes |
GET |
/api/leads/{id}/outcomes |
Bookings on a lead |
PUT |
/api/leads/{id}/outcomes |
Record or revise a booking |
Add a lead. external_id is optional; repeating it with the same details returns the existing lead.
POST /api/leads{ "external_id": "form-8812", "name": "Dana Ruiz", "contact": "+15125550199", "source": "Website", "campaign": "Contact form", "notes": ""}Qualify a lead. version is the lead’s current version; the update is rejected with 409 if it has changed. qualification is unreviewed, qualified, unqualified or spam.
PATCH /api/leads/{id}{ "version": 3, "qualification": "qualified", "notes": "Two units, wants a quote" }Record a booking. external_id is your job or invoice reference. amount_minor is in cents. revision must be 1 for a new reference, then one more than the last revision. Only USD is supported.
PUT /api/leads/{id}/outcomes{ "external_id": "JOB-1042", "amount_minor": 125000, "currency": "USD", "status": "booked", "revision": 1 }See Leads, qualification and bookings for why versions and revisions work this way.
Numbers and reports
Section titled “Numbers and reports”| Method | Path | Description |
|---|---|---|
GET |
/api/numbers |
Tracking numbers |
POST |
/api/numbers |
Register a tracking number |
GET |
/api/summary |
Leads, qualified leads, bookings and revenue by source |
GET |
/api/bootstrap |
Workspace details for the web app |
POST /api/numbers{ "label": "Spring HVAC", "phone_number": "+15125550142", "destination": "+15125550100", "source": "Google Ads", "campaign": "Spring HVAC"}Twilio connection
Section titled “Twilio connection”| Method | Path | Description |
|---|---|---|
GET |
/api/connections/twilio |
Connection status, revision and the webhook URLs |
PUT |
/api/connections/twilio |
Connect or update: account_sid, auth_token, revision (0 when not connected) |
DELETE |
/api/connections/twilio |
Disconnect; requires the current revision and no tracking numbers |
GET |
/api/connections/twilio/numbers |
Voice numbers in the account |
Health
Section titled “Health”GET /health needs no key and returns {"status": "ok"}.
More endpoints
Section titled “More endpoints”Inquiry grouping, website tracking and dynamic number insertion have their own endpoints. They are documented on GitHub for now: