Scoutmon REST API

The Scoutmon API lets you read and manage your IT assets, users, vendors, and locations programmatically. All endpoints are scoped to your company — you can only access data that belongs to your account.

ℹ
Base URL: https://scoutmon.com/api  ·  versioned alias https://scoutmon.com/api/v1

All requests and responses use JSON. Timestamps are ISO 8601 in UTC. UUIDs are used for all resource identifiers.

⚡
Interactive reference & OpenAPI spec. Explore every endpoint at /api-reference, or import the machine-readable spec into Postman/Insomnia: https://scoutmon.com/api/openapi.json. It covers asset lookup by tag/serial, checkout/checkin, and outbound webhooks.

Authentication

The API uses Bearer token authentication via API keys. Generate an API key from your Settings → API Keys page.

Pass your key in the Authorization header on every request:

# Replace sk_... with your actual API key
curl https://scoutmon.com/api/assets \
  -H "Authorization: Bearer sk_your_api_key_here"

API Key format

Keys follow the format sk_ followed by 56 hex characters. The first 10 characters form the key prefix used for rate limiting.

⚠
API keys are shown once at creation and cannot be retrieved again. Store them securely (environment variables, secrets manager). Never commit keys to source control.

Scopes

Each API key has one or more scopes. Request the minimum scope needed for your integration.

ScopeDescription
readRead-only access to all resources in your company
writeCreate, update, and delete resources (includes read)

What API keys can't do

Keys are for working with your asset data. Anything that changes who can get into your account needs a person signed in to Scoutmon, so these return 403 with "code": "api_key_not_allowed" even for a write key:

  • inviting, changing or removing users, and changing permissions
  • creating or revoking API keys
  • creating, changing or deleting webhooks (listing them is fine)
  • changing company settings

Expiry

When you create a key you choose when it expires: 30, 90, 180 or 365 days, or never. An expired key, or a key whose creator has been deactivated, returns 401.

Rate Limits

Rate limits are applied per API key. If you exceed a limit, requests return 429 Too Many Requests.

60
requests per minute (burst)
1,000
requests per hour

After the limit resets, requests proceed normally. For bulk operations, use the limit and offset query parameters to page through results rather than fetching everything repeatedly.

Errors

The API returns standard HTTP status codes. Error responses include a JSON body with an error field describing what went wrong.

StatusMeaning
200Success
201Resource created
400Bad request — check request body / query params
401Unauthorized — missing or invalid API key
402Subscription lapsed — the account is read-only. GET requests still work; writes return "code": "subscription_required"
403Forbidden — insufficient scope, a read-only key, or an action API keys can't perform
404Resource not found, or no such endpoint (always JSON)
409Conflict — e.g. duplicate email
429Rate limit exceeded
500Server error
Error response
{
  "error": "Asset not found"
}

Pagination & Filtering

All list endpoints support limit and offset for pagination, plus endpoint-specific filter parameters. The total count of matching records is returned in the X-Total-Count response header.

Common query parameters

ParameterTypeDefaultDescription
limitinteger500Records per page. Max 1000.
offsetinteger0Number of records to skip.
searchstring—Text search across name and other key fields (endpoint-specific).

Example — paginate through assets

# Page 1
curl "https://scoutmon.com/api/assets?limit=50&offset=0" \
  -H "Authorization: Bearer sk_..."

# Page 2
curl "https://scoutmon.com/api/assets?limit=50&offset=50" \
  -H "Authorization: Bearer sk_..."

The X-Total-Count header tells you how many records match the current filter, so you can compute the number of pages as Math.ceil(total / limit).

Assets

GET /api/assets read

Returns a list of assets for your company, including joined location, vendor, owner, and classification names.

Query parameters

