← Back to Docs
Last updated: 2026-07-05

API Endpoints (Overview)

This page lists available endpoint groups, routing rules, auth model, and practical request examples.

Authentication

  • API access uses API keys generated in Configuration → API Keys (UI).
  • Tokens are shown once; store securely.
  • Header format:
    • Authorization: ApiKey <token> for API key calls
  • API keys sent with Bearer are rejected.

Tenant routing (important)

The backend resolves the tenant/workspace from the request Host header:

  • the tenant is inferred from the subdomain (the first .-separated segment)

Recommended production pattern:

  • https://<tenant-subdomain>.invymate.com/api/v1/...

Local/test hosts depend on your deployment setup, but tenant is always host/subdomain-derived.

The public tenant bootstrap response used by the auth shell includes:

  • exists
  • tenantId
  • ssoProvider
  • ssoConfigured
  • ssoLoginEnabled
  • ssoOnlyEnabled
  • ssoAccess

The sign-in screen always keeps Google login available for non-SSO workspaces, and shows both Google and SSO only when the workspace owner has enabled the SSO-only gate.

ssoProvider reflects the configured workspace SSO protocol, such as oidc for Auth0-style OpenID Connect setups or saml for metadata-driven SAML setups. ssoConfigured means an SSO config record exists. ssoLoginEnabled means the workspace owner has enabled the SSO-only gate, so the login screen should expose SSO.

When ssoOnlyEnabled is true:

  • the password sign-in screen hides the password form by default
  • the dedicated SSO entrypoint is /auth/sso-login, which calls the backend /api/v1/auth/sso-login redirect helper and sends the user to the workspace's configured SSO provider
  • the backend SSO route is feature-gated and returns 403 when the workspace plan does not include SSO
  • workspace owners can still use the password sign-in path as break-glass recovery from the SSO page
  • SSO configuration lives in the dedicated Configuration → SSO node
  • only the owner can open the Configuration area and maintain the SSO draft
  • SSO is available whenever the workspace subscription includes the SSO feature flag
  • the service-provider callback is fixed by the selected protocol:
    • SAML uses /api/v1/auth/saml/callback
    • OIDC uses /api/v1/auth/oidc/callback
  • the callback host must be the tenant subdomain, for example https://<tenant-subdomain>.invymate.com/api/v1/auth/oidc/callback
  • SAML login uses the IdP metadata URL to discover the provider's sign-in endpoint and signing certificate
  • the service-provider metadata is available at /api/v1/auth/saml/metadata for IdP setup

SSO onboarding sequence:

  • the workspace admin first assigns the user to the application or group inside the SSO provider
  • the Invymate owner then invites that same email address in Invymate
  • SSO sign-in matches by email, so the identity provider email must match the invited Invymate user email
  • if the user is still in the invite state and has not been created in users yet, the first OIDC or SAML login consumes the invite and creates the user record
  • after that first login, the user can authenticate through the SSO button on the login page

Tenant SAML config

SSO draft configuration is exposed as a separate tenant subresource.

  • GET /tenants/current/saml-config
  • PATCH /tenants/current/saml-config

Access pattern:

  • owners can read the current draft with GET
  • owners can update the draft with PATCH
  • the owner saves the draft directly from the UI
  • the UI shows help tooltips next to each SSO field so owners can see which IdP value belongs in each input
  • the UI lets owners choose between SAML and OIDC and shows the protocol-specific fields
  • the callback URL shown in the UI is the fixed backend endpoint for the chosen protocol, so copy it into the IdP instead of editing it manually

The request body for PATCH is the selected protocol config itself. You do not include a tenant ID in the body:

  • provider: saml or oidc

SAML fields:

  • entityId: the SAML issuer/entity identifier
  • acsUrl: the assertion consumer service URL. This is the fixed backend callback endpoint and is not tenant-editable.
  • idpMetadataUrl: optional IdP metadata URL
  • idpCertificate: optional IdP certificate text
  • ssoOnlyEnabled: optional toggle for SSO-only access, editable by workspace owners in Configuration → SSO
  • ssoAccess: true when the workspace plan includes SSO
  • ssoLoginEnabled: true when the workspace owner has enabled the SSO-only gate, so the login screen should expose SSO

OIDC fields:

  • issuerUrl: the OIDC issuer URL
  • discoveryUrl: optional OIDC discovery document URL
  • clientId: the OIDC client ID
  • clientSecret: the OIDC client secret
  • redirectUri: the fixed backend callback endpoint for OIDC
  • scopes: optional space-separated scopes, defaulting to openid profile email
  • ssoOnlyEnabled: optional toggle for SSO-only access, editable by workspace owners in Configuration → SSO

