FeaturesPricingDownloadDocsChangelogSupport
Get started free Log in
API reference

NetMind REST API

The same REST API the NetMind dashboard uses — your account, devices and network data. Available on every plan.

Base URL: https://backend-netmindweb.onrender.com/api

Authentication: sign in with POST /auth/login and send the returned token as Authorization: Bearer <token>. Access tokens expire after a short time — use /auth/refresh to get a new one.

Content-Type: request bodies are application/json. IDs are UUIDs.

Limits: sign-in endpoints allow 20 requests per 15 minutes per IP; other endpoints 600. Browser calls are only accepted from the NetMind website — call the API from your own server or scripts.

Authentication

POST /auth/signup Create an account
{
  "email": "you@company.com",
  "password": "at least 8 characters",
  "full_name": "Your Name",
  "company_name": "Optional"
}

// 201 — no tokens yet: the email address must be verified first
{ "message": "Account created successfully. Please check your email…", "requiresVerification": true, "email": "you@company.com" }
POST /auth/login Sign in with email and password
{ "email": "you@company.com", "password": "…", "remember_me": false }

// 200 — signed in
{
  "token": "eyJ…",               // access token, send as "Authorization: Bearer <token>"
  "token_expires_at": 1791460000000,
  "refresh_token": "…",
  "refresh_expires_at": 1792060000000,
  "user": { "id": "8b1c…-uuid", "email": "you@company.com", "full_name": "Your Name", … },
  "subscription": { "plan_id": "free", "status": "active", "renewal_date": null }
}

// 200 — two-factor authentication is on: finish with /auth/2fa/challenge
{ "requires_2fa": true, "mfa_token": "eyJ…" }

// 401 wrong password · 403 EMAIL_NOT_VERIFIED · 429 ACCOUNT_LOCKED (after 5 failures)
POST /auth/2fa/challenge Second step when 2FA is on
{ "mfa_token": "eyJ…", "code": "123456" }

// 200 — same body as a successful /auth/login
// 401 INVALID_2FA (counts toward the lockout) · 401 MFA_EXPIRED (sign in again; tokens last 5 minutes)
POST /auth/refresh Get a new access token
{ "refresh_token": "…" }

// 200 — a new token pair; the old refresh token stops working
{ "token": "eyJ…", "token_expires_at": …, "refresh_token": "…", "refresh_expires_at": … }
POST /auth/logout Revoke a refresh token
{ "refresh_token": "…" }

// 200
{ "message": "Logged out successfully." }

Account

GET /user/profile Your profile and preferences Auth required
// 200
{
  "user": {
    "id": "8b1c…-uuid", "email": "you@company.com", "full_name": "Your Name",
    "company_name": "Acme", "phone": "+216 20 123 456", "two_factor_enabled": false,
    "email_daily_report": true, "email_weekly_summary": true, "timezone": "Africa/Tunis",
    "theme": "light", "webhook_url": null, "created_at": "2026-10-08T17:42:38.027Z"
  }
}
PUT /user/profile Update name, company or phone Auth required
{ "full_name": "New Name", "company_name": "New Co", "phone": "+216 20 123 456" }

// 200
{ "message": "Profile updated successfully.", "user": { … } }
PUT /user/preferences Partial update of preferences Auth required
// Send only the fields you want to change. "webhook_url": "" removes the webhook.
{ "email_weekly_summary": false, "timezone": "Africa/Tunis", "theme": "dark", "webhook_url": "https://example.org/hook" }

// 200
{ "message": "Preferences saved successfully." }
GET /user/activity?limit=20&type=login Activity and alerts (newest first, max 50) Auth required
// 200
{ "activity": [ { "id": 42, "type": "device_new", "message": "New device joined your network: Sam iPhone (192.168.1.21)",
                  "severity": "warning", "icon": "🔌", "metadata": { "ip": "192.168.1.21", … }, "created_at": "…" } ] }
GET /user/export Download all your data as JSON Auth required
// 200 — account, preferences, subscription, devices, bandwidth_history, invoices, sessions, activity
GET /subscription Current plan Auth required
// 200
{
  "subscription": { "plan_id": "paid", "status": "active", "renewal_date": "2026-11-08T…", "cancel_at_period_end": false,
                    "max_devices": 20, "history_days": 30, … },
  "billing": { "online_payments": false, "paid_price_cents": 2000, "currency": "usd" }
}

Network data (from the desktop app)

GET /tool/devices Devices from the latest scan Auth required
// 200 — status is "live" while the app is online, "stale" otherwise, "not_configured" if never linked
{
  "status": "live", "total": 2, "last_updated": "…",
  "devices": [ { "ip": "192.168.1.20", "mac": "aa:bb:cc:00:00:01", "name": "Reception PC",
                 "status": "active", "download": 12.5, "upload": 1.2 } ]   // speeds in Mbps
}
GET /tool/status Is the desktop app online? Auth required
// 200
{ "status": "online", "last_updated": "…", "online_since": "…", "uptime_seconds": 5400, "device_count": 7, … }
// or { "status": "offline", "last_seen": "…" } · { "status": "not_configured" }
GET /tool/history?hours=24 Bandwidth history (capped at 7 days Free / 30 days Paid) Auth required
// 200
{ "hours": 24, "max_hours": 168, "bucket_seconds": 240, "plan": "free",
  "points": [ { "t": "2026-10-08T17:00:00Z", "down_mbps": 14.2, "up_mbps": 1.6, "device_count": 7 } ] }
POST /tool/command Block or limit a device remotely Auth required
{ "command": "limit", "payload": { "ip": "192.168.1.45", "down_kbps": 625, "up_kbps": 312 } }   // KB/s
{ "command": "block", "payload": { "ip": "192.168.1.45" } }
{ "command": "remove_limit", "payload": { "ip": "192.168.1.45" } }
{ "command": "restore_all", "payload": {} }

// 200 { "ok": true, "command_id": "…", "message": "Command 'limit' queued…" }
// 403 DEVICE_LIMIT (plan cap reached) · 503 desktop app offline

Reviews (public)

GET /reviews Approved reviews
// 200
{ "reviews": [ { "id": "c1f2…-uuid", "name": "Sam", "rating": 5, "comment": "…", "created_at": "…" } ] }
POST /reviews Submit a review (3 per hour per IP)
{ "name": "Sam", "rating": 5, "comment": "Setup was easy and the till is fast again." }

// 201
{ "message": "Review submitted — it will appear after approval" }