Get started · VISH
VISH quickstart
Make your first authenticated VISH API call in under ten minutes — no SDK required.
VISH runs on the same EnvisionCloud platform as PatientNow Essentials, exposed as a slimmed-down API for VISH customers. It shares PNE's authentication, paging, IDs, and error handling — but offers a focused subset of resources (appointments, companies, employees, services, orders and formulas). If you're on the full PNE product, use the PNE quickstart → instead.
Before you start
You need three things:
- A VISH account with API access enabled.
- Your gateway
apikeyand a username and password authorized to call the API — both are sent on every request (see Authentication). - The API base URL:
https://api.envisiongo.com/api/v1(shared by both APIs).
Anyone with your username and password has the same access your client does. Keep them out of source control, browser code shipped to end users, and logs. Prefer a dedicated API user over a person's login.
1 · Build your auth token
Every request needs two things: your gateway apikey
(on the query string) and an Authorization header containing the Base64
encoding of username:password. Build the token once:
# cURL builds and sends the Basic header for you with -u:
# -u "USERNAME:PASSWORD"
# ...or build it explicitly:
TOKEN=$(printf 'USERNAME:PASSWORD' | base64)
echo "Authorization: Basic $TOKEN"// Browser: btoa(); Node 16+: Buffer
const token = typeof btoa === "function"
? btoa("USERNAME:PASSWORD")
: Buffer.from("USERNAME:PASSWORD").toString("base64");
const authHeader = { Authorization: `Basic ${token}` };import base64
token = base64.b64encode(b"USERNAME:PASSWORD").decode()
headers = {"Authorization": f"Basic {token}"}
# Or let requests build it for you:
# from requests.auth import HTTPBasicAuth
# auth = HTTPBasicAuth("USERNAME", "PASSWORD")using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
var http = new HttpClient { BaseAddress = new Uri("https://api.envisiongo.com/api/v1/") };
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes("USERNAME:PASSWORD"));
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token);2 · Confirm connectivity
VISH doesn't expose a dedicated status endpoint, so the cleanest first call is
GET /api/v1/companies — it lists your business locations, needs valid
auth, and takes no required input. Send your apikey and Basic
credentials; a 200 OK proves your key, token and base URL are correct.
curl "https://api.envisiongo.com/api/v1/companies?apikey=YOUR_API_KEY" \
-u "USERNAME:PASSWORD"// Bake the apikey into the base URL so every call carries it:
const base = "https://api.envisiongo.com/api/v1";
const key = "YOUR_API_KEY";
const res = await fetch(`${base}/companies?apikey=${key}`, { headers: authHeader });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
console.log(await res.json());import requests
base = "https://api.envisiongo.com/api/v1"
# A session with the apikey as a default param keeps every call clean:
s = requests.Session()
s.params = {"apikey": "YOUR_API_KEY"}
s.headers.update(headers)
res = s.get(f"{base}/companies")
res.raise_for_status()
print(res.json())var res = await http.GetAsync("companies?apikey=YOUR_API_KEY");
res.EnsureSuccessStatusCode();
Console.WriteLine(await res.Content.ReadAsStringAsync());A 200 OK with a JSON body means you're in. A 401
Unauthorized means the apikey, token or base URL is wrong — see
401 pitfalls. The python
session above sends the apikey on every call automatically; the
curl and js samples below add it to each request's query
string.
3 · Read real data
List today's appointments. Results are paginated with
Page and Rows, and you can scope to one location with the
optional CompanyId filter. Here we ask for the first 5:
curl "https://api.envisiongo.com/api/v1/appointments?apikey=YOUR_API_KEY&Page=1&Rows=5" \
-u "USERNAME:PASSWORD"const params = new URLSearchParams({ apikey: key, Page: "1", Rows: "5" });
const res = await fetch(`${base}/appointments?${params}`, { headers: authHeader });
const appointments = await res.json();
console.log(appointments);# s (from step 2) already sends apikey on every call:
res = s.get(
f"{base}/appointments",
params={"Page": 1, "Rows": 5},
)
print(res.json())Record IDs returned by the API are encrypted, URL-safe strings — not raw database integers. Pass them back exactly as received; don't try to parse or increment them. More in Guides → Resource IDs.
4 · Create a record
Write operations POST a JSON body. This creates a treatment
formula — one of VISH's writable resources. On success the
response body is the new record's ID as a JSON-encoded string —
e.g. {"id": "QXVrT3RT…"} — which you then use to read or update it.
curl -X POST "https://api.envisiongo.com/api/v1/formulas?apikey=YOUR_API_KEY" \
-u "USERNAME:PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"Description": "Filler touch-up",
"FormulaSpecs": "0.5ml, left cheek",
"ServiceDate": "2026-06-21T00:00:00",
"CustomerId": "OPAQUE_CUSTOMER_ID",
"EmployeeId": "OPAQUE_EMPLOYEE_ID",
"ServiceId": "OPAQUE_SERVICE_ID"
}'const res = await fetch(`${base}/formulas?apikey=${key}`, {
method: "POST",
headers: { ...authHeader, "Content-Type": "application/json" },
body: JSON.stringify({
Description: "Filler touch-up",
FormulaSpecs: "0.5ml, left cheek",
ServiceDate: "2026-06-21T00:00:00",
CustomerId: "OPAQUE_CUSTOMER_ID",
EmployeeId: "OPAQUE_EMPLOYEE_ID",
ServiceId: "OPAQUE_SERVICE_ID",
}),
});
console.log(res.status, await res.json());res = s.post( # s carries apikey + auth headers from step 2
f"{base}/formulas",
json={
"Description": "Filler touch-up",
"FormulaSpecs": "0.5ml, left cheek",
"ServiceDate": "2026-06-21T00:00:00",
"CustomerId": "OPAQUE_CUSTOMER_ID",
"EmployeeId": "OPAQUE_EMPLOYEE_ID",
"ServiceId": "OPAQUE_SERVICE_ID",
},
)
print(res.status_code, res.json())Creating and updating records changes real data immediately — there is no separate sandbox environment. Test with disposable records you can clean up, and double-check the account behind your credentials before running writes.