Diode Diode Console

API

Diode Console APIs Overview

Diode Console provides APIs for automating fleet creation, membership changes, and retirement using organization-scoped keys.

The public integration surface is JSON-RPC 2.0 over HTTPS. It is not Moonbeam RPC: on-chain work is queued by the console and completed asynchronously through the Diode chain layer.

Available APIs

API Description
Console JSON-RPC API

POST /api/v1/rpc

Manage fleet lifecycle and members from scripts, MDM tooling, or internal systems.
Organization API keys

dck_...

Create, update, and revoke secrets in Settings. Each key is scoped to one organization with a label, fleet access mode (all fleets vs restricted grants), and action scopes.
Fleet operations

fleet.*

Create, rename, list members, look up a device, add/remove members, and start fleet retirement.
API key management

api_key.*

List, create, update, and revoke organization API keys. Requires the admin scope on the bearer key.

Authentication

Create API keys under Settings (owners and admins only). Set an optional label, choose fleet access (all fleets in the org or an explicit grant list), and select action scopes (read, member changes, rename, destroy, fleet creation, or the admin scope for API key management RPCs). The admin scope implies all fleet actions. Org-wide admin keys (all_fleets) can only be created in Settings, not via api_key.create. Keys with only create_fleet may start with an empty grant list; each successful fleet.create adds the new fleet to grants when access is restricted. You can edit keys later; the secret stays read-once. Copy the secret when it is created; only the hash is stored on the server. Send it as a Bearer token. Lowercase bearer is accepted.

Action scopes

Each JSON-RPC method requires a scope on the bearer key (or admin, which implies all fleet scopes).

Scope Methods
fleet_read fleet.info, fleet.member.list, fleet.member.get
fleet_add_device fleet.member.add, fleet.member.add_batch
fleet_remove_device fleet.member.remove, fleet.member.remove_batch
fleet_update fleet.rename
fleet_destroy fleet.destroy
create_fleet fleet.create
admin api_key.list, api_key.create, api_key.update, api_key.revoke

Header

Authorization: Bearer YOUR_API_KEY

Request Format

Every call is a JSON object with jsonrpc, method, params (object), and id (string or number). Successful responses include result; failures include error.

POST /api/v1/rpc application/json

Batch Requests

POST a JSON array of request objects to run multiple calls in one HTTP request. Empty arrays are rejected with HTTP 400 and a JSON-RPC error object. For device imports, prefer the member batch methods over JSON-RPC request arrays: they create one database batch and split on-chain work into safe transaction chunks.

Batch example (curl)

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '[{"jsonrpc":"2.0","method":"fleet.create","params":{"name":"Alpha"},"id":1},{"jsonrpc":"2.0","method":"fleet.create","params":{"name":"Beta"},"id":2}]'

fleet.create

Create a new fleet for the organization. Returns fleet_id and initial state while deployment continues asynchronously.

Parameters

  • name (string, required): display name.

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.create","params":{"name":"Production"},"id":1}'

Example response

{"jsonrpc":"2.0","id":1,"result":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","state":"deploying"}}

fleet.rename

Update the fleet name in the console. Imported read-only fleets can use this metadata-only operation.

Parameters

  • fleet_id (UUID or contract address, required).
  • name (string, required).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.rename","params":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","name":"Staging"},"id":2}'

Example response

{"jsonrpc":"2.0","id":2,"result":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","name":"Staging","state":"live"}}

fleet.info

Read-only snapshot: device count (fleet member rows), authoritative bandwidth usage in bytes for the current epoch (used_bytes — larger of chain snapshot and live relay total, same rule as the fleet page bandwidth meter and epoch-close billing), registry stake as a wei string (or null if the balance cannot be read), chain id, operator and accountant addresses, the fleet smart contract address, and a billing object with plan context (mode, plan_id, monthly_traffic_gb, allowance_bytes, free_bytes_remaining). Hex fields use lowercase 0x prefixes. Imported fleets are supported.

Parameters

  • fleet_id (UUID or contract address, required).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.info","params":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000"},"id":21}'

Example response

