Guides
Conventions & versioning
The rules every endpoint follows, and what may change within v1.
Versioning and compatibility
The version is part of the path: /v1/…. Within v1, we make only additive changes:
- New endpoints
- New fields in responses
- New error codes
- New scopes
A new scope never changes what an existing key can do. Existing keys don’t receive it, so to call an endpoint that needs a new scope, create a key that has it. See Changing a key’s scopes.
Build your client to ignore fields it doesn’t recognize, and to handle unknown error codes by their HTTP status. Breaking changes, such as removing or renaming a field or changing its type or meaning, ship as a new version (/v2). We announce changes in the changelog.
Requests
- All requests use HTTPS. v1 endpoints are read-only
GETrequests without a body. - Responses are JSON. Send
Accept: application/jsonor omit the header. AnAcceptheader that excludes JSON fails with 406 not_acceptable. - Other methods fail with 405 method_not_allowed, and unknown paths with 404 route_not_found. Paths are matched after percent-decoding.
- Ids in paths and filters, such as
policyId, are case-insensitive. Responses always use lowercase. The values of theplatformandtypefilters are case-insensitive too, and theappsfilter ignores the case of ASCII letters. Theroleandactorfilters are exceptions. Send roles in lowercase, because any other case fails with 400 invalid_parameter. Send emails exactly as recorded, becauseactoris case-sensitive. - The time filters
sinceanduntilare ISO-8601 timestamps with a UTC offset.sinceis inclusive anduntilis exclusive. See Time ranges. - On per-day lists, such as screen time and app usage,
sinceanduntilare UTC calendar dates in the formYYYY-MM-DD, and both are inclusive. See Date ranges.
Strict query parameters
The API validates query parameters strictly, so a mistake returns an error instead of quietly returning unfiltered data. An unsupported parameter fails with 400 unknown_parameter. A parameter sent twice, or with an invalid value, fails with 400 invalid_parameter.
curl "https://api-gw.weguard.ai/core/v1/devices?platfrom=ios" \
-H "Authorization: Bearer $WEGUARD_API_KEY"{
"type": "https://weguard.ai/docs/errors#unknown_parameter",
"title": "Unknown parameter",
"status": 400,
"code": "unknown_parameter",
"detail": "Unknown query parameter 'platfrom'. Allowed: platform, policyId, limit, cursor, includeTotal.",
"instance": "/core/v1/devices",
"requestId": "req_k3j2h1g0f9e8d7c6b5a4z3y2",
"errors": [
{
"field": "platfrom",
"code": "unknown_parameter",
"message": "Unknown query parameter 'platfrom'. Allowed: platform, policyId, limit, cursor, includeTotal."
}
]
}Boolean parameters accept only true or false, in lowercase.
Response formats
- JSON, UTF-8, with
camelCasefield names. - Timestamps are ISO-8601 in UTC, for example
2026-10-07T09:30:00Z. Calendar days, such asdateon per-day resources, are UTC dates, for example2026-10-07. - Ids are 24-character lowercase hexadecimal strings, for example
6523f1c2a7b9d40012345678. Treat them as opaque: store them as strings and don’t derive meaning from them. - Unknown values are
null, not omitted. Every documented field is present in every response, unless its description says otherwise (for example,totalCount). - Errors use RFC 9457 problem details. See Errors.
The object field
Every resource has an object field naming its type, so you can tell payloads apart without knowing which endpoint they came from:
| object | Described in |
|---|---|
me | The me object |
account | The account object |
device | The device object |
device_status | The device status object |
device_location | The device location object |
installed_app | The installed app object |
location_point | The location point object |
screen_time_day | The screen time day object |
app_usage_day | The app usage day object |
policy | The policy object |
user | The user object |
audit_log | The audit log object |
list | The list object |
Platforms
Devices and policies have a platform. The platform filter takes the same values:
| platform | Devices |
|---|---|
android | Android phones, tablets and dedicated devices |
ios | iPhone, iPad and iPod touch |
macos | Macs |
tvos | Apple TV |
windows | Windows PCs |
Request ids
Every response has an X-Request-Id header, and every error body repeats it as requestId. You can send your own X-Request-Id to correlate our logs with yours. It must be 8 to 128 characters long and use only ASCII letters, digits and . _ : -. WeGuard echoes a valid value back. If you don’t send one, WeGuard generates one that starts with req_. A value that doesn’t match the format is replaced with a generated id.
curl -i https://api-gw.weguard.ai/core/v1/me \
-H "Authorization: Bearer $WEGUARD_API_KEY" \
-H "X-Request-Id: cmdb-sync-2026-10-07-0001"Conditional requests (ETags)
Successful GET responses include an ETag header. Send it back in If-None-Match. If the response would be identical, you get 304 Not Modified with an empty body and can reuse your cached copy. Responses carry Cache-Control: private, no-cache. Your client can store them but must revalidate them before reuse, and shared caches must not store them.
curl -i https://api-gw.weguard.ai/core/v1/policies/64ff0a1b2c3d4e5f60718293 \
-H "Authorization: Bearer $WEGUARD_API_KEY" \
-H 'If-None-Match: "0d41d8cd98f00b204e9800998ecf8427e"'HTTP/1.1 304 Not Modified
ETag: "0d41d8cd98f00b204e9800998ecf8427e"
Cache-Control: private, no-cache
X-Request-Id: req_k3j2h1g0f9e8d7c6b5a4z3y2
RateLimit-Limit: 600
RateLimit-Remaining: 586
RateLimit-Reset: 2A 304 saves bandwidth and parsing, but still counts toward your rate limit.