OwlOps Public API — Getting Started
Connect your systems to the data captured in OwlOps
Overview
The OwlOps Public API lets your systems read your OwlOps data (tasks, assets, inventory, invoices, activity logs and checklists) and create, update, reassign and close tasks. Use it to feed dashboards, data warehouses and reporting tools, or have a monitoring system open a ticket the moment it detects a problem and close it once the problem is confirmed fixed.
Getting an API Key
Open the Setup menu in the OwlOps web platform and select API Keys to create and manage your keys. (Need help? Contact support@owlops.com.)
Your API key will look like this: owlk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Important: Store your API key securely. It can't be recovered. If you lose it, create a new one.
Read-only and write access
New keys are read-only. To let a key create and update tasks, tick Allow writes when you create the key, or under Edit on an existing key. Only users with the API Keys admin permission can change this. A read-only key that tries to write gets a 403.
Who a key runs as
Every key runs as a user in your company. That user shows as the creator of the tasks the key opens, and the key can only read tasks that user can see in OwlOps.
For an integration, create an API user under Setup > API Keys > API Users. An API user is a service account such as "Alarm Monitor". It has no login, isn't offered as an assignee, and starts with no locations, so it sees only the tasks it creates. To let it also see other tasks at your locations (for example, tickets your team opened by hand), copy locations from a person when you create it.
Locking a key to a location or category
A key can be locked to a location or asset, and/or to a category. Tasks the key creates are filed there automatically, and a request that names anything else is refused (400). This is useful when a system should only ever raise one kind of ticket.
API Documentation
Full interactive documentation is available in Swagger:
https://api-owlops-public-bugrb4gxeqcghqh5.eastus2-01.azurewebsites.net/swagger
Swagger lists every endpoint with its request and response formats, filter parameters and field descriptions. You can also send requests from the browser. Note that writes made there create real tasks.
Authentication
Include your API key in the X-Api-Key header with every request:
GET /v1/tasks Host: api-owlops-public-bugrb4gxeqcghqh5.eastus2-01.azurewebsites.net X-Api-Key: owlk_your_key_here
Send request bodies as JSON with Content-Type: application/json.
Available Endpoints
Tasks: read
| Endpoint | Description |
|---|---|
GET /v1/tasks |
List tasks with optional filters |
GET /v1/tasks/{id} |
Get a single task with full detail |
GET /v1/tasks/{id}/log |
Activity log for a specific task |
GET /v1/tasklog |
Activity log across all tasks by date range |
Tasks: write (the key needs write access)
| Endpoint | Description |
|---|---|
POST /v1/tasks |
Create a task |
POST /v1/tasks/{id}/notes |
Add an update, optionally changing the priority |
POST /v1/tasks/{id}/assign |
Reassign the person and/or vendor |
POST /v1/tasks/{id}/close |
Close a task (notes required) |
Lookups: the IDs and names you need to create tasks
| Endpoint | Description |
|---|---|
GET /v1/departments |
Locations, with store number (short code) and task list ID |
GET /v1/categories |
Categories and subcategories |
GET /v1/users |
People tasks can be assigned to |
GET /v1/vendors?departmentId=… |
Vendors available at a location (add assignedTaskListAssetId for a category) |
Checklists
| Endpoint | Description |
|---|---|
GET /v1/checklist-templates |
Checklist templates |
GET /v1/checklist-templates/{id} |
A template with its sections and items |
GET /v1/checklists |
Completed and in-progress checklists by date range |
GET /v1/checklists/{taskId} |
One checklist with every answer, photo and follow-up task |
GET /v1/checklists/results |
One row per answer, for reporting |
Assets, inventory and invoices
| Endpoint | Description |
|---|---|
GET /v1/assets |
List assets with optional filters |
GET /v1/assets/{id} |
Get a single asset with full detail |
GET /v1/inventory |
List inventory items with optional filters |
GET /v1/inventory/{id} |
Get a single inventory item with full detail |
GET /v1/invoices |
List invoices with optional filters |
GET /v1/invoices/{id} |
Get an invoice with line items |
Pagination
All list endpoints return paginated results. Use the page and pageSize query parameters to move through them:
GET /v1/tasks?page=1&pageSize=25
Every response includes a pagination object:
{ "data": [ ... ], "pagination": { "page": 1, "pageSize": 25, "totalCount": 142, "totalPages": 6, "hasNextPage": true } }
The maximum page size is 250 (100 for task log endpoints).
Filtering
Filters use label values, not internal IDs. For example:
GET /v1/tasks?status=Open&priority=High GET /v1/assets?assetType=Capital&status=Active GET /v1/inventory?assetType=Parts&stockState=toOrder GET /v1/invoices?status=Paid&from=2026-01-01&to=2026-03-31
Tasks can be filtered by status, priority, taskType (Fix, Need, Do, Checklist), assetId, assignedTaskListAssetId (a category or subcategory ID from /v1/categories; a category includes its subcategories), externalRef, q (subject or description contains), and from / to (created date range).
Assets can be filtered by assetType and status.
Inventory can be filtered by assetType and stockState (toOrder for items at or below their reorder minimum, or excess for items above their maximum).
Invoices can be filtered by status, from and to (invoice date range).
Task log (date range) requires both from and to (maximum 90 days) and can be filtered by logType.
Checklists require from and to (maximum 90 days). You can filter by checklistName, checklistTemplateId, departmentId, status, completed and pretask. Add dateField=completed to filter by completion date instead of start date.
Lookups (/v1/departments, /v1/categories, /v1/users) take q to search by name.
All dates use ISO 8601: a date (2026-04-14) or a date and time (2026-04-14T13:00:00).
Creating and Updating Tasks
Creating, updating, reassigning and closing tasks sends the same notifications as doing it in the app. Test on a test location first.
Create a task
POST /v1/tasks { "subject": "Alarm offline", "description": "Alarm panel offline at store 1234 (incident 98765)", "department": "1234", "category": "IT", "subCategory": "Ring Alarm System", "priority": "High", "assignTo": "jane.smith@example.com", "externalRef": "alarm-98765" }
A new task returns 201 with the task ID and the full task.
| Field | Notes |
|---|---|
subject |
Required, up to 50 characters |
description |
Full details |
Where: department, departmentId or assetId |
Send one. department is the store number (short code) or exact location name. assetId is a piece of equipment, or a location's taskListAssetId from /v1/departments |
What: category + subCategory, or assignedTaskListAssetId |
Names or the ID from /v1/categories |
priority |
Low, Medium, High, Urgent, Non-Urgent. If omitted, your OwlOps default applies |
assignTo or assignedUserId |
default (or omitted) uses the assignee configured in OwlOps for that location and category. Otherwise send a person's email, or their name as "First Last". assignedUserId comes from /v1/users |
assignVendor or assignedVendorId |
default (or omitted) uses the configured vendor, none dispatches no vendor, or send a vendor's name or email. /v1/vendors lists the options |
taskType |
Fix (default), Need, Do, Project |
dueDate |
Optional |
externalRef |
Your own reference, such as an alarm or incident ID (see below) |
A name that matches nothing returns 400. A name that matches more than one person, location or vendor returns 409 with the candidates. Pick the right one and send its ID.
Avoiding duplicate tickets with externalRef
Send your system's incident ID as externalRef.
- While that task is open, creating it again returns
200with"created": falseand the existing task. Nothing new is created, so one call both checks and creates. - A reference belongs to one task for good. Once that task is closed, creating with the same reference returns
409. Use a new reference for each new incident. GET /v1/tasks?externalRef=alarm-98765finds the task later.
OwlOps also refuses an identical task from the same key within 10 seconds: same location or asset, category, type and description. That returns 409 with the earlier taskId. Including your incident reference in the description keeps separate incidents distinct.
Update, reassign and close
POST /v1/tasks/{id}/notes { "notes": "Still offline after reboot", "priority": "Urgent" } POST /v1/tasks/{id}/assign { "assignTo": "default", "notes": "Back to the store team" } POST /v1/tasks/{id}/close { "notes": "Alarm restored; confirmed by monitoring" }
/notesadds an update to the task's activity log. Includepriorityto change it in the same update./assignchanges the person, the vendor, or both. A field you leave out is not changed./closerequiresnotes. Closing a task that's already closed returns409.
Checklists
GET /v1/checklists lists checklists started (or, with dateField=completed, completed) in a date range, with progress, score and out-of-range counts. GET /v1/checklists/{taskId} returns one checklist with every answer, photo and follow-up task. GET /v1/checklists/results returns one row per answer for reporting.
A checklist is completed once its task is Closed or Closed - Pending Invoice. A pre-task checklist (one completed before working a task) is completed once submitted. Pre-task checklists are returned with "pretask": true. Use pretask=only or pretask=exclude to separate them.
For example, the Restaurant Walkthroughs completed in the last 7 days:
GET /v1/checklists?checklistName=Restaurant Walkthrough&dateField=completed&from=2026-04-07&to=2026-04-14
Tasks raised from a checklist answer carry a sourceChecklist showing the checklist, the item and the answer that triggered them.
Checklist templates are live, not versioned. When an administrator edits a checklist item's name, description, range or scoring, the change applies everywhere, including checklists completed before the edit. Results always show the item's current definition next to the answer that was recorded. If you need a point-in-time record of exactly what the technician saw, store the response when you first retrieve the completed checklist.
Items removed from a template since a checklist was completed still appear in that checklist's results, marked active: false (itemActive: false on /v1/checklists/results), so answers you've already received are never dropped.
Photos, audio and documents are returned as direct links. Links do not expire.
Recommended Integration Pattern
To keep your systems in sync, we recommend a daily pull of both tasks and task log entries. For example, each morning pull the previous day's data.
New and updated tasks:
GET /v1/tasks?from=2026-04-13&to=2026-04-14&pageSize=100
All activity from yesterday (updates, hours logged, parts, notes):
GET /v1/tasklog?from=2026-04-13&to=2026-04-14&pageSize=100
Between the two, you'll have a complete picture of new work orders and all activity across your tasks for the day.
Usage Patterns
How you use the API depends on your integration needs. Here are some common approaches.
Daily Sync
Pull the previous day's tasks and activity log each morning to keep an external system in sync. Best for reporting dashboards, data warehouses and ERP integrations.
GET /v1/tasks?from=2026-04-13&to=2026-04-14&pageSize=100 GET /v1/tasklog?from=2026-04-13&to=2026-04-14&pageSize=100
Periodic Polling
Poll every 15–60 minutes for near-real-time updates. Use a short date range to capture recent activity.
GET /v1/tasks?from=2026-04-14T12:00:00&to=2026-04-14T13:00:00&pageSize=100 GET /v1/tasklog?from=2026-04-14T12:00:00&to=2026-04-14T13:00:00&pageSize=100
At 60 requests per minute, polling every 15 minutes stays well within rate limits.
Monitoring System Tickets
Let a monitoring system (alarms, drive-thru timers, equipment sensors) open a ticket when it detects a problem and close it when the problem clears:
- Create the task with your incident ID as
externalRef. If a ticket for that incident is already open, you get it back instead of a duplicate. - When the problem clears, find the task with
GET /v1/tasks?externalRef=…and close it withPOST /v1/tasks/{id}/close.
POST /v1/tasks GET /v1/tasks?externalRef=alarm-98765 POST /v1/tasks/{id}/close
Give each system its own key, running as its own API user, and lock the key to the category it reports.
Checklist Reporting
Pull completed checklists each day or week for audits and scorecards. Use the results endpoint for one row per answer.
GET /v1/checklists?dateField=completed&from=2026-04-07&to=2026-04-14&pageSize=250 GET /v1/checklists/results?from=2026-04-07&to=2026-04-14&pageSize=250
Asset Inventory Snapshot
Pull your full asset list weekly or monthly for inventory reconciliation or insurance reporting.
GET /v1/assets?pageSize=250&page=1 GET /v1/assets?pageSize=250&page=2
Page through results until hasNextPage is false.
Inventory Reorder Check
Pull stock items that have reached their reorder point to drive purchasing, or take a full stock snapshot for reconciliation. Each item includes its quantity on hand, min/max, unit cost, and an isMaster flag that distinguishes company-wide items from single-department stock.
GET /v1/inventory?stockState=toOrder&pageSize=250 GET /v1/inventory?pageSize=250&page=1
Invoice Reconciliation
Pull invoices by date range or status to match against your accounts payable. Use the detail endpoint to get line items for each invoice.
GET /v1/invoices?status=Sent&from=2026-04-01&to=2026-04-14 GET /v1/invoices/12345
Tips
- Start with the Swagger docs. Test your queries interactively before writing code.
- Page through large result sets. Always check
hasNextPageand incrementpageuntil it's false. - Use date filters on the task log and checklists.
fromandtoare required and keep queries fast. The maximum range is 90 days. - Cache where possible. Asset, inventory, invoice and lookup data changes infrequently. Daily or weekly pulls are usually enough.
- Test writes on a test location first. Creating and updating tasks sends real notifications.
- Use one key per system. That way each integration's tasks are easy to identify, and a key can be revoked without affecting the others.
Rate Limiting
API requests are limited to 60 requests per minute per API key. If you exceed this limit, you'll receive a 429 response:
{ "error": "Rate limit exceeded. Slow down and retry.", "statusCode": 429, "retryAfterSeconds": 60 }
The response also carries a Retry-After header. Wait that long before retrying.
Error Responses
All errors return a consistent JSON format:
| Status Code | Meaning |
|---|---|
| 400 | Bad request: check your parameters. Also returned when a name (location, category, person, vendor) matches nothing |
| 401 | Missing or invalid API key |
| 403 | The key is read-only and the request is a write |
| 404 | Resource not found or not accessible to your account |
| 409 | Conflict: a name matches more than one record (candidates are listed), the externalRef belongs to a closed task, the task is already closed, or an identical task was just created |
| 429 | Rate limit exceeded |
| 500 | Server error: include the traceId when contacting support |
Example error response:
{ "error": "An unexpected error occurred. If the problem persists, contact support with the traceId.", "statusCode": 500, "traceId": "abc123-def456" }
Data Scoping
All data returned by the API is automatically scoped to your organization:
- Tasks and checklists are limited to those your key's user can see in OwlOps
- Assets are limited to your company
- Inventory is limited to your company
- Invoices are limited to those billed to departments within your company
- Locations, categories, users and vendors are limited to your company
- API users are not listed by
/v1/usersand can't be assigned tasks
Internal platform data (task lists, request items, system log entries) is automatically excluded.
Need Help?
- API documentation:
https://api-owlops-public-bugrb4gxeqcghqh5.eastus2-01.azurewebsites.net/swagger - Support: support@owlops.com