ThreatLocker Portal API fundamentals: raw-key authentication (no Bearer prefix), multi-tenant routing via the organizationId header, POST-based "GetByParameters" list endpoints, pagination shape, and child-organization fan-out patterns.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add WYRE-AI/msp-claude-plugins --skill api-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Api Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/wyre-ai-api-patterns-26f5c319)More formats (shields.io, HTML) on the badges page.
---
name: "ThreatLocker API Patterns"
description: >
ThreatLocker Portal API fundamentals: raw-key authentication (no Bearer prefix),
multi-tenant routing via the organizationId header, POST-based "GetByParameters" list
endpoints, pagination shape, and child-organization fan-out patterns.
when_to_use: >-
When working with ThreatLocker auth headers, multi-tenant requests, POST-based list
endpoints, pagination, or fanning queries across child organizations. Use when:
threatlocker api, threatlocker authentication, threatlocker pagination, threatlocker
organizationid, threatlocker mcp, threatlocker tools, threatlocker child
organizations, threatlocker getbyparameters, or threatlocker portalapi.
---
# ThreatLocker MCP Tools & API Patterns
## Overview
The ThreatLocker MCP server wraps the ThreatLocker Portal API
(`https://portalapi.g.threatlocker.com/portalapi`) and exposes tools
across computers, computer groups, approval requests, audit log
("Action Log" in the UI), and organizations. The API has two quirks
that surprise people: the auth header does NOT use `Bearer`, and most
"list" endpoints are POSTs against `/Entity/EntityGetByParameters` with
a structured body — not GETs with query strings.
## Anti-triggers
- **Enumerating or pivoting between tenants.** This skill explains the
`organizationId` header and the `childOrganizations` flag; the tools
that actually list children, fetch auth keys, and resolve move targets
are `threatlocker-organizations`.
- **Reading or storing an organization's auth key.** The header mechanics
are here, but the tool that returns a live credential is in
`threatlocker-organizations` — treat its output as a secret.
## Connection & Authentication
### Raw API Key Header
ThreatLocker authenticates with a raw API key — no `Bearer` prefix:
| Header | Value |
|--------|-------|
| `Authorization` | `<apiKey>` (raw, no prefix) |
| `ManagedClientId` | (optional) for legacy partner setups |
| `organizationId` | (optional) tenant to scope this call to |
> **Common mistake:** Sending `Authorization: Bearer <key>` returns
> 401. Send the key bare.
### Environment Variables
```bash
export THREATLOCKER_API_KEY="your-raw-api-key"
export THREATLOCKER_BASE_URL="https://portalapi.g.threatlocker.com/portalapi"
```
## Multi-Tenant Routing
ThreatLocker is built for MSPs and uses organizations as the tenant
boundary. Three patterns:
1. **Default org** — Omit the `organizationId` header. The API uses
the API key's primary organization.
2. **Specific child org** — Set `organizationId` to a child org ID to
scope a single call to that tenant.
3. **Fleet-wide fan-out** — Set the body flag `childOrganizations: true`
on `*GetByParameters` endpoints to roll up data across all child
organizations the API key can see.
For tenant pivots, see the `organizations` skill.
## Available MCP Tools
### Computers
| Tool | Description |
|------|-------------|
| `threatlocker_computers_list` | List computers with pagination/filters |
| `threatlocker_computers_get` | Get full details for one computer |
| `threatlocker_computers_get_checkins` | Recent check-in history |
### Computer Groups
| Tool | Description |
|------|-------------|
| `threatlocker_computer_groups_list` | Full group list with metadata |
| `threatlocker_computer_groups_dropdown` | Slim list for selection UIs |
### Approval Requests
| Tool | Description |
|------|-------------|
| `threatlocker_approvals_list` | List approval requests |
| `threatlocker_approvals_get` | Single approval with full context |
| `threatlocker_approvals_pending_count` | Quick pending-queue size |
| `threatlocker_approvals_get_permit_application` | Application that would be permitted |
### Audit Log (Action Log)
| Tool | Description |
|------|-------------|
| `threatlocker_audit_search` | Search Action Log by time/host/file |
| `threatlocker_audit_get` | Full record for one action |
| `threatlocker_audit_file_history` | All actions for a given file path/hash |
### Organizations
| Tool | Description |
|------|-------------|
| `threatlocker_organizations_list_children` | All child orgs visible to the key |
| `threatlocker_organizations_get_auth_key` | Auth key for a specific org |
| `threatlocker_organizations_for_move_computers` | Orgs eligible as move targets |
## POST-Based "GetByParameters" Pattern
Most list endpoints are `POST /Entity/EntityGetByParameters` with a
JSON body. Request shape:
```json
{
"pageNumber": 1,
"pageSize": 50,
"isAscending": false,
"orderBy": "lastCheckin",
"searchText": "",
"childOrganizations": false
}
```
Response shape:
```json
{
"totalItems": 1284,
"items": [ /* array of entities */ ]
}
```
### Pagination
ThreatLocker uses page numbers, not cursors:
1. Call with `pageNumber: 1`, `pageSize: 50` (or 100/200).
2. Compute `totalPages = ceil(totalItems / pageSize)`.
3. Continue until you have collected `totalItems` rows or reached
the last page.
Avoid huge `pageSize` values — large pages can time out. 50–200 is the
sweet spot.
### Sort and Search
- `orderBy` is an entity-specific column name (e.g. `lastCheckin`,
`computerName`).
- `isAscending` toggles direction.
- `searchText` is a substring match across the entity's searchable
columns (computer name, hostname, OS, etc.).
## Error Handling
| Code | Meaning | Fix |
|------|---------|-----|
| 401 | Bad API key OR `Bearer` prefix included | Send raw key |
| 403 | Key valid, but no access to requested org | Check `organizationId` |
| 404 | Wrong endpoint or unknown entity ID | Recheck path |
| 429 | Rate limited | Backoff and retry |
| 500 | Portal API hiccup | Retry, then escalate |
## Best Practices
- Default to `pageSize: 100` and paginate; always check `totalItems`
before assuming you have the full set.
- For multi-tenant reports, fan out with `childOrganizations: true`
rather than looping per-org when the entity supports it.
- Cache the result of `threatlocker_organizations_list_children` —
child org lists rarely change within a session.
- Always pass `organizationId` explicitly when generating client-facing
reports so the source tenant is unambiguous.
## Related Skills
- [computers](../computers/SKILL.md) — Endpoint inventory
- [computer-groups](../computer-groups/SKILL.md) — Policy scoping
- [approval-requests](../approval-requests/SKILL.md) — Application approvals
- [audit-log](../audit-log/SKILL.md) — Action Log investigation
- [organizations](../organizations/SKILL.md) — Multi-tenant pivots
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!