{"jsonrpc":"2.0","id":21,"result":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","device_count":2,"used_bytes":150000000,"stake_wei":"1000000000000000000","chain_id":1284,"operator":"0x2222222222222222222222222222222222222222","accountant":"0x3333333333333333333333333333333333333333","contract_address":"0x742d35cc6634c0532925a3b844bc454e4438f44e","billing":{"mode":"prepaid","plan_id":"default_50","monthly_traffic_gb":50,"allowance_bytes":50000000000,"free_bytes_remaining":49850000000}}}

fleet.member.add

Add a member address to a fleet. Imported read-only fleets reject this method.

Parameters

  • fleet_id (UUID or contract address, required).
  • address (string, required): member wallet address.
  • label (string, optional).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.member.add","params":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","address":"0x742d35Cc6634C0532925a3b844Bc454e4438f44e","label":"Device A"},"id":3}'

Example response

{"jsonrpc":"2.0","id":3,"result":{"member_id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","state":"pending_add"}}

fleet.member.add_batch

Add many member addresses to a fleet. The console validates the full request before inserting members, then queues one AddDeviceBatch on-chain transaction per safe chunk.

Parameters

  • fleet_id (UUID or contract address, required).
  • Exactly one of: members (array of objects with address and optional label) or addresses (array of address strings when labels are not needed).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.member.add_batch","params":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","members":[{"address":"0x742d35Cc6634C0532925a3b844Bc454e4438f44e","label":"Device A"},{"address":"0x1111111111111111111111111111111111111111","label":"Device B"}]},"id":4}'

Example response

{"jsonrpc":"2.0","id":4,"result":{"count":2,"members":[{"member_id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","state":"pending_add"},{"member_id":"6ba7b811-9dad-11d1-80b4-00c04fd430c8","state":"pending_add"}]}}

fleet.member.list

Paginated list of devices (fleet members) for a fleet. Includes removed rows still stored in the console. Imported read-only fleets are supported.

Parameters

  • fleet_id (UUID or contract address, required).
  • limit (integer, optional): page size, default 50, maximum 100.
  • offset (integer, optional): rows to skip, default 0.

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.member.list","params":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","limit":50,"offset":0},"id":41}'

Example response

{"jsonrpc":"2.0","id":41,"result":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","members":[{"member_id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","address":"0x742d35cc6634c0532925a3b844bc454e4438f44e","label":"Device A","state":"active"}],"total":1,"limit":50,"offset":0,"has_more":false}}

fleet.member.get

Fetch one member by console id or device address. Pass exactly one of member_id or address. Imported read-only fleets are supported.

Parameters

  • fleet_id (UUID or contract address, required).
  • member_id (UUID): console member row id.
  • address (string): device address (0x hex).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.member.get","params":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","address":"0x742d35Cc6634C0532925a3b844Bc454e4438f44e"},"id":42}'

Example response

{"jsonrpc":"2.0","id":42,"result":{"member_id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","address":"0x742d35cc6634c0532925a3b844bc454e4438f44e","label":"Device A","state":"active"}}

fleet.member.remove

Remove a member by its console id. Imported read-only fleets reject this method. Members already allowlisted on chain return state: "pending_remove" while the removal transaction confirms; members whose add transaction never reached the chain are deleted immediately and return state: "removed".

Parameters

  • member_id (UUID string, required).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.member.remove","params":{"member_id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8"},"id":5}'

Example response

{"jsonrpc":"2.0","id":5,"result":{"member_id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","state":"pending_remove"}}

fleet.member.remove_batch

Remove many members. Pass member_ids directly, or pass fleet_id with addresses to remove by device address. The console queues RemoveDeviceBatch transactions in safe chunks. Same pending_remove / removed state semantics as fleet.member.remove.

Parameters

  • member_ids (array): console member UUIDs.
  • fleet_id plus addresses (array): remove by fleet and member address.

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.member.remove_batch","params":{"member_ids":["6ba7b810-9dad-11d1-80b4-00c04fd430c8","6ba7b811-9dad-11d1-80b4-00c04fd430c8"]},"id":6}'

Example response

{"jsonrpc":"2.0","id":6,"result":{"count":2,"members":[{"member_id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","state":"pending_remove"},{"member_id":"6ba7b811-9dad-11d1-80b4-00c04fd430c8","state":"pending_remove"}]}}

fleet.destroy

Retire a fleet: archives immediately when there is no registry stake (or the fleet was never deployed); otherwise enqueues full unstake and returns unstaking. Imported read-only fleets archive locally only. Destroyed fleets stay in the database as archived and disappear from the dashboard.

Parameters

  • fleet_id (UUID or contract address, required).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"fleet.destroy","params":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000"},"id":7}'

Example response

