xPlantAPI

Authentication and API keys

How to create a key, send it, keep it safe, and tell the two kinds of credential apart.

Every request carries a credential as a bearer token:

Authorization: Bearer xpk_live_…

There are two kinds of credential, and they are not interchangeable.

Workspace API keyDevice token
Prefixxpk_live_ or xpk_dev_xpd_live_ or xpd_dev_
Can doWhatever its scopes allow, across the workspacePost readings, events and heartbeats for one device, nothing else
Lives onA server, a script, an integration you runThe device itself: a Raspberry Pi, a gateway, a microcontroller
Created inSettings → Integrations → API KeysWith the API, using a workspace key (see Device tokens)

Plans and access

Three things bound what a key can do: its scopes, its owner's role, and the workspace's plan. A key never does more than its owner can in xPlant.

By plan

PlanWhat API keys can do
xPlant+ Teams, EnterpriseThe whole API: every scope.
Hobby, Pro LabConnect devices only: read:devices, write:devices, write:sensor_readings and write:device_events. Keys can register devices, manage their tokens, and post their readings and events. They can't read sensor readings back; that data is visible in xPlant.
FreeNo API access. Every request answers 402 PAID_PLAN_REQUIRED.

A call outside what the plan includes answers 402 PAID_PLAN_REQUIRED. See plans to upgrade. Your plan's allowances still apply too: registering devices beyond the plan's allowance answers 402 DEVICE_LIMIT_REACHED.

By role

A key acts with its owner's role in the workspace, as it is at the time of each request. If the owner's role changes, the key follows.

ScopesMinimum role of the key's owner
read: scopes, except the two belowAny active member
write: scopes, except the one belowmember
read:pricing, read:commerce, write:demandmanager

Roles rank owner > admin > manager > member > viewer > guest. A call that needs more than the owner's role answers 403 FORBIDDEN, and the message names the scope and the role it needs, for example:

{
  "ok": false,
  "data": null,
  "error": "This key's owner is a viewer in this workspace, which cannot use write:tasks (needs member or above). A key never does more than its owner can in xPlant.",
  "code": "FORBIDDEN"
}

The wording can change; branch on code. As a rule of thumb, 402 is about the plan, and 403 is about the role or a missing scope.

When you create a key

You can only grant scopes that your role and your plan allow. A scope above your role is refused with 403, and one above your plan with 402, and both messages name the scopes involved.

Check before you call

GET /me returns the key's scopes (what it was created with), effectiveScopes (what it can use right now, after the role and plan limits), the owner's role, and apiAccess: full on Teams and Enterprise, devices on plans whose keys can connect devices only.

Devices after a plan lapses

Device tokens keep posting readings, events and heartbeats after a plan lapses, so sensors don't go quiet. New devices and new tokens follow the plan's device allowance.

Enterprise customers can scope organisation-specific integrations and API requirements with us: support@xplantpro.com.

Creating a key

  1. Open Settings → Integrations → API Keys in xPlant.
  2. Name the key after what will use it ("Nightly task sync", "Grow room dashboard"). You'll thank yourself when you need to revoke one.
  3. Choose its scopes. A key gets exactly what you tick, and nothing by default. See Scopes for what each one allows and some common setups.
  4. Copy the key straight away. It is shown once. If you lose it, create a new one and revoke the old.

Scopes are fixed when a key is created. To change what an integration can do, create a new key with the scopes it needs, move the integration to it, then revoke the old key. Rotating a key in xPlant issues a new secret with the same name, scopes and environment.

A workspace can have up to 10 active keys at a time.

Live and dev keys

The xpk_live_ and xpk_dev_ prefixes are labels for your own bookkeeping. Both act on your real workspace, with the same data and the same limits. There is no sandbox. Use a dev key to keep test traffic separate in your records, not to protect production data.

What a key can reach

  • One workspace. A key belongs to the workspace it was created in and can never read or write another workspace's records. If you belong to several labs, each needs its own key.
  • Its scopes, and nothing more. No scope implies another; write:tasks does not grant read:tasks.
  • A record in another workspace looks the same as one that doesn't exist. Both answer 404 NOT_FOUND, so a key can't be used to probe for ids.

Call GET /me to see which key you're using and every scope it holds. It needs no scope.

When a key stops working

You getBecause
401 UNAUTHORIZEDThe key is missing, mistyped or revoked, or the person who created it has left the workspace.
402 PAID_PLAN_REQUIREDThe workspace's plan doesn't include this call. Teams and Enterprise include the whole API; Hobby and Pro Lab keys can connect devices only; Free has no API access. See Plans and access.
403 FORBIDDENThe key lacks the scope this endpoint needs, or its owner's role is below what the scope needs. The error text says which, e.g. Missing scope: write:tasks.
403 DEVICE_TOKEN_NOT_ACCEPTEDYou sent a device token to an endpoint that needs a workspace key.

A key is tied to the member who created it. When someone leaves the workspace, their keys stop working, so create keys for long-running integrations from an account that will stay.

Keeping keys safe

  • Keep keys in environment variables or a secrets manager, never in source code or a repository.
  • Never put a workspace key on a device. A box on a shelf, in a room other people walk through, should carry a device token that can only post its own readings.
  • Never embed a key in a web page or a mobile app. Anyone who opens it can read it. Call the API from your own backend instead.
  • Give each integration its own key with only the scopes it needs, so you can revoke one without breaking the others.
  • If a key leaks, revoke it in Settings → Integrations → API Keys at once, then create a replacement.
Edit on GitHub

On this page