Advanced / at-your-own-risk. Everything on this page sits below the Addigy UI: a direct agent command, the public API, and the agent's local state database. These are powerful for testing and troubleshooting, but they are not a substitute for policy configuration. Internal paths, table names, and command syntax can change between agent versions without notice. Test on a non-production device first.
Who this is for
This page is for admins who are already comfortable with Prebuilt Apps in the Addigy UI and want to go further — installing a specific version on demand, working with Prebuilt Apps programmatically, and reading exactly what the agent thinks is happening on a device in real time.
If you are new to Prebuilt Apps, start with the standard documentation instead:
1. Ad hoc one-off install from the command line
The Addigy agent binary at /Library/Addigy/go-agent exposes a policier subcommand that can install a specific Prebuilt App version immediately, without waiting for a policy run and without adding the app to a policy.
sudo /Library/Addigy/go-agent policier install prebuilt-app-adhoc%24VERSION_ID
Where VERSION_ID is the version ID of the specific Prebuilt App version you want installed. You can get that ID from the Catalog in the Addigy UI by going to the App > App Details, or pull it programmatically using the API.
What it does and does not do
| Behavior | Detail |
| Installs immediately | Runs on demand rather than on the next policy check-in. |
| Installs one exact version | You pin the version by ID — there is no "latest" keyword. |
| Does not change policy | The app is not added to any policy, and no ongoing enforcement, update schedule, or deployment schedule is created. |
| Not a deployment mechanism | For anything that needs to stay installed, stay updated, or apply to more than a handful of devices, configure it in Policy > Software. |
Good use cases
Validating a specific app version on a test Mac before scoping it to a policy.
Getting a single device unstuck without touching policy configuration for the whole group.
An on-demand install triggered from your own tooling or a support workflow.
2. Prebuilt Apps is available in the API
Prebuilt Apps has public endpoints in the Addigy API v2. Anything you can do with Prebuilt Apps in the Catalog and in Policy has an API equivalent — which means you can script it, schedule it, or drive it from your own tooling instead of clicking through the UI one policy at a time.
Find the endpoints here: https://api.addigy.com/api/v2/documentation/,
Why you would reach for the API
| Goal | What the API Gets you |
| Reporting and auditing | Pull which Prebuilt Apps are configured across all of your policies in one pass, instead of opening each policy to check. Feed it into your own reporting, a client-facing report, or a spreadsheet. |
| Bulk and repeatable setup | Apply the same set of Prebuilt App configurations across many policies, or stamp out a standard software build for every new client or site, without doing it by hand each time. |
| Version pinning | Look up the exact version ID for an app in the catalog — which is what the ad hoc install command in section 1 takes, so you can resolve the ID at runtime rather than hardcoding one that goes stale. |
| Drift detection | Run a scheduled job that compares what is actually configured against what you expect, and alerts you when they diverge. |
| Integration with your own stack | Trigger Prebuilt Apps work from your PSA, RMM, ticketing system, or automation platform as part of a larger workflow — onboarding, offboarding, a security remediation. |
What you can fetch and change
The Prebuilt Apps endpoints fall into three groups:
The app catalog — search the Prebuilt App library by name and read back details for a given app. This is how you find out what is available to deploy.
App versions — list the individual versions of an app and look up a specific version by ID. This is where version IDs come from, and how you confirm what a version ID actually points to before you act on it.
Policy configurations — read the Prebuilt App configurations attached to your policies, and create, update, or remove them. This is the group to use for real deployment automation, as opposed to the one-off install in section 1.
Some of these endpoints write. The policy configuration endpoints include update and delete operations that change live policy and will affect every device in scope. Scope your API token to read-only unless you specifically intend to write, and test writes against a policy with no production devices in it. Treat your API token like a password and give the token only the permissions it needs to accomplish your end goal.
Practical Notes
Rate limits: 1,000 requests per 10 seconds across the API. Exceeding it blocks further requests for 24 hours — so build in backoff rather than hammering endpoints in a loop.
Pagination: list endpoints return paged results via
pageandper_page, with ametadatablock in the response you can use to iterate to the end.Token hygiene: never hardcode a token in a script you share or commit. Source it from an environment variable or your secrets manager. A leaked token carries whatever permissions you granted it.
Confirm before you act: when a script resolves an ID automatically, print it and sanity-check it once before wiring it into anything that installs or modifies configuration.
Full detail on authentication, rate limiting, pagination, and error codes: API Documentation (v2).
3. Real-time device state: the Prebuilt Apps SQLite database
The Addigy Agent maintains a local SQLite database of Prebuilt Apps state on each Mac. Reading it directly is the fastest way to see what the real time state of the device is in regards to Prebuilt apps — which apps it is tracking, their status, enforcement dates, and what the end user was prompted with and how they responded.
/Library/Addigy/ansible/prebuilt-apps/state.db
Read only. Never write to, delete, or otherwise modify state.db. It is agent-owned. Writing to it can desync the device from Addigy in ways that are difficult to diagnose. Query it, do not edit it.
Tables
prebuilt_apps — one row per Prebuilt App the agent is tracking on this device.
| Column | What it tells you |
| app_id | Identifier for the app. |
| provider | Source of the app entry. |
| config_id | The configuration this row came from — useful for tracing a row back to a policy configuration. |
| app_name | Human-readable app name. |
| version | Version the agent is tracking. |
| status | Current state of the app on the device — the first column to look at when something has not installed. |
| enforcement_date | Unix epoch. When enforcement kicks in. |
| updated_at | Unix epoch. Last time the agent touched this row. |
prompt_log — history of end-user prompts and their outcomes. This is where you go when a user says "I was never asked" or "I clicked defer and nothing happened.
| Column | What it tells you |
| id | Row identifier. |
| config_id | Configuration the prompt originated from. |
| app_id | App the prompt was for. Not human-readable — join to prebuilt_apps to get the name. |
| outcome | What the user did with the prompt. |
| prompted_at | Unix epoch. When the user was prompted. |
datetime(updated_at, 'unixepoch', 'localtime').
Install Status Values
As an app moves through its lifecycle, each stage writes its status to the app's row in prebuilt_apps. Reading that column tells you exactly where a device got to — and where it stopped. There are six possible values today. As Prebuilt Apps matures- this list may expand to include new statuses as warranted.
| Status | Meaning | What it tells you |
| PENDING | An update is known to be available but work has not started yet. A row also returns to PENDING after a user deferral, a skip, or stale-state recovery. |
Normal to see. Because deferrals reset to PENDING, a row sitting here for a long time is usually a user repeatedly deferring — check prompt_log to confirm. |
| DOWNLOADING | The download is in flight. | Transient. If it persists, suspect network, bandwidth, or content-filtering issues on the device. |
| INSTALLING | Download finished; the installer is running. | Transient. Stuck here points at the installer itself rather than at delivery. |
| INSTALLED | The install succeeded. | Terminal, successful. What you want to see. |
| FAILED | The install started but the installer exited non-zero. | Terminal, unsuccessful. The app itself failed to install — this is the one to alert on and investigate. |
| ENFORCED | The enforcement deadline passed, so the app was force-quit and installed via the CloseRunningAppTemplate path. |
Terminal, successful — but it means the deadline was reached rather than the user acting. |
Two practical notes. The values are uppercase — status = 'INSTALLED' will match, 'installed' will not. And INSTALLED and ENFORCED are both success states, so a "what is broken" query should exclude both rather than just filtering on != 'INSTALLED'.
Useful Queries
See what tables and columns exist. The safest first step on an agent version you have not inspected before.
sudo sqlite3 /Library/Addigy/ansible/prebuilt-apps/state.db ".schema"
Everything the agent is tracking, most recently touched first.
sudo sqlite3 -header -column /Library/Addigy/ansible/prebuilt-apps/state.db \ "SELECT app_name, version, status, datetime(updated_at, 'unixepoch', 'localtime') AS updated FROM prebuilt_apps ORDER BY updated_at DESC;"
State of applications that are not updated the fastest way to spot what has not installed the latest version.
sudo sqlite3 -header -column /Library/Addigy/ansible/prebuilt-apps/state.db \ "SELECT app_name, version, status, config_id FROM prebuilt_apps WHERE status != 'installed';"
Full detail on every tracked app, including enforcement dates.
sudo sqlite3 -header -column /Library/Addigy/ansible/prebuilt-apps/state.db \ "SELECT app_name, version, status, provider, config_id, datetime(enforcement_date, 'unixepoch', 'localtime') AS enforcement, datetime(updated_at, 'unixepoch', 'localtime') AS updated FROM prebuilt_apps ORDER BY updated_at DESC LIMIT 20;"
The last 20 user prompts and what the user did. prompt_log only stores app_id, so this joins to prebuilt_apps to get a readable app name and version alongside the outcome.
sudo sqlite3 -header -column /Library/Addigy/ansible/prebuilt-apps/state.db \ "SELECT a.app_name, a.version, p.outcome, datetime(p.prompted_at, 'unixepoch', 'localtime') AS prompted, p.app_id FROM prompt_log p LEFT JOIN prebuilt_apps a ON a.app_id = p.app_id AND a.config_id = p.config_id ORDER BY p.prompted_at DESC LIMIT 20;"
Prompt history for a single app by name, when you are chasing one specific complaint.
sudo sqlite3 -header -column /Library/Addigy/ansible/prebuilt-apps/state.db \ "SELECT a.app_name, p.outcome, datetime(p.prompted_at, 'unixepoch', 'localtime') AS prompted FROM prompt_log p JOIN prebuilt_apps a ON a.app_id = p.app_id AND a.config_id = p.config_id WHERE a.app_name LIKE '%1Password%' ORDER BY p.prompted_at DESC;"