API authentication, tokens and scopes
The API authenticates every call with a bearer token you create in the app. A token carries the account it belongs to, the scopes (operations) it may perform, an expiry and, optionally, an IP allow-list. The same token works for raw HTTP calls, the SDKs, ht-cli, the Terraform provider and the MCP server.
Before you start
Section titled “Before you start”Your plan must include API access - the app refuses to create a token otherwise. See which plans include the API. Subaccounts need the API access right.
Token settings
Section titled “Token settings”| Setting (UI label) | Mint field | Allowed values | Default | What it does for you |
|---|---|---|---|---|
| Token name | name |
Free text (placeholder “e.g. CI server”) | Empty | Lets you recognise the token later. |
| Token scopes (allowed operations) | scopes |
Any of the scopes below; at least one | None ticked | What the token may do. A token with no scope is refused. |
| Token expiration | tokenDuration or tokenExpiration |
10 years, 1 day, 7 days, 30 days, 120 days, 1 year, Custom date | 10 years | When the token stops working. |
| Token IP white list (optional) | ipWhiteList |
Up to 10 entries: an address (1.2.3.4) or a range (1.2.3.4-4.3.2.1) |
Empty (any address) | Calls from any other address answer 403 ip_not_allowed. |
Create a token
Section titled “Create a token”- Open Integrations -> API in the app (
/integrations/api). - In New access token, enter a Token name.
- Under Token scopes (allowed operations), tick the scopes the integration needs (each family has All and None shortcuts).
- Choose a Token expiration. Prefer a short one for anything you hand to a person, a CI job or an AI tool.
- Optionally list the addresses allowed to use it in Token IP white list.
- Click Create Access Token and copy the token. It is shown once and is not stored on HostTracker’s side - if you lose it, create another.
Use the token
Section titled “Use the token”Send it on every request:
Authorization: Bearer YOUR_HOSTTRACKER_API_TOKENcurl https://api2.host-tracker.com/account -H "Authorization: Bearer $HT_TOKEN"There is no account id in URLs or bodies - the token says who is calling.
Scopes
Section titled “Scopes”There are 13 leaf scopes, one per action on an area, and 7 family scopes (the bare area name):
| Family | Leaves | Covers |
|---|---|---|
monitor |
monitor:read, monitor:write |
Monitors, results, incidents, uptime summaries, maintenance windows, reports, per-monitor subscriptions |
contact |
contact:read, contact:write |
Contacts, contact groups, confirmations, tests, the notification log, per-contact subscriptions |
subs |
subs:read |
The flat account-wide subscription lists (GET /alert, GET /report) |
webhook |
webhook:read, webhook:write |
Webhooks, their delivery log, tests and redelivery |
statuspage |
statuspage:read, statuspage:write |
Status pages, components, declared incidents, templates, subscribers |
account |
account:read, account:write |
Account details, usage, limits, quota; account:write changes profile, time zone, language and default locations |
check |
check:read, check:write |
Instant checks |
Rules:
- A leaf does not imply its sibling.
monitor:writedoes not grantmonitor:read, and the reverse is also false. An integration that both reads and writes monitors needs both leaves, or the family. - A family covers every leaf in it -
monitorpasses bothmonitor:readandmonitor:write. A family also grows automatically if its area gains a new action later; grant leaves when you want the token pinned to today’s surface. - A write that reaches two areas needs both. Creating a monitor with inline
contactsneedsmonitor:writeandcontact:write; the bulk subscription writes (POST /alert/bulk,POST /report/bulk) need both writes too. - Subscription writes ride their parent:
PUT /monitor/{id}/alert/{contactId}needsmonitor:write, the mirrorPUT /contact/{id}/alert/{monitorId}needscontact:write. - Jobs need the scope of the operation that created them.
- The old spellings
ic,ic:read,ic:writeandsubs:writeno longer exist.
GET /account/quota returns the full scope catalogue with a one-line description of each, and shows which scopes
the calling token carries.
Common scope sets
Section titled “Common scope sets”| Integration | Scopes |
|---|---|
| Status dashboard (read-only) | monitor:read |
| Provisioning script (create monitors, never read them back) | monitor:write |
| Monitors as code (Terraform, CI) | monitor (plus contact, webhook, statuspage for those resources; account:read for the account data source) |
| Deploy smoke test with instant checks | check |
| Alert routing sync | contact, monitor:write, subs:read |
| Status page automation | statuspage |
What a refusal looks like
Section titled “What a refusal looks like”| Status and code | Meaning | Fix |
|---|---|---|
401 invalid_token, reason missing |
No Authorization header. |
Send the header. |
401 invalid_token, reason invalid |
Malformed, tampered or expired token (the two look identical on purpose). | Mint a new token. |
403 missing_scope |
The token is valid but lacks the scope. errors[0] carries required and granted. |
Mint a token with the missing scope - scopes cannot be added to an existing token. |
403 ip_not_allowed |
Called from an address outside the token’s allow-list. errors[0].clientIp shows your address. |
Call from an allowed address or mint a new token. |
403 insufficient_rights |
A subaccount token lacks the subaccount right for this operation. | Ask the account owner to grant the right. |
{ "code": "missing_scope", "status": 403, "errors": [ { "required": "monitor:write", "granted": ["monitor:read"] } ]}Token security
Section titled “Token security”A token is a password for its scopes. It is not stored on HostTracker’s side - the grant lives inside the signed token - so:
- A token cannot be revoked before it expires. Changing your password or signing out everywhere does not stop it. Only an account-wide API disable (a support action) stops every token at once.
- Limit the damage in advance: scope narrowly, set a short expiration, use the IP allow-list for anything that runs from a fixed address, and use one token per integration.
- A token with a past
tokenExpirationis refused at creation. - If a token leaks, remove it everywhere, mint a replacement and contact [email protected]. Never send the token itself.
The minting endpoint also accepts a self-cap (the most calls this one token may spend from the account’s quota); the form does not have a field for it yet.
Connected apps (OAuth)
Section titled “Connected apps (OAuth)”Some clients - AI assistants such as Claude and ChatGPT connecting to the MCP server - sign in with OAuth 2.1 instead of a pasted token. You sign in to HostTracker, see a consent card listing the scopes, and approve.
- Access tokens last an hour and are refreshed automatically; refresh tokens rotate on every use.
- A client that asks for no scopes gets
checkandmonitor:read. Theaccountfamily is never granted to a connected app. - Unlike pasted tokens, a connected app can be revoked: Integrations -> API -> Connected apps lists every app with its scopes and connection date; Revoke cuts it off at once (its last access token expires within the hour).