ParameterTypeDescription
searchstringFilter by name, asset tag, or serial number (case-insensitive).
statusstringFilter by status: active, checked-out, checked-in, retired, etc.
categorystringFilter by category (exact match). E.g. Laptop, SaaS.
location_iduuidFilter by location.
owner_iduuidFilter by owner (user).
assigned_user_iduuidFilter by the user an asset is checked out to.
classification_iduuidFilter by data classification.
sort_bystringname | created_at | status | category | value | asset_tag. Default: created_at.
sort_dirstringasc or desc. Default: desc.
limitintegerDefault 500, max 1000.
offsetintegerDefault 0.
Request
curl "https://scoutmon.com/api/assets?status=checked-out&sort_by=name&sort_dir=asc&limit=25" \
  -H "Authorization: Bearer sk_..."
Response (200)
[
  {
    "id": "a1b2c3d4-...",
    "asset_tag": "IT-0042",
    "name": "MacBook Pro 16\"",
    "category": "Laptop",
    "status": "checked-out",
    "value": "2499.00",
    "location_name": "Sydney HQ",
    "vendor_name": "Apple Inc.",
    "assigned_user_name": "Alice Smith",
    "created_at": "2025-11-01T09:00:00.000Z"
  }
]

The response header X-Total-Count contains the total number of matching assets (before pagination).

GET /api/assets/:id read

Returns a single asset by ID. Use GET /api/assets/:id/decrypt (admin-only) to retrieve encrypted serial/notes fields.

Request
curl https://scoutmon.com/api/assets/a1b2c3d4-... \
  -H "Authorization: Bearer sk_..."
GET /api/assets/by-tag/:tag  ·  /api/assets/by-serial/:serial read

Finds a single asset by its asset tag or serial number: the lookup you want when scanning a label. Returns the same shape as GET /api/assets/:id, or 404 if nothing in your company matches.

Request
curl https://scoutmon.com/api/assets/by-tag/SM-0042 \
  -H "Authorization: Bearer sk_..."

Photos aren't included in single-asset or list responses; has_photo tells you whether one exists.

POST /api/assets write admin

Creates a new asset. If asset_tag is omitted and auto-increment is configured, a tag is generated automatically.

Body parameters

FieldTypeRequiredDescription
namestringrequiredDisplay name for the asset.
categorystringoptionalAsset category (e.g. Laptop, Monitor, SaaS).
statusstringoptionalDefault: active.
asset_tagstringoptionalCustom tag. Auto-generated if omitted.
serial_numberstringoptionalDevice serial number.
valuenumberoptionalPurchase price (numeric).
purchase_datedateoptionalISO 8601 date string (YYYY-MM-DD).
warranty_expirydateoptionalISO 8601 date string (YYYY-MM-DD).
location_iduuidoptionalLocation UUID.
vendor_iduuidoptionalVendor UUID.
assigned_user_iduuidoptionalUser UUID to assign immediately.
manufacturerstringoptionale.g. Apple, Dell.
modelstringoptionalDevice model.
notesstringoptionalFree-text notes.
Request
curl -X POST https://scoutmon.com/api/assets \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "MacBook Pro 16\"",
    "category": "Laptop",
    "manufacturer": "Apple",
    "model": "MacBook Pro 16\" M3",
    "value": 2499,
    "purchase_date": "2025-10-15",
    "warranty_expiry": "2028-10-15"
  }'
PUT /api/assets/:id write admin

Replaces all fields on an asset. Send all fields (including unchanged ones) — this is a full update, not a partial patch. Accepts the same body parameters as POST /api/assets.

DELETE /api/assets/:id write admin

Permanently deletes an asset. This action cannot be undone.

Response (200)
{ "ok": true }
POST /api/assets/:id/checkout write admin

Checks an asset out to a user. Sets status to checked-out and records the assignment.

Body parameters

FieldTypeRequiredDescription
assigned_user_iduuidrequiredUUID of the user to check out to.
expected_returndateoptionalExpected return date (YYYY-MM-DD).
POST /api/assets/:id/checkin write admin

Checks an asset back in. Sets status to checked-in and clears the assigned user.

Users

GET /api/users read

Returns all users in your company. Includes role, status, department, and last login timestamp.

Query parameters

