Learn
Recipes — common workflows
The reference documents one endpoint at a time. Real features chain several together. Here are three end-to-end flows — pulled from production-style examples — that show how one call's output feeds the next.
These workflows lean on PNE resources — customers,
products, and the appointment ShowAvailable search — that
the VISH subset doesn't expose. The auth, paging,
ID and date conventions are identical on both APIs, so the shapes below
transfer; just swap in the resources your API actually has. VISH-specific
differences are flagged inline.
The setup these recipes share
Every snippet below assumes you've already built an authenticated client, exactly as
in the PNE quickstart — so we don't repeat auth in each
step. In Python that's a requests.Session that carries your gateway
apikey on every call and sets the Basic Authorization
header:
import base64, requests
base = "https://api.envisiongo.com/api/v1"
s = requests.Session()
s.params = {"apikey": "YOUR_API_KEY"} # sent on every request
s.headers["Authorization"] = "Basic " + base64.b64encode(b"USERNAME:PASSWORD").decode()# Each curl below omits these for brevity — add them to every request:
# ?apikey=YOUR_API_KEY (gateway key, on the query string)
# -u "USERNAME:PASSWORD" (cURL turns this into the Basic header)Creating appointments and orders changes real records immediately — there's no sandbox. Run writes against an account you control, with disposable records you can clean up afterward.
Build a customer 360 view
Pull a customer's profile together with their upcoming appointments and their
purchase history — the data behind a "client card" screen. The thread that ties the
calls together is the CustomerId: you look it up once,
then reuse it.
- Find the customer — GET
/customers, filtered. - Read their appointments — POST
/customers/{id}/Appointments. - Read their purchases — POST
/customers/{id}/Purchases.
1 · Look up the customer
Search by any combination of FirstName, LastName,
Email or MobilePhone. Grab the
CustomerId off the first match — it's an
opaque string, so pass it back verbatim.
match = s.get(f"{base}/customers", params={"LastName": "Client", "Rows": 1}).json()
cust_id = match[0]["CustomerId"] # e.g. "aFBoL3M3ODJoSFNhdDNSb3hDK0hNdz09"
company_id = match[0]["CompanyId"] # carry this for scoping later callscurl "https://api.envisiongo.com/api/v1/customers?apikey=YOUR_API_KEY&LastName=Client&Rows=1" \
-u "USERNAME:PASSWORD"
# → [ { "CustomerId": "aFBoL3M3...", "CompanyId": "WlBiYmF...", "FirstName": "Test", ... } ]2 · Read their appointments
POST
The customer sub-resources — Appointments, Purchases,
CancelledAppointments, GiftCertificates — are fetched with
POST, not GET, even though they only
read. Send an empty body. Optional StartDate/EndDate (plus
Page/Rows) narrow the window.
appts = s.post(f"{base}/customers/{cust_id}/Appointments",
params={"StartDate": "2026-06-01", "EndDate": "2026-06-30"}).json()
for a in appts:
print(a["StartDate"], a["Service"], "with", a["Employee"])curl -X POST "https://api.envisiongo.com/api/v1/customers/CUSTOMER_ID/Appointments?apikey=YOUR_API_KEY" \
-u "USERNAME:PASSWORD" \
--data ""
# → [ { "AppointmentId": "...", "StartDate": "2026-05-21T12:00:00",
# "Service": "test service", "Employee": "Andrew Ault", ... } ]3 · Read their purchase history
Same shape, different sub-resource. Each row carries the human-readable
Item, Employee and Customer names alongside the
IDs, so a history list needs no extra lookups.
purchases = s.post(f"{base}/customers/{cust_id}/Purchases").json()
total_spent = sum(p["Amount"] for p in purchases)
print(f"{len(purchases)} purchases, ${total_spent:,.2f} lifetime")curl -X POST "https://api.envisiongo.com/api/v1/customers/CUSTOMER_ID/Purchases?apikey=YOUR_API_KEY" \
-u "USERNAME:PASSWORD" \
--data ""
# → [ { "OrderId": "...", "OrderNumber": "2", "Item": "test service",
# "OrderDate": "2025-09-08T14:04:04", "Qty": 1, "Amount": 100.0 } ]Full field lists: Customers reference →
Book a visit from an open slot
Turn "this customer wants a service with this provider" into a booked appointment. You assemble three IDs — service, employee, company — ask the API which slots are free, then write the appointment into one of them.
- Choose a service — GET
/services(givesServiceId+ its duration). - Choose a provider — GET
/employees(givesEmployeeId). - Find open slots — GET
/appointments/ShowAvailable. - Book one — POST
/appointments.
1 · Pick the service and provider
List services and employees (both scope to a location with
CompanyId). A service's InitialMinutes /
ProcessMinutes / CompleteMinutes become the appointment's
Init / Delay / Complete in step 4.
svc = s.get(f"{base}/services", params={"CompanyId": company_id, "IsActive": True}).json()[0]
emp = s.get(f"{base}/employees", params={"CompanyId": company_id, "IsActive": True}).json()[0]
service_id, employee_id = svc["ServiceId"], emp["EmployeeId"]
duration = svc["InitialMinutes"] # e.g. 15curl "https://api.envisiongo.com/api/v1/services?apikey=YOUR_API_KEY&CompanyId=COMPANY_ID&IsActive=true" \
-u "USERNAME:PASSWORD"
curl "https://api.envisiongo.com/api/v1/employees?apikey=YOUR_API_KEY&CompanyId=COMPANY_ID&IsActive=true" \
-u "USERNAME:PASSWORD"2 · Find an open slot
ShowAvailable needs all four query params —
CompanyId, EmployeeId, ServiceId and a
StartDate (the day to search). It returns the bookable
AvailableSlot times for that provider/service on that day.
slots = s.get(f"{base}/appointments/ShowAvailable", params={
"CompanyId": company_id, "EmployeeId": employee_id,
"ServiceId": service_id, "StartDate": "2025-09-11T12:00:00",
}).json()
first_slot = slots[0]["AvailableSlot"] # e.g. "2025-09-11 13:15:00"curl "https://api.envisiongo.com/api/v1/appointments/ShowAvailable?apikey=YOUR_API_KEY&CompanyId=COMPANY_ID&EmployeeId=EMPLOYEE_ID&ServiceId=SERVICE_ID&StartDate=2025-09-11T12:00:00" \
-u "USERNAME:PASSWORD"
# → [ { "AvailableSlot": "2025-09-11 13:15:00", "EmployeeName": "Lev Kurts", "Initial": 15, ... }, ... ]3 · Book the appointment
Now POST /appointments with the IDs you gathered and the slot you chose.
A 200 OK returns the new appointment's ID, e.g.
{"id": "U3V2Z1BZ…"}.
The create body is an appointment — the
Appointment model: CustomerId,
CompanyId, EmployeeId, ServiceId,
StartDate, the Init/Delay/Complete
minutes, Notes and BookedOnline. (Some older examples paste
the customer field list here by mistake — ignore that; use the fields below.)
booked = s.post(f"{base}/appointments", json={
"CompanyId": company_id,
"CustomerId": cust_id,
"EmployeeId": employee_id,
"ServiceId": service_id,
"StartDate": "2025-09-11T13:15:00", # a slot from step 2
"Init": duration, "Delay": 0, "Complete": 0,
"Notes": "Booked via API",
"BookedOnline": True,
}).json()
print("new appointment:", booked) # {"id": "U3V2Z1BZ..."}curl -X POST "https://api.envisiongo.com/api/v1/appointments?apikey=YOUR_API_KEY" \
-u "USERNAME:PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"CompanyId": "COMPANY_ID",
"CustomerId": "CUSTOMER_ID",
"EmployeeId": "EMPLOYEE_ID",
"ServiceId": "SERVICE_ID",
"StartDate": "2025-09-11T13:15:00",
"Init": 15, "Delay": 0, "Complete": 0,
"Notes": "Booked via API",
"BookedOnline": true
}'On VISH, appointments is read-only and there's no
ShowAvailable search, so this booking flow is PNE-only. VISH clients can
still list services, employees and appointments — see the
VISH reference.
Ring up a retail order
Record a sale: find what's being sold, then post an order that bundles its line items and payments in one call. An order is a composite document, so you build the whole thing client-side and submit it together.
- Find the item — GET
/products(or a service from recipe 2). - Create the order — POST
/orderswith line items + payments. - Read it back — GET
/orders.
1 · Find the product
List products for the location. Per-location pricing and stock live in
the nested ProductDetails array (matched by CompanyId), so
read the price from the entry for the company you're selling at.
prod = s.get(f"{base}/products", params={"CompanyId": company_id, "IsActive": True}).json()[0]
item_id = prod["ProductId"]
price = next(d["Price"] for d in prod["ProductDetails"] if d["CompanyId"] == company_id)curl "https://api.envisiongo.com/api/v1/products?apikey=YOUR_API_KEY&CompanyId=COMPANY_ID&IsActive=true" \
-u "USERNAME:PASSWORD"
# → [ { "ProductId": "...", "Description": "Test Product",
# "ProductDetails": [ { "CompanyId": "...", "Price": 20.0, "QtyOnHand": 0 } ] } ]2 · Create the order
Each line item declares its kind with InvType, and each payment its
method with a numeric PaymentType. The two enums:
InvType (line item) | PaymentType (payment) |
|---|---|
R Retail · S Service · P Package · O Other · G Gift | 1 Cash · 2 Check · 3 Gift · 4 Visa · 5 MC · 6 AMEX · 7 Discover · 18 Debit |
The order's SubTotal/Total should equal the sum of its line
items, and the Payments should cover the Total. The example
sells one retail item at $20 and pays $20 cash. Most cost/tax fields can be
0.0 when you're just recording a straightforward sale.
order = s.post(f"{base}/orders", json={
"CompanyId": company_id,
"CustomerId": cust_id,
"EmployeeId": employee_id,
"OrderDate": "2025-09-08T14:04:04",
"SubTotal": price, "Total": price,
"LineItems": [{
"CompanyId": company_id, "CustomerId": cust_id, "EmployeeId": employee_id,
"ItemId": item_id, "InvType": "R", # R = Retail
"Qty": 1, "RetailPrice": price, "ExtendedPrice": price,
}],
"Payments": [{
"CompanyId": company_id, "PaymentType": 1, # 1 = Cash
"Amount": price, "PaymentDate": "2025-09-08T14:04:00",
}],
}).json()
print("new order:", order) # {"id": "aEd0K3Jz..."}curl -X POST "https://api.envisiongo.com/api/v1/orders?apikey=YOUR_API_KEY" \
-u "USERNAME:PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"CompanyId": "COMPANY_ID",
"CustomerId": "CUSTOMER_ID",
"EmployeeId": "EMPLOYEE_ID",
"OrderDate": "2025-09-08T14:04:04",
"SubTotal": 20.0, "Total": 20.0,
"LineItems": [ { "CompanyId": "COMPANY_ID", "ItemId": "PRODUCT_ID",
"InvType": "R", "Qty": 1, "RetailPrice": 20.0, "ExtendedPrice": 20.0 } ],
"Payments": [ { "CompanyId": "COMPANY_ID", "PaymentType": 1,
"Amount": 20.0, "PaymentDate": "2025-09-08T14:04:00" } ]
}'3 · Read the order back
Confirm it landed with GET /orders (filter by CustomerId,
CompanyId or a date range), or fetch the one you just created with
GET /orders/{id}. The response echoes the full document — line items,
payments, and any Coupons or Tips.
orders = s.get(f"{base}/orders", params={"CustomerId": cust_id}).json()
print(orders[0]["OrderNumber"], orders[0]["Total"])curl "https://api.envisiongo.com/api/v1/orders?apikey=YOUR_API_KEY&CustomerId=CUSTOMER_ID" \
-u "USERNAME:PASSWORD"products is PNE-only, so this retail flow is written for PNE. VISH
exposes orders and services — check the
VISH reference for exactly what its order surface
supports before adapting this.
All three lean on the same conventions: opaque IDs you pass back verbatim, paging on the list calls, and status-code-first error handling. Learn those once in Guides & concepts and every recipe reads the same way.