Access4 / Sasboss Integration - User Guide
Access4 / Sasboss Integration
The Access4 integration automatically pulls your Access4 (Sasboss) enterprise, service, DID, and billing data into PracBill so you can bill your customers without manual data entry.
What Gets Synced
Data | Source | Destination |
|---|---|---|
Enterprise → Customer | Sasboss Enterprise | PracBill Customer |
DID numbers (individual or blocks) | Sasboss DID numbers | PracBill Engineering (DID) records |
Service accounts (endpoints, huntgroups, etc.) | Sasboss Service Accounts | PracBill Engineering (license) records |
Wholesale cost | Sasboss billing charges | Engineering |
Retail price | PricingService (see Pricing below) | Engineering |
Setup fees | Sasboss billing charges | Engineering iItems (unbilled line items) |
The sync runs automatically every night at 00:30. It is idempotent — re-running it does not create duplicates.
How Services Are Created
Each enterprise produces two types of engineering records:
DID Records (number rentals)
One engineering record per DID number (or per DID block for 10/100 number ranges). The block size comes directly from Sasboss's didNumberGroupSize field — PracBill never guesses ranges.
Individual DIDs (groupSize=1) → one record per number
10-blocks (groupSize=10) → one record per block
100-blocks (groupSize=100) → one record per block
DID records carry the DID rental charge from the billing API (e.g. $0.35/month per number).
Service Account Records (user licenses)
One engineering record per provisioned service account — endpoints, huntgroups, ring groups, IVRs, call centres, fax lines, etc. These are created regardless of whether the service account has a DID attached.
Service account records carry the user license charge from the billing API (e.g. $35/month for an Executive User). When a service account has multiple charges (e.g. Executive User + Collaboration User add-on), the cost is the sum of all charges on that serviceId.
This means a DID with an attached endpoint produces two engineering records: one for the number rental and one for the endpoint license. This matches how Access4 bills — DID charges and user license charges are separate line items.
Pricing Model
PracBill uses a three-tier pricing hierarchy to determine the retail price (monthlyfee) for each engineering record:
1. Price Book Override (highest priority)
If the customer has a price_book_id set, PracBill looks up the price book for a service-type-specific override. This lets you set custom retail prices per customer.
2. Service Type List Price
If the service type (eng_typeservices) has a list_price set, that value is used as the retail price. For example, you might set list_price = $1.00 on the "DID Number" service type to charge $1/month per DID regardless of the wholesale cost.
3. Wholesale Pass-Through (default)
If neither a price book override nor a service type list price exists, the retail price equals the wholesale cost from Access4. This ensures you never undercharge — at worst you break even.
How to Set Pricing
For most services: Leave list_price empty on the service type. The sync will charge retail = wholesale automatically. If Access4 changes their wholesale price, your retail updates on the next sync.
To charge more than wholesale: Set list_price on the service type (e.g. DID Numbers at $1.00 when wholesale is $0.35). This is a one-time setup.
For customer-specific pricing: Create a price book, set per-service-type prices, and assign the price book to the customer.
Important: The sync never auto-sets list_price when creating new service types. New products always start with wholesale pass-through until you explicitly set a list price.
Service Types and Products
Each Access4 billing product (identified by productId) maps to a PracBill service type via the vendor_product_id field. The sync auto-creates service types when it encounters new products.
Common products and their typical wholesale ranges:
Product | Description | Wholesale Range |
|---|---|---|
6408 | Executive User | $15 – $35 |
6414 | Collaboration User | $25 – $40 |
6405 | Office User | $10 – $25 |
6492 | DID Number (1) | $0.35 – $1.00 |
6495 | DID Number Block (10) | $3.51 – $10 |
6498 | DID Number Block (100) | $35 – $39 |
6486 | Business Trunk | $8.97 – $50 |
Customer Mapping
Default: One PracBill Customer per Enterprise (Rollup Mode)
By default, each Sasboss enterprise becomes a single PracBill customer. All groups, sites, and services under that enterprise roll up to that single customer. This is what you want for the vast majority of customers — one bill, one customer record.
Opt-In: Split by Group (One PracBill Customer per Site)
Some customers have multiple sites/branches/locations in Access4 (configured as "groups" in Sasboss) and want each site billed as its own PracBill customer. For these cases, you enable the split by group option on the parent customer.
When enabled:
The parent (enterprise) customer still exists
Each Sasboss group creates its own PracBill customer, named
Enterprise Name - Group NameDID blocks and service accounts are attached to the group customer they belong to
Any DIDs/services that aren't tied to a specific group stay on the parent customer
How to Enable Split-by-Group
Option 1 — By customer name (easiest)
php artisan access4:enable-split-by-group {deptId} "Customer Name 1" "Customer Name 2"Example:
php artisan access4:enable-split-by-group 165 "Melbourne Racing Club" "Estia" "Iron Mountain" "Calvary Health"The command will:
Authenticate with Sasboss and fetch the enterprise list
For each name, find the matching Sasboss enterprise (case-insensitive substring match)
Find or create the Access4 enterprise mapping
Insert a config mapping with
external_source = 'access4_config'andexternal_id = 'split_by_group'
Option 2 — By customer ID
php artisan access4:enable-split-by-group 165 --cid=7088777Disabling Split-by-Group
php artisan access4:enable-split-by-group 165 "Melbourne Racing Club" --disableImportant: When you disable split-by-group, the next sync rolls everything back under the parent customer. Group customer services get terminated and re-created on the parent.
After Changing Configuration
After enabling/disabling split-by-group or changing service type pricing, run the sync to apply:
# Single enterprise (fast)
php artisan access4:sync-services 165 --enterprise-id=5656
# Full sync
php artisan access4:sync-services 165Cleanup Command
Roll back group customers that were created incorrectly:
# Preview
php artisan access4:cleanup-group-customers 165 --dry-run
# Apply
php artisan access4:cleanup-group-customers 165Safety features:
Skips customers with invoices or quotes
Re-homes engineering records to the parent enterprise customer
Soft-deletes the group customer and mapping
Billing Gap Report
Compare what Access4 bills you vs what PracBill has captured:
php artisan access4:billing-gap-report 165 --top=20
php artisan access4:billing-gap-report 165 --csv=gap_report.csvTypical Setup Checklist
Ensure the Access4 integration is configured and credentials are valid
Set
list_priceon service types where you want to charge more than wholesale (e.g. DID Numbers at $1.00)Run
access4:sync-services {deptId}to import all servicesReview the billing gap report to verify totals match
For multi-site customers, run
access4:enable-split-by-groupas neededDone — nightly sync keeps everything current
Troubleshooting
Symptom | Cause | Fix |
|---|---|---|
Retail = wholesale for all services | No | This is correct default behaviour. Set |
Customer has too many engineering records | Groups are being split per-site | Check if |
Missing services after sync | New product type not yet matched | Check if a new service type was auto-created; set pricing if needed |
Duplicate customers | Access4 name differs from import name | Use the cleanup command or manually merge |
Auth fails (HTTP 401) | Credentials expired or APP_KEY changed | Re-save credentials in the Integrations UI |
Reference
Enterprise mapping:
external_source = 'access4',external_id = 'enterprise:{id}'Group mapping:
external_source = 'access4',external_id = 'group:{id}'Split-by-group flag:
external_source = 'access4_config',external_id = 'split_by_group'Nightly schedule: 00:30 daily via
access4:sync-allPricing resolution: Price book → Service type list_price → Wholesale pass-through