API Documentation
Our APIs give third-parties the ability to easily integrate with the OPSCOM platform.
OperationsCommander (OPSCOM) has made APIs (Application Programming Interface) available that allow for authenticated third-parties to access and manipulate data in OPSCOM as needed. This enables the accomplishment of specific functions, such as the ability to add valid permits from pay-and-display machines.
What is an API?
APIs, or "Application Programming Interfaces," are specially-designed channels for communication between software systems. Essentially, they give programmers the ability to connect your custom software application to an external system, whether it is running within your office space or out in the cloud.
When you have multiple software systems within your business, it can require a lot of duplicate data entry, which costs you time and money. The API integration project aims to save you money by reducing excess data entry by making it easy for your staff to maintain multiple databases from a single location.
Vendors program APIs into their software to allow external developers to access and manipulate their data. The third-party integration project aims to utilize these systems to eliminate excess data entry and provide new features to the software.
Please note this documentation is specific to APIs we have developed for third-parties to connect to OPSCOM.
We also offer API integration for other third-party hardware and software vendors.
- API Error Codes
- Permits API
- Push API: Vehicle Create
- Pull API: UserType
- Push API: User Create/Update
- Pull API: Overdue Violations
- Pull API: Plate Validation
- Lot Value API
API Error Codes
API error codes indicate a failure while communicating with the OPSCOM API.
Example Error
Content-Type: application/json
{ "ErrorCode": 9001, "ErrorMessage": "API Token is missing from the request."} |
Error Codes
| Error Code | Error Message |
| 9000 | Client Code is missing from the request. |
| 9001 | API Token is missing from the request. |
| 9002 | The supplied API token does not have permission to perform that request. |
| 9003 | Could not parse the request. |
| 9004 | End Time is a required field. |
| 9005 | The end time value is invalid. |
| 9006 | Plate is a required field. |
| 9007 |
The start time value is invalid. |
| 9008 | Reference ID is required. On a new permit push, a reference id is returned. This is required for updates and deletes. |
| 9009 | Record not found. |
| 9010 | The Plate Type is required. |
| 9011 | The province or state is required. |
| 9012 | The vehicle is already in the database. |
| 9013 | A unique id is required. |
| 9014 | The login source is required. |
| 9015 | The login source is invalid. |
| 9016 | The user e-mail is required. |
| 9017 | The user's first name is required. |
| 9018 | The user's last name is required. |
| 9019 | The user's email address must be unique. |
| 9020 | The user's username must be unique. |
| 9021 | The vehicle's plate length exceeds 50 characters. |
| 9022 | A record already exists with the supplied details. |
| 9030 | The field's maximum number of characters was exceeded. |
| 9031 | The field is required. |
| 9032 | The field has a minimum number of characters. |
|
9033 |
The field's value is invalid. |
|
9034 |
The API Token does not exist for the specified client. |
Permits API
Pull API: Permit Stats
The OPSCOM Controller provides a simple JSON based API to integrate with. Clients use this API to gather stats on permits pushed into OPSCOM.
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
Making API Requests
Make sure you set the HTTP Content-Type header to be application/json.
Raw Request:
POST /api/OC-TOMA/v1/permits/stats HTTP/1.1Host: controller.operationscommander.ioAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "apiToken": "YOUR-API-TOKEN", "zones": "NOT-REQUIRED--LIST-OF-ZONES"}JavaScript Request
var request = new XMLHttpRequest();request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "apiToken": "YOUR-API-TOKEN", "zones": "Lot 01,Lot 02"}request.send(JSON.stringify(body));Request Object Attributes
| Attribute |
Type |
Limits |
Possible Names |
Description |
| apiToken | String |
50-character alphanumeric including dashes |
apiToken | (Required) Your supplied API Token. |
|
zones |
String | Listed zones match zone names in database |
zones |
(Not Required) Comma delimited list of zones e.g. zone1,zone2,Lot 03,Red Lot,Street parking |
Successful Response
The response will be a json object. The same reference id will be returned.
Content-Type: application/json
{ "data": [ { "type": "standard", "zone": "zone1", "total": "4" }, { "type": "temp", "zone": "zone1", "total": "35" }, : :}Push API: Permit Delete
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
The OPSCOM Controller provides a simple JSON based API to integrate with. Clients use this API to directly feed details about existing paid permits and their changes into OPSCOM from other systems such as Parking apps.
Make sure you set the HTTP Content-Type header to be application/json.
Making API Requests
Raw Request:
POST /api/OC-TOMA/v1/permits/delete HTTP/1.1Host: controller.operationscommander.ioAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "apiToken": "YOUR-API-TOKEN", "referenceID": "PREVIOUS-REFERENCE-ID"} |
JavaScript Request:
var request = new XMLHttpRequest();request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "apiToken": "YOUR-API-TOKEN", "referenceID": "PREVIOUS-REFERENCE-ID"}request.send(JSON.stringify(body)); |
Request Object Attributes
| Attribute | Type |
Limits |
Possible Names |
Description |
| apiToken | String |
50-character alphanumeric including dashes |
apiToken | (Required) Your supplied API Token. |
|
Reference ID |
String | 50-character alphanumeric including dashes |
referenceid referenceID reference_id |
(Required) This value is supplied to when the permit push api is successful. e.g. 1a9b5375-cb75-4c71-9939-eeae550b09ac |
Successful Response
The response will be a json object. The same reference id will be returned.
Content-Type: application/json
{ "status": "success", "reference_id": "1a9b5375-cb75-4c71-9939-eeae550b09ac", "InternalReferenceID": "1a9b5375-cb75-4c71-9939-eeae550b09ac"} |
Push API: Permit Create
The Push API: Permit Create allows OPSCOM administrators to integrate external parking systems directly with the OPSCOM Controller. This RESTful integration automatically synchronizes paid or temporary permit details from third-party hardware and software, such as parking meters, pay stations, and mobile parking applications. By pushing active parking instances into the centralized database, administrators ensure real-time compliance tracking and seamless enforcement across all connected devices.
Setup and Configuration
Before third-party systems can transmit transaction data into the system, specific environmental settings and authorization keys must be established.
API access is a premium paid feature that requires licensing activation. Organizations must contact their OPSCOM Account Executive to negotiate access and enable the endpoint interface for their environment.
Admin Side Configuration
-
Secure an authenticated API token from your OPS-COM technical representative.
-
Confirm that all target parking zones match your external hardware naming conventions. Review configuration rules on the Parking Zone Administration page to avoid disconnected reporting errors.
-
Distribute the production endpoint URL and unique alphanumeric token to your third-party integration developers or vendors (e.g., HotSpot).
Using this Feature
The integration relies on an external system triggering HTTP POST requests to the centralized server. The endpoint accepts a standard structured JSON payload containing authorization, vehicle identity, and time boundaries.
Endpoint Address
POST [https://controller.operationscommander.io/api/OC-TOMA/v1/permits/push](https://controller.operationscommander.io/api/OC-TOMA/v1/permits/push)
Request Header Requirements
External systems must supply the following exact headers within every network transmission:
-
Content-Type: application/json -
Accept: application/json
Request Payload Examples
Raw HTTP Request
POST /api/OC-TOMA/v1/permits/push HTTP/1.1
Host: controller.operationscommander.io
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
{
"apiToken": "YOUR-API-TOKEN",
"Amount": "14.50",
"CurrencyID": "CAD",
"LicencePlate": "PL8RDR",
"zone": "Lot 4",
"permitNo": "L4-1138",
"startTime": "2018-07-02T09:00:00",
"endTime": "2018-07-02T09:30:00",
"promoCode": "DISCOUNT20"
}
JavaScript XMLHttpRequest Example
var request = new XMLHttpRequest();
request.open('POST', 'https://controller.operationscommander.io/api/OC-TOMA/v1/permits/push');
request.setRequestHeader('Content-Type', 'application/json');
request.setRequestHeader('Accept', 'application/json');
request.onreadystatechange = function () {
if (this.readyState === 4) {
console.log('Status:', this.status);
console.log('Headers:', this.getAllResponseHeaders());
console.log('Body:', this.responseText);
}
};
var body = {
"apiToken": "YOUR-API-TOKEN",
"Amount": "14.50",
"CurrencyID": "CAD",
"LicencePlate": "PL8RDR",
"zone": "Lot 4",
"permitNo": "L4-1138",
"startTime": "2018-07-02T09:00:00",
"endTime": "2018-07-02T09:30:00",
"promoCode": "DISCOUNT20"
};
request.send(JSON.stringify(body));
Request Object Attributes
The endpoint processes incoming data objects using strict key names. Use the definitions below to map external database variables correctly.
| Attribute | Type | Limits | Possible Names | Required / Optional | Description |
|---|---|---|---|---|---|
| apiToken | String |
50-character alphanumeric including dashes |
apiToken | Required | The unique system token supplied by OPSCOM for validation. |
| LicensePlate | String | 25-characters |
plate LicencePlate |
Required | The license plate of the vehicle receiving the parking permission. |
| Amount | String | 9-character decimal |
amount Amount |
Optional |
Transaction amount. Must contain at least 3 digits, two of which are penny values. The minimum allowable value is $0.01, and the maximum allowable value is $999999.99. |
| CurrencyID | String | 10-characters |
currency CurrencyID |
Optional | Transaction currency type. Supported defaults include CAD or USD. |
|
Start Date |
String |
20-characters |
startTime StartDateUtc |
Required |
Must be in the format of Y-m-d\TH:i:s e.g. 2000-05-30T14:38:22 For formatting help, see PHP Date Formatting |
| End Date | String |
20-characters |
endTime EndDateUtc |
Required |
Must be in the format of Y-m-d\TH:i:s e.g. 2000-05-30T14:38:22 For formatting help, see PHP Date Formatting |
| permitNo | String | 50-characters |
permitNo |
Optional | The permit identifier or unique receipt ID |
| Ticket Number | String | 50-characters |
TicketNumber |
Optional | The ticket identifier or unique receipt ID |
| zone | String | 200-characters |
zone ParkingZoneName |
Optional |
The localized parking area identifier. This should match an explicit string name inside the system. If the zone does not match a zone in our system, it will be a disconnected record and may not report properly. |
| promoCode | String | 50-characters |
promoCode |
Optional |
Alphanumeric validation string detailing applied customer discounts, validation codes, or free parking promotional campaigns (e.g., HotSpot promo keys). |
API Server Responses
Successful Response
Upon successfully accepting and writing a record to the database, the server transmits an HTTP status code 200 OK along with a tracking object.
Successful Response
The response will be a json object. Content-Type: application/json
{
"status": "success",
"reference_id": "1a9b5375-cb75-4c71-9939-eeae550b09ac",
"InternalReferenceID": "1a9b5375-cb75-4c71-9939-eeae550b09ac"
}
Best Practices and Considerations
-
Audit third-party zone names precisely. Ensure that zone names passed into the zone parameter exactly match your current system setup. If an external pay station pushes a value that does not correspond with a recognized lot name, it registers as a disconnected record and fails to populate correctly within enforcement reports.
-
Validate promotional campaign metrics. When working with mobile applications like HotSpot, instruct vendors to map their promotional parameters to the promoCode field. Administrators can track usage and verify free or discounted transaction validity by auditing the dedicated promotional code column found on the Paystation Status page.
-
Adhere strictly to UTC string constraints. Confirm that your developers match the ISO-8601 date formatting style explicitly for startTime and endTime. For technical validation, reference the PHP Date Formatting development rules.
Push API: Permit Update
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
The OPSCOM Controller provides a simple JSON based API to integrate with. Clients use this API to directly feed paid permit details into OPSCOM from other systems such as Parking Apps.
Make sure you set the HTTP Content-Type header to be application/json.
Making API Requests
Raw Request:
POST /api/OC-TOMA/v1/permits/update HTTP/1.1Host: controller.operationscommander.ioAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "apiToken": "YOUR-API-TOKEN", "referenceID": "PREVIOUS-REFERENCE-ID", "plate": "PL8RDR", "Amount": "14.50", "currency": "CAD", "endTime": "2018-07-02T09:30:00"} |
JavaScript Request:
var request = new XMLHttpRequest();request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "apiToken": "YOUR-API-TOKEN", "referenceID": "PREVIOUS-REFERENCE-ID", "plate": "PL8RDR", "Amount": "14.50", "currency": "CAD", "endTime": "2018-07-02T09:30:00"}request.send(JSON.stringify(body)); |
Request Object Attributes
| Attribute | Type | Limits | Possible Names | Description |
|---|---|---|---|---|
| apiToken | String |
50-character alphanumeric including dashes |
apiToken | (Required) Your supplied API Token. |
|
Reference ID |
String | 50-character alphanumeric including dashes |
referenceid referenceID reference_id |
(Required) This value is supplied to when the permit push api is successful. e.g. 1a9b5375-cb75-4c71-9939-eeae550b09ac |
| End Date | String |
20-characters Y-m-d\TH:i:s format. |
endTime EndDateUtc |
(Optional) Must be in the format of Y-m-d\TH:i:s e.g. 2000-05-30T14:38:22 For formatting help, see PHP Date Formatting |
| License Plate | String | 25-characters |
plate LicencePlate |
(Optional) The plate of the vehicle. |
| Amount | String | 9-character decimal |
amount Amount |
(Optional) Transaction amount This must contain at least 3 digits, two of which are penny values. The minimum allowable value is $0.01, and the maximum allowable value is $999999.99. |
| Currency | String | 10-characters |
currency CurrencyID |
(Optional) CAD, USD |
Successful Response
The response will be a json object. The same reference id will be returned.
Content-Type: application/json
{ "status": "success", "reference_id": "1a9b5375-cb75-4c71-9939-eeae550b09ac", "InternalReferenceID": "1a9b5375-cb75-4c71-9939-eeae550b09ac"} |
Push API: Vehicle Create
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
The OPSCOM Controller provides a simple JSON based API to integrate with. Clients use this API to directly feed vehicles into OPSCOM from other systems.
Make sure you set the HTTP Content-Type header to be application/json.
Making API Requests
Raw Request:
POST /api/OC_TOMA/v1/vehicles/push HTTP/1.1Host: controller.operationscommander.ioAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "apiToken": "YOUR-API-TOKEN", "plate": "PL8RDR", "plateType": "Motorcycle", "prov": "MA", "make": "8", "type": "3", "colour": "red", "year": "2011", "vin": "8GKS1AKC7FR518845"} |
JavaScript Request:
var request = new XMLHttpRequest();request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "apiToken": "YOUR-API-TOKEN", "plate": "PL8RDR", "plateType": "Motorcycle", "prov": "MA", "make": "kia", "type": "commercial", "colour": "red", "year": "2021", "vin": "8GKS1AKC7FR518845"}request.send(JSON.stringify(body)); |
Request Object Attributes
| Attribute | Type | Limits | Possible Names | Description |
|---|---|---|---|---|
| apiToken | String |
50-character alphanumeric including dashes. |
apiToken | (Required) Your supplied API Token. |
| plate | String | 50-character alphanumeric. |
plate |
(Required) The license plate. |
| plateTypeID | String |
The ID of the VechiclePlateType record. |
plateTypeID | (One of plateTypeID or plateType is required) Your supplied VehiclePlateType identifier. |
| plateType | String |
50-character alphanumeric including dashes. |
plateType | (One of plateTypeID or plateType is required) The name of the plate type. |
| provID | String |
The ID of the state/province. |
provID | (One of provID or prov is required) Your supplied state or province identifier. |
| prov | String |
50-character alphanumeric including dashes |
prov | (One of provID or prov is required) The full name of the state/province or the corresponding postal abbreviation. |
| makeID | String |
The ID of the vehicle make. |
makeID | (Optional) Your supplied vehicle make identifier. |
| make | String | 50-character alphanumeric including dashes |
make |
(Optional) The name of the vehicle manufacturer. |
| typeID | String |
The ID of the vehicle type. |
typeID | (Optional) Your supplied vehicle type identifier. |
| type | String |
50-character alphanumeric including dashes |
type | (Optional) The name of the type of vehicle that you provided. |
| colourID | String | The ID of the vehicle colour. | colourID | (Optional) Your supplied vehicle colour identifier. |
|
colour |
String |
50-character alphanumeric including dashes |
colour |
(Optional) The name of a colour that you have provided.. |
| year | String |
4 digit year. |
year |
(Optional) The model year. |
| vin | String | 25-characters |
vin |
(Optional) The vehicle identification number. |
Successful Response
The response will be a json object.
Content-Type: application/json
{ "status": "success", "vehicle_id_id": "158", "warnings":["The vehicle colour name was too long and has been truncated."]} |
Pull API: UserType
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
The OPSCOM Controller provides a simple JSON based API to integrate with. Clients use this API to obtain a list of the current profile user types in their system.
Make sure you set the HTTP Content-Type header to be application/json.
Making API Requests
Raw Request:
POST /api/OC_TOMA/v1/profiles/types/list HTTP/1.1Host: controller.operationscommander.ioAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "apiToken": "YOUR-API-TOKEN",} |
JavaScript Request:
var request = new XMLHttpRequest();request.open('POST', 'https://controller.operationscommander.io/api/OC_TOMA/v1/profiles/types/list');request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "apiToken": "YOUR-API-TOKEN"}request.send(JSON.stringify(body)); |
Request Object Attributes
| Attribute | Type | Limits | Possible Names | Description |
|---|---|---|---|---|
| apiToken | String |
50-character alphanumeric including dashes. |
apiToken | (Required) Your supplied API Token. |
Successful Response
The response will be a json object.
Content-Type: application/json
{ "status": "success", "user_types": [ { "id": "1", "type_name": "Full Time Student", "ext_info": "Student" }, { "id": "6", "type_name": "Demo", "ext_info": "Public" }, { "id": "7", "type_name": "Full Time Staff", "ext_info": "Staff" }, { "id": "8", "type_name": "Part Time Staff", "ext_info": "Staff" }, { "id": "9", "type_name": "Part Time Student", "ext_info": "Student" }, { "id": "10", "type_name": "Exchange Student", "ext_info": "Student" }, { "id": "11", "type_name": "Athletics Member", "ext_info": "Athletics" }, { "id": "12", "type_name": "Complimentary", "ext_info": "Public" }, { "id": "13", "type_name": "Daily Reserved", "ext_info": "Public" } ]} |
Push API: User Create/Update
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
The OPSCOM Controller provides a simple JSON based API to integrate with. Clients use this API to push to OPSCOM new users and update existing users directly from another system. For example, you may wish to push Student and Staff information from Banner directly to OPSCOM.
Make sure you set the HTTP Content-Type header to be application/json.
Making API Requests
Raw Request:
POST /api/OC_TOMA/v1/profiles/push HTTP/1.1Host: controller.operationscommander.ioAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "apiToken": "YOUR-API-TOKEN", "unique_id": "tester23", "login_source": "OPSCOM", "first_name":"firstname", "last_name":"lastname", "user_name":"username", "email":"test@test.com", "street":"123 Main Street, 123 Main Street,123 Main Street,123 Main Street,123 Main Street,123 Main Street", "city":"Everywhere", "province":"bc", "state":"NY", "postal_code":"HOHOHO", "zip":"12345-1212", "street2":"123 General Street", "city2":"Somewhere", "province2":"AB", "state2":"MA", "postal_code2":"A9A9A9", "zip2":"54321-1212", "phone_cell":"613-555-1212", "user_type_id":"6", "employ_no":"employee number: default", "employee_phone":"emp ph. klondike 555", "student_no":"SN 543209854", "student_phone":"999", "driver_licence_num":"QC 99999999", "driver_license_num":"NYNY", "date_of_birth":"1901-01-31", "locker_user_type_id":"3", "driver_licence_prov":"BC", "driver_license_state":"CA"} |
JavaScript Request:
var request = new XMLHttpRequest();request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "apiToken": "YOUR-API-TOKEN", "unique_id": "tester23", "login_source": "OPSCOM", "first_name":"firstname", "last_name":"lastname", "user_name":"username", "email":"test@test.com", "street":"123 Main Street, 123 Main Street,123 Main Street,123 Main Street,123 Main Street,123 Main Street", "city":"Everywhere", "province":"bc", "state":"NY", "postal_code":"HOHOHO", "zip":"12345-1212", "street2":"123 General Street", "city2":"Somewhere", "province2":"AB", "state2":"MA", "postal_code2":"A9A9A9", "zip2":"54321-1212", "phone_cell":"613-555-1212", "user_type_id":"6", "employ_no":"employee number: default", "employee_phone":"emp ph. klondike 555", "student_no":"SN 543209854", "student_phone":"999", "driver_licence_num":"QC 99999999", "driver_license_num":"NYNY", "date_of_birth":"1901-01-31", "locker_user_type_id":"3", "driver_licence_prov":"BC", "driver_license_state":"CA"}request.send(JSON.stringify(body)); |
Request Object Attributes
| Attribute | Type | Limits | Possible Names | Description |
|---|---|---|---|---|
| apiToken | String |
50-character alphanumeric including dashes. |
apiToken | (Required) Your supplied API Token. |
| Unique ID | String | 50-character alphanumeric including dashes. | unique_id | (Required) An unique identification number of the user. |
| Login Source | String | 20-character alphanumeric including dashes. | login_source | (Required) Your supplied login source. |
| First Name | String | 50-character alphanumeric including dashes. | first_name | (Optional) User's first name. |
| Last Name | String | 50-character alphanumeric including dashes. | last_name | (Optional) User's last name. |
| User Name | String | 50-character alphanumeric including dashes. | user_name | (Optional) Unique username. |
| String | 100-character alphanumeric including dashes. | (Optional) Valid email address . | ||
| Street - address 1 | String | street | (Optional) User's primary street number and name. | |
| City - address 1 | String | 50-character alphanumeric including dashes. | city | (Optional) User's primary city name. |
| Province - address 1 | String | 2-character postal abbreviation eg. "MA" |
province, state |
(Optional) User's primary province or state. |
| Postal Code - address 1 | String | 20-character alphanumeric including dashes. |
postal_code, zip |
(Optional) User's primary postal code or zip. |
| Street - address 2 | String | 20-character alphanumeric including dashes. | street2 | (Optional) User's alternate street number and name. |
| City - address 2 | String | 50-character alphanumeric including dashes. | city2 | (Optional) User's alternate city name. |
| Province - address 2 | String | 2-character postal abbreviation eg. "MA" |
province2, state2 |
(Optional) User's alternate province or state. |
| Postal_Code - address 2 | String | 20-character alphanumeric including dashes. |
postal_code2, zip2 |
(Optional) User's alternate postal code or zip. |
| Cell phone number | String | 20-character alphanumeric including dashes. | phone_cell | (Optional) User's cell phone number |
| User Type ID | String | Id number of UserType | user_type_id | (Optional) A reference number to the type of user. |
| Employee Number | String | 50-character alphanumeric including dashes. | employ_no | (Optional) User's employee number. |
| Employee phone number | String | 50-character alphanumeric including dashes. | employee_phone | (Optional) User's employee phone number. |
| Student number | String | 50-character alphanumeric including dashes. | student_no | (Optional) User's student number. |
| Student phone number | String | 50-character alphanumeric including dashes. | student_phone | (Optional) User's student phone number. |
| Driver licence number | String | 255-character alphanumeric including dashes. |
driver_licence_num, driver_license_num |
(Optional) User's driver's licence number or driver's license number. |
| Date of Birth | String | 10-character date in format 'yyyy-mm-dd' | date_of_birth | (Optional) User's date of birth in format "YYYY-MM-DD. |
| Locker User Type ID | String | Id number of LockerUserType | locker_user_type_id | (Optional) A reference the the user's locker type id of the user. |
| Driver's licence province | String | 2-character postal abbreviation eg. "MA" |
driver_licence_prov, driver_license_state |
(Optional) The province or state of the user's driver's licence. |
Successful Response
The response will be a json object.
Content-Type: application/json
{ "status": "success", "reference_id": 44} |
Pull API: Overdue Violations
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
The OPSCOM Controller provides a simple JSON based API to integrate with.
Clients use this API to export a list of the currently overdue violations, which are then marked as having been sent to collections.
Make sure you set the HTTP Content-Type header to be application/json.
Information
When accessed, this API will send all overdue violations that have not been sent to collections yet in a JSON object. It will also mark them as having been sent to collections, so subsequent calls to the API will not get the same information more than once.
This is a POST request. Data is being posted to the server.
POST /api/{client}/v1/violations/send_overdue_to_collections
Sample Request - All Params
/api/OC_TOMA/v1/violations/send_overdue_to_collections
Making API Requests
Raw Request:
POST /api/OC_TOMA/v1/violations/send_overdue_to_collections HTTP/1.1Host: controller.operationscommander.ioAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "apiToken": "YOUR-API-TOKEN",} |
JavaScript Request:
var request = new XMLHttpRequest();request.open('POST', 'https://controller.operationscommander.io/api/OC_TOMA/v1/violations/send_overdue_to_collections');request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "apiToken": "YOUR-API-TOKEN"}request.send(JSON.stringify(body)); |
Request Object Attributes
| Attribute | Type | Limits | Possible Names | Description |
|---|---|---|---|---|
| apiToken | String |
50-character alphanumeric including dashes. |
apiToken | (Required) Your supplied API Token. |
Successful Response
The response will be a JSON object.
Content-Type: application/json
{ "records": [ { "ViolationID": 9, "SemPermitID": 0, "Ticket": "1-100013", "VehicleID": 8, "Spoiled": 0, "TicketType": 2, "Issued": "2016-05-03T20:00:00.000000Z", "convNotice": null, "Due": "2016-05-23T20:00:00.000000Z", "ViolationTypeID": -1, "Fine": 50, "AdjustedFine": 0, "Towing": 0, "taxAmount": "0.0000", "Writer": 8, "LocationID": 6, "Comment": null, "TicketAppeal": null, "appealType": 0, "appealFormat": null, "AccessAdminID": 7, "ActionedPer": null, "Created": "2020-10-15T20:13:24.000000Z", "AppealUserID": 0, "AppealProcessDate": null, "AppealAdminID": 0, "AppealComment": null, "AppealAdminComment": null, "AutoNotice": 2, "ProcessedByCollection": null, "SentToCollections": null, "PrivateComments": null, "DriveAway": 0, "UUID": "d9a1c8bb-4ed1-411e-91b1-0b63ba52e04d", "VioNotice": null, "latitude": null, "longitude": null, "Warning": null, "userid": null, "incidentID": null, "failToIdentify": null, "pin": null, "duplicate": null, "AdjustmentReason": null, "user": null, "vehicle": { "VehicleID": 8, "Active": 1, "lastUpdate": "2020-10-15T20:13:03.000000Z", "Plate": "AJNR123", "PlateTypeID": 4, "ProvID": 9, "MakeID": 13, "TypeID": 5, "ColourID": 14, "Year": 2006, "TotalVio": 0, "TotalUnpaid": 0, "TotalWarning": 0, "created": "2020-10-15T20:13:03.000000Z", "externallookupdate": null, "externallookupRequestID": null, "modified": "2022-03-16T21:36:09.000000Z", "vehicleAlert": null, "vin": null, "drivers": [ { "UserID": 73, "enabled": null, "salutation": "Dr.", "firstName": "stephen_14Oct_1114", "middleName": null, "lastName": "stephen_14Oct_1114", "username": "stephen_14Oct_1114", "email": "stephen_14Oct_1114@test", "street": "1234 Main Street", "city": "Ottawa", "prov": 9, "postal": "H0H0H0", "street2": null, "city2": null, "prov2": null, "postal2": null, "phonecell": "6135551212", "status": 1, "UserTypeID": 7, "employNo": "staff12341115", "deptNameID": null, "ePhone": null, "staffFacultyFlag": 0, "studentNo": null, "sPhone": null, "sPhone2": null, "lastUpdated": "2022-08-29T21:31:12.000000Z", "created": "2020-10-15T20:12:57.000000Z", "privateComment": null, "publicComment": null, "DLNum": "DL 123451114", "DOB": "2020-10-14T04:00:00.000000Z", "StaffMailPermit": 0, "ExtendedID": null, "UserUUID": "42c5d253-2f06-4ab6-9090-969333c25da6", "CampusBox": null, "newEmail": null, "ReadOnlyUserID": null, "studentNo_int": null, "employNo_int": null, "StuCampusLocation": null, "EmpCampusLocation": null, "MailPermitTo": "Permanent Mailing Address", "isCloudAccount": null, "lastSelfUpdated": null, "emailConsent": null, "T2P_reminders": null, "reminderTime": null, "lockerUserTypeID": null, "encid": "A063AA9AC458DA5581FC777ADC9875FF", "preferredname": null, "plateAlert": 0, "peopleAlert": 0, "salt": "85cf3dbb-54de-48e3-a2d1-0b312dd4cea8", "forcePasswordChange": 1, "lastpasswordchange": null, "DLprov": 66, "loginSource": "OPSCOM", "company_id": null, "taxexemption": null, "company_manager": null, "receives_invoice": null, "account_number": null, "company_bill_recipient": null, "kais_employer": null, "kais_building": null, "kais_supervisor_name": null, "kais_supervisor_title": null, "register_token": null, "api_token": null, "modified": "2022-08-29T21:36:24.000000Z", "bambora_customer_code": null, "language": "fr", "preferred_communication_method": null, "laravel_through_key": 8 } ], "make": { "MakeID": 13, "MakeName": "Chevrolet", "modified": "2020-10-15T20:13:11.000000Z" }, "colour": { "ColourID": 14, "ColourName": "Red", "ColourKey": null, "modified": "2020-10-15T20:13:08.000000Z" }, "vehicle_type": { "TypeID": 5, "TypeName": "Compact", "modified": "2020-10-15T20:13:13.000000Z" }, "plate_type": { "TypeID": 4, "TypeName": "Passenger", "modified": "2022-04-15T20:58:56.000000Z", "typeCode": "passenger" }, "province": { "ProvID": 9, "ProvName": "Ontario", "Country": 1, "ProvCode": "ON", "modified": "2022-08-30T21:54:10.000000Z", "payments": 1 } }, "location": { "LocationID": 6, "LocationName": "Downtown Business District", "WriterVisible": 1, "GisNo": 0, "modified": "2020-10-15T20:04:19.000000Z" }, "details": [ { "ViolationsDetailID": 10, "ViolationID": 9, "Ticket": "1-100013", "ViolationTypeID": 9, "LocationID": 6, "offenceFine": 50, "discountFlag": 1, "discountAmount": 10, "discountHours": 168, "created": "2020-10-15T20:13:33.000000Z", "type": { "ViolationTypeID": 9, "ViolationDescr": "Parked in Loading Zone", "DefaultCost": 50, "created": "2020-10-15T20:13:41.000000Z", "discountFlag": true, "discountAmount": 10, "discountHours": 168, "adminOnly": false, "violationkey": null, "modified": "2020-10-15T20:13:41.000000Z", "category_id": 1, "adjustable": false, "bylawcode": "BL-78" } } ], "attachments": [ { "attachID": 1, "storageLocation": "oc_tomahawk/VIOLATIONS/2022/08/23/index-debf76b6.png", "attachName": "index-debf76b6", "attachExt": "png", "attachMime": "image/png", "relatedType": "VIOLATIONS", "relatedID": 9, "relatedNote": "1-100013", "created": "2022-08-23T18:48:36.000000Z", "archived": null, "uniqueid": "70756a09-550e-433d-b6f4-75b0bfdcef60" }, { "attachID": 2, "storageLocation": "oc_tomahawk/VIOLATIONS/2022/08/23/index-b11529e8.png", "attachName": "index-b11529e8", "attachExt": "png", "attachMime": "image/png", "relatedType": "VIOLATIONS", "relatedID": 9, "relatedNote": "1-100013", "created": "2022-08-23T20:55:23.000000Z", "archived": null, "uniqueid": "079541cf-302e-4c42-a2cf-38665643d364" } ], "category": { "TicketTypeID": 2, "TicketTypeName": "Municipal", "HandHeldVisible": 0, "modified": "2020-10-15T20:12:51.000000Z", "archived": null, "appliesTo": 1, "enableFailToIdentify": 0 } } ], "state": { "version": "2022.5.hawksbill.0-rc", "csrf_token": "xSc9UppEG8iMXFu606Z6sfemODRyHuoyvKYT0vs6" }} |
Pull API: Plate Validation
API access is a paid feature and must be granted by OPSCOM. Email your Account Executive to negotiate access.
Use this API to obtain details related to a plate. Plate details include permits, alerts and DNTT status.
Make sure you set the HTTP Content-Type header to be application/json.
Making API Requests
Raw Request
POST /api/v1/validate/plate HTTP/1.1Host: service.OPSCOM.comAccept: application/jsonContent-Type: application/jsonCache-Control: no-cache{ "api_token": "YOUR-API-TOKEN", "client": "<client ID>", "plate": "<plate to validate>"} |
JavaScript Request
var request = new XMLHttpRequest();request.setRequestHeader('Content-Type', 'application/json');request.setRequestHeader('Accept', 'application/json');request.onreadystatechange = function () { if (this.readyState === 4) { console.log('Status:', this.status); console.log('Headers:', this.getAllResponseHeaders()); console.log('Body:', this.responseText); }};var body = { "api_token": "YOUR-API-TOKEN", "client": "<client ID>", "plate": "<plate to validate>"}request.send(JSON.stringify(body)); |
Request Object Attributes
| api_token | String |
50-character alphanumeric including dashes. |
(Required) Your supplied API Token. | |
| client | String | client identifier | Required | |
| plate | String | vehicle plate | Required |
Response Values
| error | integer | error code | 0=success |
| data | JSON bundle | returned data | |
| data.response | String |
{permits}\n\nALARM: {alarm}\n\n DNTT: {DNTT} |
empty if no data |
| data.plate | String | plate validated | |
| data.responseJSON | JSON bundle | response in JSON | |
| data.responseJSON.permits | Array |
array of permits
|
all elements: String |
| data.responseJSON.dntt | Array |
array of DNTT (do not ticket tow) results
|
all elements: String |
| data.responseJSON.alarm | String | alarm associated with plate | or linked driver |
| message | String | system error message |
Successful Response
The response will be a json object.
Content-Type: application/json
/* The below response is a merged example of different fields that may be in the response. - 'type' may be: standard, temp, Validated, T2, HotSpot, or any other "origin"*//* sample response with many included details */{ "error": 0, "data": { /* 'response' is a string concatenated list of all values carriage return delineated */ "response": "standard: BIKE\n Expires: 2025-04-30 23:59:59\nstandard: MOTO-S\n Expires: 2025-04-30 23:59:59\n\nALARM: Wanted to talk with.\n\nDNTT: Main Campus\n2024-11-15 00:00:00-2024-11-15 23:59:00 \nCLEAR FOR ANY PAY AREA\n\n", "plate": "ABC123", "responseJSON": { "permits": [ { "expires": "2025-04-30 23:59:59", "type": "standard", "shortName": "BIKE" }, { "expires": "2025-04-30 23:59:59", "type": "standard", "shortName": "MOTO-S" } ], /* like 'permits', 'dntt' (do not ticket or tow) could be an array of values */ "dntt": [{ "notes": "CLEAR FOR ANY PAY AREA", "start": "2024-11-15 00:00:00", "location": "Main Campus", "end": "2024-11-15 23:59:00" }], "alarm":"Wanted to talk with." }, } "message": ""} |
Response Samples
Any response listed below could be merged with any other. This is a list of possible responses to demonstrate responses with data.
/* No data */{ "error": 0, "data": { "response": "", "plate": "ABC123", "responseJSON": {} }, "message": ""}/* standard (temp, Validated, T2, HotSpot, ...) */{ "error": 0, "data": { "response": "standard: LOT3\n Expires: 2025-04-30 23:59:59\nstandard: MOTO-S\n Expires: 2025-04-30 23:59:59\n\n", "plate": "ABC890", "responseJSON": { "permits": [ { "expires": "2025-04-30 23:59:59", "type": "standard", "shortName": "BIKE" }, { "expires": "2025-04-30 23:59:59", "type": "standard", "shortName": "MOTO-S" } ], } }, "message": ""}/* plate with alarm */{ "error": 0, "data": { "response": "ALARM: 15-AS123 Lex Luthor (08 JUL 84) wanted by OPS.\r\n\r\n*** Violence / Weapons ***\n\n", "plate": "ABC456", "responseJSON": { "alarm": "15-AS123 Lex Luthor (08 JUL 84) wanted by OPS.\r\n\r\n*** Violence / Weapons ***" } }, "message": ""}/* DNTT: do not ticket or tow */{ "error": 0, "data": { "response": "DNTT: Lot 6\n2024-10-23 00:00:00-2025-04-30 23:59:00 \nHertz truck has permission to park overnight in lot 6. Rental for We-Move-It Services\n\n", "plate": "DEF123", "responseJSON": { "permits": [], "dntt": [ { "notes": "Hertz truck has permission to park overnight in lot 6. Rental for We-Move-It Services", "start": "2024-10-23 00:00:00", "location": "Lot 6", "end": "2025-04-30 23:59:00" } ], "active": "1" } }, "message": ""} |
Lot Value API
The Lot Value API provides administrators with a programmatic version of the existing Lot Value Report. Its primary purpose is to retrieve real-time parking lot occupancy, valuation, and capacity data directly from the OPSCOM Controller, allowing organizations to independently ingest this information into their own custom data dashboards or third-party reporting tools.
Setup and Configuration
Before querying the endpoint, A Tomahawk Support agent must generate an authentication token with the correct structural permissions assigned. Once this token is generated for you, it will be sent securely to you, and you can use this API key in the body of a get request, sent to this endpoint:
| https://controller.preview.operationscommander.io/api/[YOUR CLIENT ID]/v1/permits/lot-values |
This is how the body should be formatted to receive lot values in return;
|
{
"apiToken": "0d2bef1a-4819-4c6a-b552-1b9e3d936333"
}
|
Using this Feature
The endpoint mimics the data structure of the standard system report but delivers it as a structured payload for external integration.
Expected API Responses
A successful request returns a structured JSON payload containing real-time data for all configured parking lots. The output includes individual lot identifiers, total capacities, active permit counts, current vehicle volume calculations, and the monetary value assigned to the spaces.
If an unauthenticated key is passed into the request body, the server rejects the connection.
Here is an example of what the API will return:
| [ { "lot_type": "Y", "lot_name": "TU Residence", "default_cost": 525, "total_permits": 20, "rented_permits": 0, "utilized_pct": 0, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "TU Residence Visitors", "default_cost": 11, "total_permits": 0, "rented_permits": 0, "utilized_pct": null, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "S", "lot_name": "TU Semester East", "default_cost": 100, "total_permits": 21, "rented_permits": 17, "utilized_pct": 80.95, "amount_projected": 1700, "amount": 2897.8783, "tax_amount": 0, "tax_amount1": 144.89392, "tax_amount2": 231.83026, "total": 3274.6 }, { "lot_type": "M", "lot_name": "TU Semester Central", "default_cost": 125, "total_permits": 60, "rented_permits": 3, "utilized_pct": 5, "amount_projected": 375, "amount": 313.08447, "tax_amount": 0, "tax_amount1": 15.65422, "tax_amount2": 25.04676, "total": 353.79 }, { "lot_type": "Y", "lot_name": "TUSC Yearly Staff", "default_cost": 350, "total_permits": 10, "rented_permits": 0, "utilized_pct": 0, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "Y", "lot_name": "TUSC Yearly Executive", "default_cost": 0, "total_permits": 10, "rented_permits": 0, "utilized_pct": 0, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "TU Visitors", "default_cost": 11, "total_permits": 0, "rented_permits": 0, "utilized_pct": null, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "Veritas Communications - All Lots", "default_cost": 165, "total_permits": 28, "rented_permits": 2, "utilized_pct": 7.14, "amount_projected": 330, "amount": 330, "tax_amount": 0, "tax_amount1": 16.5, "tax_amount2": 26.4, "total": 372.9 }, { "lot_type": "M", "lot_name": "Veritas Communications - Complimentary", "default_cost": 0, "total_permits": 5, "rented_permits": 0, "utilized_pct": 0, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "North Lot", "default_cost": 195, "total_permits": 0, "rented_permits": 0, "utilized_pct": null, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "Solus Tech Inc", "default_cost": 183, "total_permits": 15, "rented_permits": 2, "utilized_pct": 13.33, "amount_projected": 366, "amount": 366, "tax_amount": 0, "tax_amount1": 18.3, "tax_amount2": 29.28, "total": 413.58 }, { "lot_type": "M", "lot_name": "Recreation Complex", "default_cost": 0, "total_permits": 0, "rented_permits": 0, "utilized_pct": null, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "Main Street Parking", "default_cost": 200, "total_permits": 20, "rented_permits": 0, "utilized_pct": 0, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "O", "lot_name": "Public Works", "default_cost": 0, "total_permits": 30, "rented_permits": 0, "utilized_pct": 0, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "Mall Parking", "default_cost": 0, "total_permits": 0, "rented_permits": 0, "utilized_pct": null, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "Main Street Private Parking", "default_cost": 150, "total_permits": 200, "rented_permits": 0, "utilized_pct": 0, "amount_projected": 0, "amount": 0, "tax_amount": 0, "tax_amount1": 0, "tax_amount2": 0, "total": 0 }, { "lot_type": "M", "lot_name": "TU South Garage", "default_cost": 75, "total_permits": 3000, "rented_permits": 2, "utilized_pct": 0.07, "amount_projected": 150, "amount": 150, "tax_amount": 0, "tax_amount1": 7.5, "tax_amount2": 12, "total": 169.5 } ] |
Best Practices and Considerations
-
Verify token scopes before deployment. The API token must be exactly as it appears when it was sent to you by OPSCOM. It is your information's password.
-
Match pull frequencies to operational needs. This API should not need to be polled more than once an hour.