ParameterTypeDescription
searchstringFilter by name or email (case-insensitive).
rolestringuser or admin.
statusstringactive or inactive.
limitintegerDefault 500, max 1000.
offsetintegerDefault 0.
Request
curl "https://scoutmon.com/api/users?role=admin" \
  -H "Authorization: Bearer sk_..."
Response (200)
[
  {
    "id": "u1b2c3d4-...",
    "name": "Alice Smith",
    "email": "[email protected]",
    "role": "admin",
    "status": "active",
    "department": "Engineering",
    "last_login": "2026-03-28T14:22:00.000Z",
    "created_at": "2025-09-01T08:00:00.000Z"
  }
]
GET /api/users/:id/assets read

Returns all hardware assets and license seats currently assigned to a specific user.

Response (200)
{
  "assets": [ /* hardware assets assigned to this user */ ],
  "seats": [ /* software license seats assigned to this user */ ]
}

Vendors

GET /api/vendors read

Returns all vendors for your company with risk rating, compliance status, and contact details.

Query parameters

ParameterTypeDescription
searchstringFilter by vendor name.
categorystringFilter by category (e.g. ICT / Cloud & Hosting).
risk_ratingstringLow, Medium, or High.
limitintegerDefault 500, max 1000.
offsetintegerDefault 0.
POST /api/vendors write admin

Creates a new vendor record.

Body parameters

FieldTypeRequiredDescription
namestringrequiredVendor name.
categorystringoptionalVendor category.
websitestringoptionalVendor website URL.
risk_ratingstringoptionalLow, Medium, or High.
compliance_statusstringoptionalCompliant, Non-Compliant, or Not Reviewed.
primary_contact_namestringoptional
primary_contact_emailstringoptional
notesstringoptionalFree-text notes.
PUT /api/vendors/:id write admin

Full update of a vendor record. Accepts the same fields as POST /api/vendors.

GET /api/vendors/:id/assets read

Returns all active assets associated with a vendor.

Locations

GET /api/locations read

Returns all locations for your company.

Query parameters

ParameterTypeDescription
searchstringFilter by location name.
typestringFilter by type (e.g. Office, Warehouse, Remote).
limitintegerDefault 500, max 1000.
offsetintegerDefault 0.
Response (200)
[
  {
    "id": "loc1b2c3-...",
    "name": "Sydney HQ",
    "type": "Office",
    "address": "123 Pitt St, Sydney NSW 2000",
    "lat": -33.8688,
    "lng": 151.2093
  }
]
POST /api/locations write admin

Creates a new location.

Body parameters

FieldTypeRequiredDescription
namestringrequiredLocation name.
typestringoptionalDefault: Office.
addressstringoptionalStreet address.
latnumberoptionalLatitude (decimal degrees).
lngnumberoptionalLongitude (decimal degrees).

Webhooks

Webhooks send an HTTPS POST to your endpoint when something happens. Set them up in Settings → Webhooks (a signed-in admin is needed; API keys can list them but not change them).

Events

EventWhen
asset.createdAn asset is added
asset.updatedAn asset is changed
asset.checked_outAn asset is checked out to someone
asset.checked_inAn asset is checked back in
warranty.expiringDaily: assets whose warranty ends in the next 30 days
licence.expiringDaily: licences and SaaS reaching end of life in the next 30 days
audit.dueDaily: assets due a physical audit in the next 7 days, or already overdue
Payload
{
  "event": "asset.checked_out",
  "delivered_at": "2026-10-05T03:12:44.120Z",
  "data": { … }
}

Verifying the signature

Each request carries X-Scoutmon-Event and X-Scoutmon-Signature: sha256=<hex>, an HMAC-SHA256 of the raw request body using your webhook's secret (shown once, when you create it). Compute the same HMAC over the exact bytes you received and compare in constant time.

// Node.js
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-scoutmon-signature']));

Delivery

Endpoints must be public https:// addresses; private and internal addresses are refused, and redirects aren't followed. Each event is attempted once, with an 8-second timeout. The last response status is shown against the webhook in Settings, and Send test sends a signed ping. There are no automatic retries yet, so use the daily events or the API to reconcile if your endpoint was down.