{"jsonrpc":"2.0","id":7,"result":{"fleet_id":"550e8400-e29b-41d4-a716-446655440000","state":"unstaking","note":"unstake_enqueued"}}

api_key.list

List non-revoked API keys for the organization. Requires the admin scope. Returns metadata only; secrets are never included.

Parameters

  • None (empty object).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"api_key.list","params":{},"id":81}'

Example response

{"jsonrpc":"2.0","id":81,"result":{"api_keys":[{"api_key_id":"a0a0a0a0-a0a0-a0a0-a0a0-a0a0a0a0a0a0","label":"CI automation","prefix":"dck_1a2b3c4d","fleet_access_mode":"all_fleets","scopes":["fleet_read","fleet_add_device"],"fleet_ids":[],"created_at":"2026-05-28T12:00:00.000000Z","last_used_at":"2026-05-28T14:30:00.000000Z"}]}}

api_key.create

Create a new API key. Requires admin. Returns the full secret once in the result; later calls and api_key.list show only the prefix. Org-wide admin keys (all_fleets) cannot be created via RPC — use Settings. Restricted admin callers may only create non-admin keys with the same fleet_ids grant set.

Parameters

  • label (string, optional).
  • fleet_access_mode (string, required): all_fleets or restricted.
  • scopes (array of strings, required): fleet scope strings such as fleet_read; do not include admin when creating via RPC.
  • fleet_ids (array of UUID or contract address strings): required when fleet_access_mode is restricted (unless the only scope is create_fleet).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"api_key.create","params":{"label":"Delegated read","fleet_access_mode":"restricted","scopes":["fleet_read"],"fleet_ids":["550e8400-e29b-41d4-a716-446655440000"]},"id":82}'

Example response

{"jsonrpc":"2.0","id":82,"result":{"api_key":{"api_key_id":"b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1","label":"Delegated read","prefix":"dck_9f8e7d6c","fleet_access_mode":"restricted","scopes":["fleet_read"],"fleet_ids":["550e8400-e29b-41d4-a716-446655440000"],"created_at":"2026-05-28T15:00:00.000000Z","last_used_at":null},"secret":"dck_9f8e7d6c5b4a3928171615141312111009f8e7d6c5b4a392"}}

api_key.update

Update label, fleet access mode, scopes, and (when restricted) fleet grants for an existing key. Requires admin. The same delegation rules as api_key.create apply. Omitted fields keep their current values when updating a single attribute.

Parameters

  • api_key_id (UUID string, required).
  • label (string, optional).
  • fleet_access_mode (string, optional): all_fleets or restricted.
  • scopes (array of strings, optional).
  • fleet_ids (array of UUID or contract address strings, optional): replaces grants when access is restricted.

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"api_key.update","params":{"api_key_id":"b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1","label":"Delegated read+update","fleet_access_mode":"restricted","scopes":["fleet_read","fleet_update"],"fleet_ids":["550e8400-e29b-41d4-a716-446655440000"]},"id":83}'

Example response

{"jsonrpc":"2.0","id":83,"result":{"api_key":{"api_key_id":"b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1","label":"Delegated read+update","prefix":"dck_9f8e7d6c","fleet_access_mode":"restricted","scopes":["fleet_read","fleet_update"],"fleet_ids":["550e8400-e29b-41d4-a716-446655440000"],"created_at":"2026-05-28T15:00:00.000000Z","last_used_at":null}}}

api_key.revoke

Revoke an API key by id. Requires admin. Idempotent when the key is already revoked. Revoked keys no longer authenticate.

Parameters

  • api_key_id (UUID string, required).

Example request

curl https://console.diode.io/api/v1/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","method":"api_key.revoke","params":{"api_key_id":"b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1"},"id":84}'

Example response

{"jsonrpc":"2.0","id":84,"result":{"api_key_id":"b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1","revoked_at":"2026-05-28T16:00:00.000000Z"}}

Common Error Responses

JSON-RPC errors use negative numeric code values. HTTP status is usually 200 for application-level errors except where noted.

Code Message
-32001 unauthorized
-32001 invalid_api_key
-32003 forbidden
-32004 fleet_not_found
-32004 api_key_not_found
-32005 imported_readonly
-32006 fleet_not_live
-32007 cap_exceeded
-32008 member_not_found
-32010 invalid_fleet_state
-32012 registry_unavailable
-32601 method_not_found
-32600 invalid_request
-32700 invalid_request
-32602 invalid_params
-32603 internal_error