Validation rules:

  • provider is required
  • entityId and acsUrl are required for SAML
  • at least one of idpMetadataUrl or idpCertificate must be present
  • acsUrl and idpMetadataUrl must be valid URLs when present
  • issuerUrl, discoveryUrl, and redirectUri must be valid URLs when present
  • clientId and clientSecret are required for OIDC

Response fields include the current workspace SSO draft used by the UI.

Common patterns

  • Pagination/filtering/sorting vary by endpoint; see per-endpoint sections below.
  • Standard error responses include message and optional details.
  • Webhook management routes are JWT-only even when API Access is enabled.
  • Internally, asset command endpoints are routed through an inventory-item facade so create/update/checkout/check-in/status/image workflows share one application entry point.
  • Architecture note: inventory item keeps its public domain barrel focused on facade/controllers/validation/types. Asset list filtering, detail, assignment history, audit, status-event, timeline, health, import fields, quick-add logging, and bulk import/export scheduling now run through the inventory-item facade, with focused unit coverage for facade orchestration and list filtering/enrichment. Session endpoints now use the same facade boundary for list/get/create/update/export/include/exclude and other controller orchestration, with focused facade coverage for those read-after-write and export paths plus narrow controller coverage around export/include/exclude HTTP responses and error forwarding. Session unscan cleanup, include/exclude membership edits, completion-side scan application, update guards, start-session snapshot setup, and the update workflow itself now live in focused application modules. The public session barrel is narrowed to facade/types while routes import controllers and validation explicitly. Maintenance endpoints now follow the same pattern through a MaintenanceFacade for schedule/log controller orchestration, while createLog branching, deleteLog schedule recalculation/health refresh, deleteSchedule, updateLog, and schedule create/update due-date wiring now live in focused application modules and routes import maintenance controllers and validation explicitly while workers/asset-attention logic use internal reader paths plus a shared due-date helper. Location endpoints now follow the same pattern through a LocationFacade for controller orchestration, with create/update/restore reloads behind the facade, routes importing location controllers and validation explicitly, and tenant/session/trash/worker internals using explicit reader/service paths. Person endpoints now follow the same pattern through a PersonFacade for controller orchestration, with create/update/restore reloads behind the facade, routes importing person controllers and validation explicitly, and auth/tenant/session/search/trash/worker internals using explicit reader/service/type paths. Category endpoints now follow the same pattern through a CategoryFacade for controller orchestration, with create/update/restore reloads behind the facade, routes importing category controllers and validation explicitly, and tenant/trash/worker/inventory internals using explicit service paths. Notification endpoints now keep the same boundary with a NotificationFacade, an index narrowed to facade/types, explicit route imports for controllers and validation, focused facade coverage around read/write delegation, a small application helper for non-failing realtime event emission, and owner-targeted realtime events that use post-update payloads. Custom-field endpoints now follow the same pattern through a CustomFieldFacade for controller orchestration, with create/update/restore reloads behind the facade, routes importing custom-field controllers and validation explicitly, domain bootstrap using explicit model/schema imports, and dedicated application modules for both create and update workflows so reserved-name checks, duplicate detection, entity-change guards, rename propagation, and unique-index queue orchestration sit outside the service class. Session-schedule endpoints now follow the same pattern through a SessionScheduleFacade for controller orchestration, with create/update reloads and trigger input shaping behind the facade, routes importing session-schedule controllers and validation explicitly, bootstrap/worker code using explicit model/service imports, and dedicated application workflows for manual trigger idempotency and ahead-of-time session generation. Layout endpoints now follow the same pattern through a LayoutFacade for controller orchestration, with update reloads behind the facade, routes importing layout controllers and validation explicitly, tenant initialization/hotfix paths using explicit layout service/type imports, and a dedicated application helper for composing default and custom layout fields outside LayoutReader. User endpoints now follow the same pattern through a UserFacade for controller orchestration, with request-user union shaping behind the facade, routes importing user controllers and validation explicitly, auth/tenant/middleware/hotfix code using explicit user reader/service/model/type imports instead of the broad public barrel, and an application workflow for user updates so admin-limit checks, usage accounting, and API-key revocation stay outside UserService. Auth routes now also import controllers and validation explicitly, the public auth barrel is intentionally empty, password sign-in, invited sign-up, email-verification account activation, Google sign-in, and Google invite acceptance each sit in dedicated application workflows so invitation lookup, role shaping, provider checks, password verification, pending-user cleanup, tenant trial activation, and Google-account validation are out of the controller, and auth helpers now own Google auth URL generation, callback token/profile exchange, tenant redirect URL shaping, and cold-start regression coverage that public auth/tenant/invited-member route imports stay free of Mongo, request-context, and mail-client side effects. Audit internals now also stay off the public barrel, with audit/index.ts narrowed to shared types only and plugins, bootstrap, stats, and inventory timeline code importing audit models and schemas explicitly. Invited-member endpoints now follow the same pattern through an InvitedMemberFacade, with invite/resend email delivery context loading in a dedicated application helper, routes importing invited-member controllers and validation explicitly, and auth/user/bootstrap internals using explicit invited-member service/model/schema/type paths instead of the broad public barrel. Feedback endpoints now keep the same boundary with FeedbackFacade, an index narrowed to facade/types, explicit route imports for controllers and validation, and focused facade coverage around submission email/storage orchestration. Tenant endpoints now start following the same pattern through a TenantFacade for current-tenant lifecycle checks and signup read-after-write flows, with routes importing tenant controllers and validation explicitly, tenant/index.ts narrowed to facade/types, a dedicated application helper handling expired-tenant suspension checks outside the controller, middleware/auth/paddle/inventory/token/user internals using explicit tenant service/model/schema/type paths instead of the broad public barrel, regression coverage that importing tenant controllers before Mongo connects does not touch the shared connection, and lazy mail-client construction so controller or service imports do not require RESEND_API_KEY at startup. Pending-user internals now also stay off the public barrel, with pendingUser/index.ts narrowed to shared types only and auth, tenant, bootstrap, and hotfix code importing pending-user models, schemas, and services explicitly. Password-request internals now follow the same rule, with passwordRequest/index.ts narrowed to shared types only and bootstrap plus user-service code importing password-request models and schemas explicitly. Subscription internals now follow the same rule, with subscription/index.ts narrowed to shared types only and admin, middleware, and domain-bootstrap code importing subscription models, schemas, and entitlements from explicit internal paths. Scan-event endpoints now keep the same boundary with ScanEventFacade, an index narrowed to facade/types, explicit route imports for controllers, focused facade coverage around item-history loading, and internal scan-event DTO helpers kept on explicit scanEvent/lib imports rather than re-exported publicly. Search endpoints now keep the same boundary with SearchFacade, an index narrowed to the facade only, explicit route imports for controllers, and focused facade coverage around query sanitization and tenant-search delegation. Object endpoints now keep the same boundary with ObjectFacade, an index narrowed to the facade only, explicit route imports for controllers and validation, and focused facade coverage around presigned upload/view URL delegation. Stats endpoints now keep the same boundary with StatsFacade for KPI, lifecycle, maintenance, depreciation, replacement-loss, overview, session analytics, session-data, recent-activity, analytics-report, and report-data orchestration, an index narrowed to facade/types, explicit route imports for controllers, focused helper coverage around KPI aggregation, lifecycle shaping, maintenance shaping, depreciation shaping, overview shaping, session-analytics shaping, session summary shaping, and recent-activity feed shaping, plus focused facade coverage around replacement-loss and report delegation while existing query builders continue to power the detailed report payloads. Paddle checkout endpoints now also follow the same pattern through a PaddleFacade, with routes importing paddle controllers and validation explicitly, checkout token/data orchestration behind the facade, shared plan/tenant/user checkout context loading in a focused application helper, and subscription model access moved off the broad subscription barrel. Trash endpoints now also keep the same boundary with a TrashFacade, an index narrowed to facade/types, explicit route imports for controllers and validation, focused facade coverage around deleted-item reads plus restore/permanent-delete delegation, and cold-start regression coverage so importing trash controllers does not require request context before middleware initializes it.

