All endpoints are JSON over HTTPS. Org scope is handled via the x-org-key header for both GET and POST requests.
Don’t put org keys in query strings or URLs.
Base URL:
https://machineid.io
API version:
/api/v1/...
Content type:
application/json
- Org key per customer or tenant (
orgApiKey). - Device IDs are strings you control (
deviceId). - Limits enforced server-side by plan tier (free, pro, scale, max).
- Stripe Checkout and portal back billing and upgrades.
Create an org and receive an orgApiKey. Store it with your customer record and in your agents.
Called from your backend or control plane when a new customer is created. The response includes a unique
orgApiKey for that tenant.
Example response:
{
"status": "ok",
"orgApiKey": "org_123",
"handler": "org_create"
}
Register devices against an org, validate them at the edge, list them, and revoke or restore as needed.
Called by your agent, gateway, or service when a machine first comes online. Idempotent for the same
deviceId: you can safely retry.
Possible responses:
{
"status": "ok",
"handler": "devices/register",
"deviceId": "agent-01",
"planTier": "free",
"planState": "active",
"accessUntil": null,
"limit": 3,
"devicesUsed": 1,
"remaining": 2,
"overLimit": false,
"softGraceWindow": false
}
{
"status": "exists",
"handler": "devices/register",
"deviceId": "agent-01",
"planTier": "free",
"planState": "active",
"accessUntil": null,
"limit": 3,
"devicesUsed": 1,
"remaining": 2,
"overLimit": false,
"softGraceWindow": false
}
{
"status": "restored",
"handler": "devices/register",
"deviceId": "agent-01",
"planTier": "free",
"planState": "active",
"accessUntil": null,
"limit": 3,
"devicesUsed": 2,
"remaining": 1,
"overLimit": false,
"softGraceWindow": false
}
{
"status": "limit_reached",
"handler": "devices/register",
"deviceId": "agent-99",
"planTier": "free",
"planState": "active",
"accessUntil": null,
"limit": 3,
"devicesUsed": 3,
"remaining": 0,
"overLimit": true,
"softGraceWindow": false
}
Called by agents before doing work (on startup or on a schedule). Returns whether a device is allowed to run.
Example responses:
{
"status": "ok",
"handler": "devices/validate",
"deviceId": "agent-01",
"planTier": "free",
"planState": "active",
"effectivePlanState": "active",
"accessUntil": null,
"limit": 3,
"devicesUsed": 1,
"overLimit": false,
"allowed": true,
"reason": "ok"
}
{
"status": "revoked",
"handler": "devices/validate",
"deviceId": "agent-02",
"planTier": "free",
"planState": "active",
"effectivePlanState": "active",
"accessUntil": null,
"limit": 3,
"devicesUsed": 2,
"overLimit": false,
"allowed": false,
"reason": "device_revoked",
"revoked_at": "2025-11-17T09:00:00.000Z"
}
Returns all devices for an org. Used by the MachineID.io dashboard and can be wired into your own admin tools.
Example response:
{
"status": "ok",
"handler": "devices/list",
"devices": [
{
"device_id": "agent-01",
"created_at": "2025-11-17T07:23:20.926Z",
"status": "active",
"revoked_at": null
},
{
"device_id": "agent-02",
"created_at": "2025-11-17T08:00:00.000Z",
"status": "revoked",
"revoked_at": "2025-11-17T09:00:00.000Z"
}
]
}
Use /devices/revoke to turn off a device, and /devices/unrevoke to restore it.
Revoked devices fail validation until restored.
Example revoke response:
{
"status": "ok",
"handler": "devices/revoke",
"deviceId": "agent-01",
"device": {
"device_id": "agent-01",
"created_at": "2025-11-16T10:00:00.000Z",
"revoked_at": "2025-11-17T07:30:00.000Z",
"updated_at": "2025-11-17T07:30:00.000Z"
}
}
Check how many devices are active for an org and what cap applies to that plan.
Use /usage in your own admin tools to show the same numbers as the MachineID.io dashboard:
plan tier, active devices, and the limit for that plan.
Example response:
{
"status": "ok",
"handler": "usage",
"planTier": "free",
"planState": "active",
"accessUntil": null,
"limit": 3,
"devicesUsed": 1,
"remaining": 2,
"overLimit": false,
"isActive": true,
"isGrace": false,
"isFrozen": false
}
Plans are backed by Stripe. Query the current plan and open Checkout when it’s time to upgrade.
Shows the current plan tier and a short message. Free plans typically return "Free plan — upgrade available",
while paid plans are managed via the Stripe customer portal.
Example response:
{
"status": "ok",
"planTier": "free",
"stripeCustomerId": null,
"stripeSubscriptionId": null,
"message": "Free plan — upgrade available",
"handler": "billing_summary"
}
When upgrading from your own UI, call /billing/checkout with the target plan in the JSON body
("pro", "scale", or "max") and send the org key in the
x-org-key header. The response includes a Stripe checkoutUrl you can redirect to.
In environments where Stripe is not configured, you’ll see status: "no_stripe" and a message
explaining that Checkout is unavailable.
Responses are intentionally small and consistent. Log status and handler for quick debugging.
"ok"– success."exists"– device already active."restored"– device was revoked, now active again."limit_reached"– plan cap hit for that org."error"– input or validation issue."not_found"– org or device not found.
Examples:
{
"status": "error",
"error": "missing_params",
"handler": "usage"
}
{
"status": "not_found",
"handler": "usage"
}
{
"status": "limit_reached",
"deviceId": "dev-999",
"planTier": "free",
"limit": 3,
"devicesUsed": 3,
"handler": "devices/register"
}
{
"status": "error",
"error": "missing_params",
"handler": "devices/register"
}
Designed to be safe for scripts, services, and AI tools working alongside human operators.
Whether you call the API from a CLI, a background job, or an AI agent acting on your behalf, the shapes are kept small and predictable so automation stays safe and boring:
- Stable JSON envelopes with
statusandhandleron every response. devices/registeris idempotent for a givendeviceId– safe to retry.limit_reachedis explicit, so callers can surface an upgrade prompt instead of hammering.- No hidden state beyond org key, plan tier, and device records.
Recommended behavior:
- On
limit_reached, stop creating devices and surface an upgrade path or alert. - On
errorlikemissing_params, prompt for configuration instead of retrying blindly. - On transient network issues or rate limiting, retry with backoff from your automation layer.
Think of MachineID.io as a simple, central source of truth your agents and tools can trust – built by people who ship agents, for people who ship agents.