Services API
52 PracBill API endpoints for services. Base URL https://billing.pracbill.com.au/api.
Legacy route form with the token as the last segment. List the unbilled CDR calls (cdr_billing.invoice = 0) for a service, found by `enid` and/or `service_num`. Note the envelope is {result, message, data} (not `success`); only the `invalid key` failure uses {success:false, description}.
POST /service/unbilled_calls/{api_key}
Request body
| Field | Type | Description |
|---|---|---|
enid | integer | Engineering (service) ID |
service_num | string | Service number |
Responses
200— Result envelope (or {success:false,description:'invalid key'})
List a customer's non-deleted service sites (the engineering_sites records shown in the UI as "Service Sites"), ordered by name. Constrained to the token's department via the customer. An unknown/foreign customer returns {success:false, description:'invalid customer'}.
GET /{api_key}/customer/{cid}/service-sites
Responses
200— Service sites for the customer
Paginated service list
GET /{api_key}/eengineering/get
Legacy alias (typo'd/deprecated URI) of `/{api_key}/services/get`. Lists non-deleted services, newest start date first, 20 per page (department-scoped). Row keys are id, cid, service_num, start_date, servicetype, monthlyfee, date_ended, billing_cycle, contractterm, billing_name, call_rates_id, bundle_id, cost, quantity, parent_id, nbn_avc, service_status. Response is {results, page_number, total_pages} with no success key.
Responses
200— Page of services. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Paginated service list
GET /{api_key}/eengineering/get/page
Legacy alias (typo'd/deprecated URI) of `/{api_key}/services/get/page`. Lists non-deleted services, newest start date first, 20 per page (department-scoped). Row keys are id, cid, service_num, start_date, servicetype, monthlyfee, date_ended, billing_cycle, contractterm, billing_name, call_rates_id, bundle_id, cost, quantity, parent_id, nbn_avc, service_status. Response is {results, page_number, total_pages} with no success key.
Responses
200— Page of services. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Paginated service list
GET /{api_key}/eengineering/get/page/{pageNumber}
Legacy alias (typo'd/deprecated URI) of `/{api_key}/services/get/page/{pageNumber}`. Lists non-deleted services, newest start date first, 20 per page (department-scoped). Row keys are id, cid, service_num, start_date, servicetype, monthlyfee, date_ended, billing_cycle, contractterm, billing_name, call_rates_id, bundle_id, cost, quantity, parent_id, nbn_avc, service_status. Response is {results, page_number, total_pages} with no success key.
Responses
200— Page of services. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Check whether service numbers are active
GET /{api_key}/engineering/activeCheck
Declared as GET but reads a JSON array of service numbers from the request body (plain JSON, not the data= form). Scoped to the token's department. The handler reads a JSON request body even though this is a GET (shape: `ServiceCoreActiveCheckRequest`); OpenAPI 3.0 cannot express a GET body, so it is described here.
Responses
200— Request received successfully. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Create a service
POST /{api_key}/engineering/add
Create a new service record. service_status, when sent, is validated (see ServiceCreateItem); when omitted the database default 'active' applies.
Request body
| Field | Type | Description |
|---|---|---|
id | integer | Maps to engineering.enid. Normally omit. On update this would overwrite the primary key - do not send. |
cid required | integer | Customer ID. On add, required in practice (used for the price book lookup when monthlyfee is omitted). |
service_num | string | Service number/identifier |
start_date | string | Service start date (written to port_dateacc). Accepted alias of port_dateacc; NOT run through date conversion, so send YYYY-MM-DD. Ignored if port_dateacc is also sent. |
port_dateacc | string | Service start date (database column name, accepted directly). Converted with AppDate::toDBDate() and takes precedence over start_date. |
servicetype required | integer | Service type ID (esid). On add, required in practice (used for the price lookup when monthlyfee is omitted). |
monthlyfee | number | Monthly fee. On add, when omitted it is taken from the price book, else the service type's list_price. On update, omitting leaves it unchanged; sending the JSON value false triggers the same price book/list price recalculation. |
date_ended | string | Service end date, converted with AppDate::toDBDate() |
billing_cycle | string | Billing cycle |
contractterm | integer | Contract term in months |
billing_name | string | Billing name |
call_rates_id | integer | Call rates group ID (stored in ctgid) |
bundle_id | integer | Service bundle ID (stored in engineering_bundle_id) |
cost | number | Cost price |
quantity | number | Quantity (DB default 1) |
nbn_avc | string | NBN AVC identifier |
service_information_data | object | Additional service information. Re-encoded to a JSON string for storage. |
service_status | string (active | pending | suspended | pending_disconnection | disconnected | churned) | Service lifecycle status. Validated case-sensitively and strictly (type and value) against active, pending, suspended, pending_disconnection, disconnected, churned. Any other value is rejected before anything is written with {"success": false, "description": "invalid service_status"} (HTTP 200). When omitted on add the database default 'active' applies. A 'pending' service is excluded from billing. (Read responses return this as a plain string, not an enum.) |
site_id | integer | Service site to link to (engineering.engineering_site_id). Must be a live site of the service's customer in the token's department, else {"success": false, "description": "invalid site_id"}. Values <= 0 or omitted leave it unchanged. |
full_address | string | The service's primary address as a full-address string, geocoded and stored via saveAddress(). Omit/empty to leave unchanged. |
parent_enid | integer | Parent service ID (note: add accepts parent_enid, not parent_id) |
Responses
200— Service created. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate ETF for several services
POST /{api_key}/engineering/calculateMultipleETF
Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Response is a bare array of calculateETF() results each with an enid.
Request body
Array of:
Responses
200— ETFs calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate ETF for several services
POST /{api_key}/engineering/calculateMultipleETF/{date}
Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Response is a bare array of calculateETF() results each with an enid.
Request body
Array of:
Responses
200— ETFs calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute ETF for several services
POST /{api_key}/engineering/dMultipleoETF
Legacy alias (typo'd/deprecated URI) of `/{api_key}/engineering/doMultipleETF/{date}`. Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Runs doETF() for each. Response is a bare array of {success, enid}. Code bug: the handler signature is post($token, $enid, $date) so on the dated URIs the :date segment binds to $enid and the date is effectively ignored (today is used).
Request body
Array of:
Responses
200— ETFs processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Delete a service
POST /{api_key}/engineering/delete/{enid}
Soft-deletes the service (EP_Database Delete). Returns success true even if the enid does not exist.
Responses
200— Service deleted. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute ETF for several services
POST /{api_key}/engineering/doMultipleETF/{date}
Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Runs doETF() for each. Response is a bare array of {success, enid}. Code bug: the handler signature is post($token, $enid, $date) so on the dated URIs the :date segment binds to $enid and the date is effectively ignored (today is used).
Request body
Array of:
Responses
200— ETFs processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Get a service
GET /{api_key}/engineering/get/{enid}
Get a specific service record by ID. Does not return an error for an unknown enid: success is true and every field is null.
Responses
200— Request received successfully. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Add a one-time charge item to a service
POST /{api_key}/engineering/item/add
Add a one-time charge item to a service (for additional fees, equipment, installation charges, etc.)
Request body
| Field | Type | Description |
|---|---|---|
pid required | integer | Product ID (required) - references inventory table |
enid | integer | Service ID to associate the item with |
charge_date | string | Date the charge should be applied (YYYY-MM-DD, converted with AppDate::toDBDate()) |
inc_tax_amount | number | Amount including tax (defaults to the product's) |
taxrate | number | Tax rate percentage (read but overwritten with the rate that applies) |
description | string | Charge description (defaults to the product's) |
Responses
200— Service item created. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Update a one-time charge item
POST /{api_key}/engineering/item/update/{id}
Update a one-time charge item on a service. Errors: 'no data provided', 'service item id is required', 'no service item found'.
Request body
| Field | Type | Description |
|---|---|---|
pid | integer | Product ID - if supplied, tax and ex-tax amount are recalculated |
charge_date | string | Date the charge should be applied (YYYY-MM-DD) |
inc_tax_amount | number | Amount including tax |
taxrate | number | Tax rate percentage |
description | string | Charge description |
Responses
200— Service item updated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Search services
POST /{api_key}/engineering/search
Search for services with flexible criteria. The request body is a JSON **array** of criterion objects. Each criterion has a `field`, a `value`, and an optional `operator` (defaults to `like`). Multiple criteria are combined with AND. Results are automatically scoped to the API token's department. Request body is plain JSON. If no criterion is usable the response is ServiceCoreSearchErrorResponse.
Request body
Array of:
| Field | Type | Description |
|---|---|---|
field required | string (id | cid | service_num | servicetype | start_date | monthlyfee | date_ended | billing_name) | The field to filter on. API names (id, start_date, call_rates_id, parent_id, locid, site_id, username, service_status ...) are translated to the database column; the raw column names enid, port_dateacc, parent_enid, nbn_loc_id, engineering.cid, engineering.ctgid, engineering.ext_field2 and engineering.engineering_site_id are also accepted. billing_cycle, contractterm, cost and bundle_id are NOT searchable (silently ignored). `active_services` is a special flag that takes no value/operator and limits results to services that have not ended (date_ended null, 0000-00-00, 1970-01-01 or >= today). Unrecognised fields are silently ignored. |
value | object | The value to compare against. Required for every field except `active_services`. May be a string or number depending on the field. |
operator | string (= | like | < | > | <= | >= | !=) | Comparison operator. Defaults to `like` (substring match — the value is wrapped in % wildcards) when omitted. Ignored for `active_services`. |
Responses
200— Search completed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Update a service
POST /{api_key}/engineering/update/{enid}
Update an existing service record. Only supplied keys are written. service_status, when sent, is validated (see ServiceCoreUpdateItem). Changing servicetype without sending monthlyfee recalculates monthlyfee from the customer's price book for the new type, falling back to its list_price; an explicit monthlyfee is never replaced. Errors: 'no record found to update', 'no data provided', 'invalid service_status', 'invalid site_id'.
Request body
| Field | Type | Description |
|---|---|---|
id | integer | Maps to engineering.enid. Normally omit. On update this would overwrite the primary key - do not send. |
cid | integer | Customer ID. When sent alongside a service type change that recalculates monthlyfee, this customer's price book is used; otherwise the service's stored customer is used. |
service_num | string | Service number/identifier |
start_date | string | Service start date (written to port_dateacc). Accepted alias of port_dateacc; NOT run through date conversion, so send YYYY-MM-DD. Ignored if port_dateacc is also sent. |
port_dateacc | string | Service start date (database column name, accepted directly). Converted with AppDate::toDBDate() and takes precedence over start_date. |
servicetype | integer | Service type ID (esid). Changing it without sending monthlyfee recalculates monthlyfee (see monthlyfee). |
monthlyfee | number | Optional monthly fee. When supplied (including 0) it is written as-is. When omitted and servicetype is sent with a value different from the stored service type, the fee is recalculated for the target service type from the customer's applicable price book (final_total), falling back to the service type's list_price if no price-book entry applies. When omitted and the service type is unchanged, the stored fee is left unchanged. Sending the JSON value false forces the same recalculation for the target (or stored) service type. |
date_ended | string | Service end date, converted with AppDate::toDBDate() |
billing_cycle | string | Billing cycle |
contractterm | integer | Contract term in months |
billing_name | string | Billing name |
call_rates_id | integer | Call rates group ID (stored in ctgid) |
bundle_id | integer | Service bundle ID (stored in engineering_bundle_id) |
cost | number | Cost price |
quantity | number | Quantity (DB default 1) |
nbn_avc | string | NBN AVC identifier |
service_information_data | object | Additional service information. Re-encoded to a JSON string for storage. |
service_status | string (active | pending | suspended | pending_disconnection | disconnected | churned) | Service lifecycle status. Validated case-sensitively and strictly (type and value) against active, pending, suspended, pending_disconnection, disconnected, churned. Any other value is rejected before anything is written with {"success": false, "description": "invalid service_status"} (HTTP 200). When omitted on update the stored status is unchanged. A 'pending' service is excluded from billing. (Read responses return this as a plain string, not an enum.) |
site_id | integer | Service site to link to (engineering.engineering_site_id). Must be a live site of the service's customer in the token's department, else {"success": false, "description": "invalid site_id"}. Values <= 0 or omitted leave it unchanged. |
full_address | string | The service's primary address as a full-address string, geocoded and stored via saveAddress(). Omit/empty to leave unchanged. |
locid | string | NBN Location ID, stored in nbn_loc_id (same name returned by get). Non-empty only; omit/empty leaves it unchanged. |
primaryAddress | string | Preferred name for the primary address (as returned by get); takes precedence over full_address. Omit/empty leaves unchanged. |
Responses
200— Service updated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate Early Termination Fee
GET /{api_key}/engineering/{enid}/calculateETF
Calculate Early Termination Fee (ETF) for a service as at :date (default today). Response is the bare calculateETF() result (no success key).
Responses
200— ETF calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate Early Termination Fee
GET /{api_key}/engineering/{enid}/calculateETF/{date}
Calculate Early Termination Fee (ETF) for a service as at :date (default today). Response is the bare calculateETF() result (no success key).
Responses
200— ETF calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute Early Termination Fee
POST /{api_key}/engineering/{enid}/doETF
Execute ETF: if the ETF amount is > 0 an engineering_iitems charge is created (description from the department's etf_pid product, else 'Early Termination Fee'), and the service's date_ended is set to the ETF date. Always returns {success: true}.
Responses
200— ETF processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute Early Termination Fee
POST /{api_key}/engineering/{enid}/doETF/{date}
Execute ETF: if the ETF amount is > 0 an engineering_iitems charge is created (description from the department's etf_pid product, else 'Early Termination Fee'), and the service's date_ended is set to the ETF date. Always returns {success: true}.
Responses
200— ETF processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Create a service site. cid must be a customer in the token's department (`invalid cid`); name must not be blank (`name is required`); an empty body gives `no data provided`.
POST /{api_key}/service-sites/add
Request body
| Field | Type | Description |
|---|---|---|
cid required | integer | Customer ID (must be a customer in the token's department) |
name required | string | Site name (trimmed; must not be blank) |
sid | string | Site reference (DB field sitesid); defaults to empty |
domain_name | string | Site domain (DB field domainname); defaults to empty |
Responses
200— Service site created ({success:true,id}) or an error ({success:false,description})
Soft-delete a service site (deleted = 1; never a hard delete). Fails (`site not found`) for a nonexistent/deleted/cross-department site. Success returns only {success:true}.
POST /{api_key}/service-sites/delete/{id}
Responses
200— Service site deleted
Fetch a single service site. Fails ({success:false, description:'site not found'}) when the site does not exist, is deleted, or belongs to a customer outside the token's department.
GET /{api_key}/service-sites/get/{id}
Responses
200— The service site
Update a service site (name/sid/domain_name, and optionally cid to another customer in the same department). Fails for a nonexistent/deleted/cross-department site (`site not found`), a blank name (`name cannot be blank`) or an invalid cid (`invalid cid`). Success returns description `service site updated`.
POST /{api_key}/service-sites/update/{id}
Request body
| Field | Type | Description |
|---|---|---|
cid | integer | Reassign to another customer in the same department |
name | string | Site name (trimmed; blank is rejected with `name cannot be blank`) |
sid | string | Site reference (DB field sitesid) |
domain_name | string | Site domain (DB field domainname) |
Responses
200— Service site updated
List the unbilled CDR calls (cdr_billing.invoice = 0) for a service, found by `enid` and/or `service_num`. Note the envelope is {result, message, data} (not `success`); only the `invalid key` failure uses {success:false, description}.
POST /{api_key}/service/unbilled_calls
Request body
| Field | Type | Description |
|---|---|---|
enid | integer | Engineering (service) ID |
service_num | string | Service number |
Responses
200— Result envelope (or {success:false,description:'invalid key'})
Check whether service numbers are active
GET /{api_key}/services/activeCheck
Declared as GET but reads a JSON array of service numbers from the request body (plain JSON, not the data= form). Scoped to the token's department. The handler reads a JSON request body even though this is a GET (shape: `ServiceCoreActiveCheckRequest`); OpenAPI 3.0 cannot express a GET body, so it is described here.
Responses
200— Request received successfully. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Create a service
POST /{api_key}/services/add
Create a new service record. service_status, when sent, is validated (see ServiceCreateItem); when omitted the database default 'active' applies.
Request body
| Field | Type | Description |
|---|---|---|
id | integer | Maps to engineering.enid. Normally omit. On update this would overwrite the primary key - do not send. |
cid required | integer | Customer ID. On add, required in practice (used for the price book lookup when monthlyfee is omitted). |
service_num | string | Service number/identifier |
start_date | string | Service start date (written to port_dateacc). Accepted alias of port_dateacc; NOT run through date conversion, so send YYYY-MM-DD. Ignored if port_dateacc is also sent. |
port_dateacc | string | Service start date (database column name, accepted directly). Converted with AppDate::toDBDate() and takes precedence over start_date. |
servicetype required | integer | Service type ID (esid). On add, required in practice (used for the price lookup when monthlyfee is omitted). |
monthlyfee | number | Monthly fee. On add, when omitted it is taken from the price book, else the service type's list_price. On update, omitting leaves it unchanged; sending the JSON value false triggers the same price book/list price recalculation. |
date_ended | string | Service end date, converted with AppDate::toDBDate() |
billing_cycle | string | Billing cycle |
contractterm | integer | Contract term in months |
billing_name | string | Billing name |
call_rates_id | integer | Call rates group ID (stored in ctgid) |
bundle_id | integer | Service bundle ID (stored in engineering_bundle_id) |
cost | number | Cost price |
quantity | number | Quantity (DB default 1) |
nbn_avc | string | NBN AVC identifier |
service_information_data | object | Additional service information. Re-encoded to a JSON string for storage. |
service_status | string (active | pending | suspended | pending_disconnection | disconnected | churned) | Service lifecycle status. Validated case-sensitively and strictly (type and value) against active, pending, suspended, pending_disconnection, disconnected, churned. Any other value is rejected before anything is written with {"success": false, "description": "invalid service_status"} (HTTP 200). When omitted on add the database default 'active' applies. A 'pending' service is excluded from billing. (Read responses return this as a plain string, not an enum.) |
site_id | integer | Service site to link to (engineering.engineering_site_id). Must be a live site of the service's customer in the token's department, else {"success": false, "description": "invalid site_id"}. Values <= 0 or omitted leave it unchanged. |
full_address | string | The service's primary address as a full-address string, geocoded and stored via saveAddress(). Omit/empty to leave unchanged. |
parent_enid | integer | Parent service ID (note: add accepts parent_enid, not parent_id) |
Responses
200— Service created. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate ETF for several services
POST /{api_key}/services/calculateMultipleETF
Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Response is a bare array of calculateETF() results each with an enid.
Request body
Array of:
Responses
200— ETFs calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate ETF for several services
POST /{api_key}/services/calculateMultipleETF/{date}
Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Response is a bare array of calculateETF() results each with an enid.
Request body
Array of:
Responses
200— ETFs calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute ETF for several services
POST /{api_key}/services/dMultipleoETF
Legacy alias (typo'd/deprecated URI) of `/{api_key}/engineering/doMultipleETF/{date}`. Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Runs doETF() for each. Response is a bare array of {success, enid}. Code bug: the handler signature is post($token, $enid, $date) so on the dated URIs the :date segment binds to $enid and the date is effectively ignored (today is used).
Request body
Array of:
Responses
200— ETFs processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute ETF for several services
POST /{api_key}/services/dMultipleoETF/{date}
Legacy alias (typo'd/deprecated URI) of `/{api_key}/engineering/doMultipleETF/{date}`. Body is a JSON array of enids (raw JSON; the 'data=' form does not work). Runs doETF() for each. Response is a bare array of {success, enid}. Code bug: the handler signature is post($token, $enid, $date) so on the dated URIs the :date segment binds to $enid and the date is effectively ignored (today is used).
Request body
Array of:
Responses
200— ETFs processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Delete a service
POST /{api_key}/services/delete/{enid}
Soft-deletes the service (EP_Database Delete). Returns success true even if the enid does not exist.
Responses
200— Service deleted. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Paginated service list
GET /{api_key}/services/get
Lists non-deleted services, newest start date first, 20 per page (department-scoped). Row keys are id, cid, service_num, start_date, servicetype, monthlyfee, date_ended, billing_cycle, contractterm, billing_name, call_rates_id, bundle_id, cost, quantity, parent_id, nbn_avc, service_status. Response is {results, page_number, total_pages} with no success key.
Responses
200— Page of services. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate the daily cost for an active service (monthlyfee divided by days in the current month, times quantity). Failures: `{n} not found`.
GET /{api_key}/services/get/monthlyCostByServiceNumber/daily/{service_num}
Responses
200— Daily cost calculated successfully
Calculate the pro-rata monthly cost for a service that started on the given date (calculated from monthlyfee to the end of that month). Failures: `{n} not found as starting on {date}`.
GET /{api_key}/services/get/monthlyCostByServiceNumber/proRata/{date}/{service_num}
Responses
200— Pro-rata monthly cost calculated successfully
Get the actual monthly cost charged for a service in the month of the given date (from non-void invoice data for that customer dated between the date and the end of its month). Failures are HTTP 200 with {success:false, description}: `{n} not found`, `Unable to Find invoice for customer: ...`, `{n} was not billed on {date}`.
GET /{api_key}/services/get/monthlyCostByServiceNumber/{date}/{service_num}
Responses
200— Monthly cost retrieved successfully
Paginated service list
GET /{api_key}/services/get/page
Lists non-deleted services, newest start date first, 20 per page (department-scoped). Row keys are id, cid, service_num, start_date, servicetype, monthlyfee, date_ended, billing_cycle, contractterm, billing_name, call_rates_id, bundle_id, cost, quantity, parent_id, nbn_avc, service_status. Response is {results, page_number, total_pages} with no success key.
Responses
200— Page of services. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Paginated service list
GET /{api_key}/services/get/page/{pageNumber}
Lists non-deleted services, newest start date first, 20 per page (department-scoped). Row keys are id, cid, service_num, start_date, servicetype, monthlyfee, date_ended, billing_cycle, contractterm, billing_name, call_rates_id, bundle_id, cost, quantity, parent_id, nbn_avc, service_status. Response is {results, page_number, total_pages} with no success key.
Responses
200— Page of services. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Get a service
GET /{api_key}/services/get/{enid}
Get a specific service record by ID. Does not return an error for an unknown enid: success is true and every field is null.
Responses
200— Request received successfully. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
AVC Transfer Qualification Check
POST /{api_key}/services/qualify/avc-check
Verify that an AVC ID matches a given location before submitting a transfer order. Parameters may be sent in the query string or as a form-encoded body. Validation and carrier failures are {success:false, description} (`missing location_id`, `invalid location_id format`, `missing avcid`, `invalid avcid format`, `invalid service_type`, or the carrier error message).
Responses
200— AVC check result
Search services
POST /{api_key}/services/search
Search for services with flexible criteria. The request body is a JSON **array** of criterion objects. Each criterion has a `field`, a `value`, and an optional `operator` (defaults to `like`). Multiple criteria are combined with AND. Results are automatically scoped to the API token's department. Request body is plain JSON. If no criterion is usable the response is ServiceCoreSearchErrorResponse.
Request body
Array of:
| Field | Type | Description |
|---|---|---|
field required | string (id | cid | service_num | servicetype | start_date | monthlyfee | date_ended | billing_name) | The field to filter on. API names (id, start_date, call_rates_id, parent_id, locid, site_id, username, service_status ...) are translated to the database column; the raw column names enid, port_dateacc, parent_enid, nbn_loc_id, engineering.cid, engineering.ctgid, engineering.ext_field2 and engineering.engineering_site_id are also accepted. billing_cycle, contractterm, cost and bundle_id are NOT searchable (silently ignored). `active_services` is a special flag that takes no value/operator and limits results to services that have not ended (date_ended null, 0000-00-00, 1970-01-01 or >= today). Unrecognised fields are silently ignored. |
value | object | The value to compare against. Required for every field except `active_services`. May be a string or number depending on the field. |
operator | string (= | like | < | > | <= | >= | !=) | Comparison operator. Defaults to `like` (substring match — the value is wrapped in % wildcards) when omitted. Ignored for `active_services`. |
Responses
200— Search completed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Alias of /{api_key}/customer/{cid}/service-sites. List a customer's non-deleted service sites (the engineering_sites records shown in the UI as "Service Sites"), ordered by name. Constrained to the token's department via the customer. An unknown/foreign customer returns {success:false, description:'invalid customer'}.
GET /{api_key}/services/sites/customer/{cid}
Responses
200— Service sites for the customer
Update a service
POST /{api_key}/services/update/{enid}
Update an existing service record. Only supplied keys are written. service_status, when sent, is validated (see ServiceCoreUpdateItem). Changing servicetype without sending monthlyfee recalculates monthlyfee from the customer's price book for the new type, falling back to its list_price; an explicit monthlyfee is never replaced. Errors: 'no record found to update', 'no data provided', 'invalid service_status', 'invalid site_id'.
Request body
| Field | Type | Description |
|---|---|---|
id | integer | Maps to engineering.enid. Normally omit. On update this would overwrite the primary key - do not send. |
cid | integer | Customer ID. When sent alongside a service type change that recalculates monthlyfee, this customer's price book is used; otherwise the service's stored customer is used. |
service_num | string | Service number/identifier |
start_date | string | Service start date (written to port_dateacc). Accepted alias of port_dateacc; NOT run through date conversion, so send YYYY-MM-DD. Ignored if port_dateacc is also sent. |
port_dateacc | string | Service start date (database column name, accepted directly). Converted with AppDate::toDBDate() and takes precedence over start_date. |
servicetype | integer | Service type ID (esid). Changing it without sending monthlyfee recalculates monthlyfee (see monthlyfee). |
monthlyfee | number | Optional monthly fee. When supplied (including 0) it is written as-is. When omitted and servicetype is sent with a value different from the stored service type, the fee is recalculated for the target service type from the customer's applicable price book (final_total), falling back to the service type's list_price if no price-book entry applies. When omitted and the service type is unchanged, the stored fee is left unchanged. Sending the JSON value false forces the same recalculation for the target (or stored) service type. |
date_ended | string | Service end date, converted with AppDate::toDBDate() |
billing_cycle | string | Billing cycle |
contractterm | integer | Contract term in months |
billing_name | string | Billing name |
call_rates_id | integer | Call rates group ID (stored in ctgid) |
bundle_id | integer | Service bundle ID (stored in engineering_bundle_id) |
cost | number | Cost price |
quantity | number | Quantity (DB default 1) |
nbn_avc | string | NBN AVC identifier |
service_information_data | object | Additional service information. Re-encoded to a JSON string for storage. |
service_status | string (active | pending | suspended | pending_disconnection | disconnected | churned) | Service lifecycle status. Validated case-sensitively and strictly (type and value) against active, pending, suspended, pending_disconnection, disconnected, churned. Any other value is rejected before anything is written with {"success": false, "description": "invalid service_status"} (HTTP 200). When omitted on update the stored status is unchanged. A 'pending' service is excluded from billing. (Read responses return this as a plain string, not an enum.) |
site_id | integer | Service site to link to (engineering.engineering_site_id). Must be a live site of the service's customer in the token's department, else {"success": false, "description": "invalid site_id"}. Values <= 0 or omitted leave it unchanged. |
full_address | string | The service's primary address as a full-address string, geocoded and stored via saveAddress(). Omit/empty to leave unchanged. |
locid | string | NBN Location ID, stored in nbn_loc_id (same name returned by get). Non-empty only; omit/empty leaves it unchanged. |
primaryAddress | string | Preferred name for the primary address (as returned by get); takes precedence over full_address. Omit/empty leaves unchanged. |
Responses
200— Service updated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate Early Termination Fee
GET /{api_key}/services/{enid}/calculateETF
Calculate Early Termination Fee (ETF) for a service as at :date (default today). Response is the bare calculateETF() result (no success key).
Responses
200— ETF calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Calculate Early Termination Fee
GET /{api_key}/services/{enid}/calculateETF/{date}
Calculate Early Termination Fee (ETF) for a service as at :date (default today). Response is the bare calculateETF() result (no success key).
Responses
200— ETF calculated. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute Early Termination Fee
POST /{api_key}/services/{enid}/doETF
Execute ETF: if the ETF amount is > 0 an engineering_iitems charge is created (description from the department's etf_pid product, else 'Early Termination Fee'), and the service's date_ended is set to the ETF date. Always returns {success: true}.
Responses
200— ETF processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
Execute Early Termination Fee
POST /{api_key}/services/{enid}/doETF/{date}
Execute ETF: if the ETF amount is > 0 an engineering_iitems charge is created (description from the department's etf_pid product, else 'Early Termination Fee'), and the service's date_ended is set to the ETF date. Always returns {success: true}.
Responses
200— ETF processed. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.
End a service by number
POST /{api_key}/services/{number}/endService
Sets date_ended on the active service(s) (no end date, 0000-00-00 or future end date) whose service_num equals {number}. All matching rows are updated. Error 'number not found' if none match; 'no data provided' for an empty body.
Request body
| Field | Type | Description |
|---|---|---|
date | string | End date. Used only when strictly after today; otherwise (or when omitted) the service is ended today. |
Responses
200— Service ended. Errors are returned with HTTP 200 as {"success": false, "description": ...} (ErrorResponse), e.g. 'invalid key'.