Contract docs

Use these docs together:

  • API Access: key creation and auth setup
  • API Endpoints (Overview): endpoint groups, auth model, and query patterns (this page)
  • Webhooks: delivery model and webhook signatures

Endpoints available via API key

All endpoints below are under the /api/v1 prefix and accept API key auth unless noted.

Categories

Base: /categories

  • GET /categories
  • GET /categories/default
  • POST /categories
  • PATCH /categories/:categoryId
  • DELETE /categories/:categoryId
  • POST /categories/:categoryId/restore

Locations

Base: /locations

  • GET /locations
  • GET /locations/default
  • POST /locations
  • PATCH /locations/:locationId
  • DELETE /locations/:locationId
  • POST /locations/:locationId/restore

Assets (Inventory items)

Base: /inventory-items

  • GET /inventory-items
  • POST /inventory-items
  • GET /inventory-items/:inventoryItemId
  • GET /inventory-items/unique-tag/:uniqueTag
  • PATCH /inventory-items/:inventoryItemId
  • DELETE /inventory-items/:inventoryItemId
  • POST /inventory-items/:inventoryItemId/restore
  • GET /inventory-items/:inventoryItemId/assignment-history
  • GET /inventory-items/:inventoryItemId/audit
  • GET /inventory-items/:inventoryItemId/allowed-status-transitions
  • GET /inventory-items/:inventoryItemId/status-events
  • GET /inventory-items/:inventoryItemId/timeline
  • GET /inventory-items/:inventoryItemId/health
  • POST /inventory-items/health/batch
  • POST /inventory-items/:inventoryItemId/status
  • POST /inventory-items/:inventoryItemId/checkout
  • POST /inventory-items/:inventoryItemId/checkin
  • POST /inventory-items/quick-add/events (JWT auth)

