Authentication
All API requests must include your API key in the X-Api-Key request header. You can find your API key in the web console under Settings → API Keys.
curl https://api.portguard.tech/devices \ -H "X-Api-Key: pg_live_xxxxxxxxxxxxxxxxxxxxxxxx"
Keep your API key secret. Do not commit it to source control or expose it in client-side code. Rotate compromised keys immediately from the console.
Rate Limiting
The API allows 100 requests per minute per API key. If you exceed this limit, the API returns a 429 Too Many Requests response.
Rate limit headers are included in every response:
X-RateLimit-Limit— maximum requests per minuteX-RateLimit-Remaining— requests remaining in the current windowX-RateLimit-Reset— Unix timestamp when the window resets
Enterprise plan customers can request higher rate limits. Contact support@portguard.tech.
Errors
All errors return a JSON body with a code and human-readable message field. HTTP status codes follow standard conventions.
{
"code": "device_not_found",
"message": "No device with that ID exists in your account."
}
| Status | Code | Description |
|---|---|---|
| 200 | — |
Request succeeded |
| 400 | invalid_request |
Missing or malformed request parameters |
| 401 | unauthorized |
Missing or invalid X-Api-Key header |
| 403 | forbidden |
API key does not have permission for this action |
| 404 | not_found |
Requested resource does not exist |
| 429 | rate_limited |
Rate limit exceeded — retry after X-RateLimit-Reset |
| 500 | internal_error |
Unexpected server error — contact support if persists |
Devices
A device represents a USB storage device that has been detected by at least one PortGuard agent. Devices are identified by their hardware serial number.
Returns a paginated list of all USB devices seen across your account, with their current policy status.
| Query Param | Type | Required | Description |
|---|---|---|---|
| status | string | optional | Filter by policy status. One of allow, block, unreviewed |
| machine_id | string | optional | Filter to devices seen on a specific machine |
| limit | integer | optional | Max results to return. Default 50, max 200 |
| cursor | string | optional | Pagination cursor from previous response next_cursor |
{
"devices": [
{
"id": "dev_01HX...",
"serial": "0781534E4A1234AB",
"vendor": "SanDisk",
"product": "Ultra USB 3.0",
"vid": "0781",
"pid": "5567",
"policy": "allow",
"first_seen": "2026-03-15T09:22:00Z",
"last_seen": "2026-03-31T08:01:44Z"
}
],
"total": 42,
"next_cursor": "eyJpZCI6ImRldl8w..."
}
Returns full details for a single device including policy history and the list of machines it has been seen on.
{
"id": "dev_01HX...",
"serial": "0781534E4A1234AB",
"vendor": "SanDisk",
"product": "Ultra USB 3.0",
"vid": "0781",
"pid": "5567",
"policy": "allow",
"first_seen": "2026-03-15T09:22:00Z",
"last_seen": "2026-03-31T08:01:44Z",
"machines": [
{ "machine_id": "mch_01HY...", "hostname": "DESKTOP-7XK2" }
]
}
Device Policy
Allow or block a specific USB device across all machines in your account. The policy is pushed to all online agents within seconds over MQTT.
| Body Field | Type | Required | Description |
|---|---|---|---|
| action | string | required | One of "allow" or "block" |
| machine_id | string | optional | Scope policy to a specific machine. Omit to apply account-wide |
{
"action": "block"
}
{
"id": "dev_01HX...",
"policy": "block",
"updated": "2026-03-31T10:15:30Z"
}
Machines
A machine is a Windows endpoint with the PortGuard agent installed. Machines are identified by a unique ID generated at agent registration time.
Returns all machines registered to your account with their current status and enforcement state.
| Query Param | Type | Required | Description |
|---|---|---|---|
| online | boolean | optional | Filter to true (connected) or false (offline) machines |
| enforcement | boolean | optional | Filter by enforcement enabled/disabled |
{
"machines": [
{
"id": "mch_01HY...",
"hostname": "DESKTOP-7XK2",
"os": "Windows 11 Pro 23H2",
"online": true,
"enforcement": true,
"agent_version":"1.0.0",
"registered_at":"2026-03-10T14:05:00Z",
"last_seen": "2026-03-31T10:12:00Z"
}
],
"total": 12
}
Returns full details for a single machine including device count, enforcement status, and recent event summary.
{
"id": "mch_01HY...",
"hostname": "DESKTOP-7XK2",
"os": "Windows 11 Pro 23H2",
"online": true,
"enforcement": true,
"default_stance": "block",
"agent_version": "1.0.0",
"device_count": 3,
"registered_at": "2026-03-10T14:05:00Z",
"last_seen": "2026-03-31T10:12:00Z"
}
Enforcement
Enable or disable real-time USB enforcement on a specific machine. When disabled, the agent logs events but does not block devices.
| Body Field | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | required | true to enable enforcement, false to disable |
{
"enabled": true
}
{
"machine_id": "mch_01HY...",
"enforcement": true,
"updated": "2026-03-31T10:17:00Z"
}
Events
Events are immutable log entries created whenever a USB device is inserted, removed, allowed, or blocked. The event log is append-only and retained for 90 days on Starter, 1 year on Pro/Enterprise.
Returns a paginated, reverse-chronological list of USB events across your account.
| Query Param | Type | Required | Description |
|---|---|---|---|
| machine_id | string | optional | Filter events to a specific machine |
| device_id | string | optional | Filter events for a specific device |
| type | string | optional | Filter by event type: connect, disconnect, blocked, allowed |
| since | string | optional | ISO 8601 datetime — return events after this time |
| until | string | optional | ISO 8601 datetime — return events before this time |
| limit | integer | optional | Max results. Default 100, max 500 |
{
"events": [
{
"id": "evt_01HZ...",
"type": "blocked",
"machine_id": "mch_01HY...",
"hostname": "DESKTOP-7XK2",
"device_id": "dev_01HX...",
"serial": "0781534E4A1234AB",
"vendor": "SanDisk",
"product": "Ultra USB 3.0",
"username": "jsmith",
"timestamp": "2026-03-31T09:47:12Z"
}
],
"total": 1458,
"next_cursor": "eyJpZCI6ImV2dF8w..."
}
Webhooks
PortGuard can send HTTP POST requests to your endpoint when events occur. Webhook payloads are signed with HMAC-SHA256 using your webhook secret, delivered in the X-PortGuard-Signature header.
Register a URL to receive real-time event notifications. Webhooks are retried up to 3 times with exponential back-off on non-2xx responses.
| Body Field | Type | Required | Description |
|---|---|---|---|
| url | string | required | HTTPS URL to deliver webhook payloads to |
| events | array | required | Event types to subscribe to: ["blocked","connect","disconnect","allowed"] |
| description | string | optional | Human-readable label for this webhook |
{
"url": "https://your-app.example.com/portguard-hook",
"events": ["blocked"],
"description": "SIEM integration"
}
{
"id": "whk_01HA...",
"url": "https://your-app.example.com/portguard-hook",
"events": ["blocked"],
"secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxx",
"created_at": "2026-03-31T10:20:00Z"
}
Save the secret. The webhook secret is only returned once at creation time. Use it to verify X-PortGuard-Signature on incoming payloads.
Webhook Payload
All webhook deliveries share the same envelope format regardless of event type.
{
"webhook_id": "whk_01HA...",
"event_id": "evt_01HZ...",
"type": "blocked",
"created_at": "2026-03-31T09:47:12Z",
"data": {
"machine_id": "mch_01HY...",
"hostname": "DESKTOP-7XK2",
"device_id": "dev_01HX...",
"serial": "0781534E4A1234AB",
"vendor": "SanDisk",
"product": "Ultra USB 3.0",
"username": "jsmith"
}
}