Developers

Get started · VISH

VISH quickstart

Make your first authenticated VISH API call in under ten minutes — no SDK required.

ℹ️ What is the VISH API?

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:

⚠️ Treat credentials as secrets

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())
📎 IDs are opaque

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())
⚠️ This writes to live data

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.

What's next