GET /inventory-items list view now includes per-item health:

  • health.score (0..100)
  • health.badge (HEALTHY | ATTENTION | AT_RISK)
  • health.reasons[]

GET /inventory-items supports health list controls:

  • healthBadge (HEALTHY | ATTENTION | AT_RISK)
  • healthSort (risk_first | healthy_first) — used by the Assets table Health column sort

GET /inventory-items/:inventoryItemId/timeline query params:

  • limit (default 50, max 100)
  • cursor (opaque pagination cursor from previous response)
  • types (optional comma-separated list):
    • CREATED
    • ASSIGNED
    • UNASSIGNED
    • MOVED
    • MAINTENANCE_COMPLETED
    • VERIFIED
    • STATUS_CHANGED
    • RETIRED

GET /inventory-items/:inventoryItemId/health returns:

  • score (0..100)
  • badge (HEALTHY | ATTENTION | AT_RISK)
  • reasons[] with reason codes and optional links

Health scoring is tenant-aware: workspace sensitivity presets can make the same signals read as more conservative or more strict, while severe states like lost still hard-fail. Reasons can include maintenance, verification, lifecycle age, and warranty signals when that data exists.

POST /inventory-items/health/batch accepts:

  • ids[] (asset ids, 1..200)

Returns:

  • items[] with id, score, badge, reasons

POST /inventory-items/:inventoryItemId/status accepts:

  • toStatus
  • reason (required for retired)
  • meta (optional context, e.g. reservation details)

Example:

{
  "toStatus": "reserved",
  "reason": "Reserved for onboarding",
  "meta": {
    "reservedUntil": "2026-03-01T09:00:00.000Z",
    "reservationReason": "New hire starts Monday"
  }
}

For maintenance, optional meta keys include:

  • no special keys are required; completion is tracked via POST /maintenance/logs

POST /inventory-items/:inventoryItemId/checkout accepts:

  • personId (required)
  • dueBackAt (optional ISO date/time)

POST /inventory-items/:inventoryItemId/checkin:

  • clears assignee and records check-in timestamps/history
  • keeps location unchanged

POST /inventory-items/quick-add/events accepts:

  • event (quick_add_opened | asset_created_quick | asset_assigned | advanced_opened)
  • flowId
  • optional itemId
  • optional meta

Ad-hoc maintenance completion example:

{
  "itemId": "<inventory-item-id>",
  "type": "repair",
  "completedDate": "2026-02-22T10:00:00.000Z",
  "notes": "Fan replaced and thermal test passed"
}

People

Base: /people

  • GET /people
  • POST /people
  • GET /people/:personId
  • PATCH /people/:personId
  • DELETE /people/:personId
  • POST /people/:personId/restore
  • GET /people/:personId/assignment-history

Inventory sessions (audits)

Base: /sessions

  • GET /sessions
  • GET /sessions/active
  • GET /sessions/:sessionId
  • POST /sessions
  • PATCH /sessions/:sessionId
  • DELETE /sessions/:sessionId
  • GET /sessions/:id/items
  • GET /sessions/:id/items/:itemId
  • POST /sessions/:id/items/:itemId/include
  • POST /sessions/:id/items/:itemId/exclude
  • GET /sessions/:id/missing
  • GET /sessions/:id/report
  • POST /sessions/:id/scan
  • POST /sessions/:id/unscan
  • GET /sessions/:id/mobile

POST /sessions/:id/scan is idempotent and returns:

  • accepted
  • already_scanned
  • not_in_session
  • wrong_location (for location-scoped sessions unless allowMarkAnyway is true)

Mobile/client scan payload accepts either:

  • itemId, or
  • code (QR value such as an asset URL)

Optional scan flags:

  • allowMarkAnyway (for location mismatch override)
  • allowRescan (explicitly re-write an already scanned item event)

GET /sessions/:id/mobile returns a fast mobile payload:

  • session identity/status/location
  • progress counts (scanned, total)
  • recent scans list for scan-loop UI

Stats / analytics

Base: /stats/analytics

  • GET /stats/analytics/overview
  • GET /stats/analytics/sessions
  • GET /stats/analytics/lifecycle
  • GET /stats/analytics/maintenance
  • GET /stats/analytics/depreciation
  • GET /stats/analytics/replacement-loss
  • GET /stats/analytics/reports

GET /stats/analytics/replacement-loss provides:

  • age buckets + age-by-category + oldest assets
  • warranty expiry counts/lists (30/60/90 days)
  • long-assigned assets and threshold counts
  • missing-rate trends (location/category) + repeatedly unscanned assets

Custom fields

Base: /custom-fields

  • GET /custom-fields
  • POST /custom-fields
  • PATCH /custom-fields/:customFieldId
  • DELETE /custom-fields/:customFieldId
  • POST /custom-fields/:customFieldId/restore

Custom-field definitions support dropdown options in addition to text, number, date, and checkbox types. Dropdown option lists are trimmed on save, cannot contain blanks, cannot contain duplicates case-insensitively, and must include at least one option.

Feedback

Base: /feedback (JWT auth)

  • POST /feedback

POST /feedback accepts a feedback title/message and optional image attachments. Attachments are limited to PNG, JPEG/JPG, or GIF files up to 5 MB each.

Objects

Base: /objects (JWT auth)

  • POST /objects
  • GET /objects/:objectKey/view-url

Object routes issue presigned upload and view URLs for tenant-scoped object keys. They are used by attachment/image workflows and do not accept API key authentication.

Base: /search (JWT auth)

  • GET /search?q=<query>

Search returns grouped quick-search results across assets, people, and inventory sessions. It is intended for authenticated app search flows and does not accept API key authentication.

Scan events

Base: /scan-events (JWT auth)

  • GET /scan-events/items/:itemId/history

Scan event history returns paginated scan records for one asset, including session context, condition, comments, photos, location, and scanner details.

Notifications

Base: /notifications (JWT auth)

  • GET /notifications
  • GET /notifications/unread-count
  • PATCH /notifications/read-all
  • PATCH /notifications/:notificationId

Notification routes are authenticated app endpoints for reading and updating in-app notification state. They do not accept API key authentication.

Maintenance

Base: /maintenance

Schedules:

  • POST /maintenance/schedules
  • GET /maintenance/schedules/due/all
  • GET /maintenance/schedules/item/:itemId
  • GET /maintenance/schedules/:id
  • PATCH /maintenance/schedules/:id
  • DELETE /maintenance/schedules/:id

GET /maintenance/schedules/due/all query params:

  • lookaheadDays (1..60, default 7)
  • Alias also accepted: reminderDays

Reminder classification:

  • overdue: nextDueDate < now
  • due today: nextDueDate is today
  • upcoming: nextDueDate > now and within schedule reminderDays

Logs:

  • POST /maintenance/logs
  • GET /maintenance/logs/item/:itemId
  • GET /maintenance/logs/schedule/:scheduleId
  • GET /maintenance/logs/:id
  • PATCH /maintenance/logs/:id
  • DELETE /maintenance/logs/:id

Webhooks (management API)

Base: /webhooks

Auth:

  • Requires JWT auth (Authorization: Bearer <jwt>)
  • API key auth is not supported on webhook management routes
  • Pro feature gate applies

Endpoints:

  • GET /webhooks/endpoints
  • POST /webhooks/endpoints
  • PATCH /webhooks/endpoints/:id
  • DELETE /webhooks/endpoints/:id
  • POST /webhooks/endpoints/:id/verify
  • GET /webhooks/health
  • GET /webhooks/deliveries
  • GET /webhooks/deliveries/:id
  • POST /webhooks/deliveries/:id/replay
  • POST /webhooks/events/:id/replay

GET /webhooks/deliveries query params:

  • endpointId (optional)
  • status (optional)
  • eventType (optional)
  • dateFrom (optional ISO date/time)
  • dateTo (optional ISO date/time)
  • limit (1..100, optional)

GET /webhooks/health query params:

  • windowMinutes (5..1440, optional, default 60)

Trash (restore / permanent delete)

Base: /trash

  • GET /trash
  • POST /trash/restore
  • POST /trash/permanent-delete

The admin API includes a TT10 report endpoint for quick-add onboarding diagnostics:

  • GET /admin/tenants/:tenantId/tt10-report?from=<ISO>&to=<ISO>

Response includes per-user entries with:

  • first created time
  • tenth assigned time
  • computed tt10Minutes
  • meetsTarget (tt10Minutes < 10)