Gardience Documentation gardience.com →
Docs / Administration

API keys and the REST API

Scripts, pipelines, monitoring tools and the gdn command-line tool talk to Gardience with an API key. A key always acts as the person who created it, called its owner, and can never do more than that person.

Create a key

  1. Sign out of the console and sign back in. Gardience only lets a session that started on its own sign-in page create keys.
  2. Open Settings and find API keys.
  3. Enter a name for the key, for example Prometheus or Nightly patch job.
  4. Choose a scope:

    • Read only: sees everything the API offers, changes nothing.
    • Operate (request runbooks): can also request runbook runs and upload Ansible playbooks.
    • Configure (Terraform, admins): for Terraform and other infrastructure-as-code tools. Manages enrollments, custom node groups, saved states and event rules, and removes machines. It cannot request runs on the existing fleet. It can, however, decide what happens to new machines: an enrollment lets them join without approval, and a join rule applies a saved state to them (states are still checked by the config keeper, and cannot run commands while command execution is off). Treat it like an admin credential. See Terraform.
  5. Leave Require approval ticked unless you have a reason not to (see below).
  6. Click Create key.
  7. Copy the key. It starts with gdn_ and is shown once. Store it in your secrets manager.

Gardience keeps only a SHA-256 hash of the key. The list shows the first 10 characters so you can tell keys apart, plus the owner, scope, approval setting, last use and expiry date.

Who can do what with keys:

ActionWho
Create a read keyAnyone who can sign in
Create an operate keyAnyone whose role can change something. A viewer cannot.
Create an operate key that skips approvalAdmins only
Create a configure keyAdmins only. It cannot be limited to runbooks or node groups, and stops working the moment its owner is no longer an admin.
See a key in the listIts owner, and all admins
Revoke a keyIts owner, and all admins

Creating and revoking keys are recorded in the audit log (apikey.created, apikey.revoked).

Approval

When an operate key has Require approval on, each run it requests waits for a second person. Someone with the admin or approver role approves or rejects it in the console under Workflows. The key's owner cannot approve their own request.

The API answers at once with the run's ID and the status awaiting approval. Poll GET /runs/{id} to follow it.

With approval off, the run starts at once with the status running.

What a key is allowed to run

Even an operate key can only:

A key also needs a valid license to request runs. See Licensing.

When a key stops working

A key is refused with HTTP 401 when any of these is true:

A paused key works again as soon as its owner signs in. Keys used by monitoring or automation therefore need an owner who signs in regularly.

A read or configure key that tries to request a run gets HTTP 403. A read or operate key that tries to change configuration gets HTTP 403, "This needs a configure key".

Call the REST API

The base URL is https://<console>/gardience/api/v1. Send the key in the Authorization header:

curl -s -H "Authorization: Bearer gdn_..." https://gardience.example.com/gardience/api/v1/fleet

Interactive documentation, generated from the running server, is at /gardience/api/v1/docs, and the OpenAPI description at /gardience/api/v1/openapi.json. The console links to it from Settings > API keys (API reference).

Endpoints

All paths are relative to /gardience/api/v1.

Method and pathScopeReturns or does
GET /fleetreadEvery node: OS, Salt agent version, pending updates, reboot pending, baseline score, failing controls, compliant, stale. Also the last scan time.
GET /nodes/{node}readOne node: pending updates, every baseline control, open drift and when drift was last checked. 404 if there is no such node.
GET /driftreadDifferences between each node and its desired state, plus history.
GET /audit?limit=50&q=textreadRecent audit entries, newest last. limit is 1 to 500. q matches any text in the entry. Searches the most recent 20,000 entries.
GET /audit/verifyreadRecomputes the audit log's hash chain and reports whether it is intact.
GET /runbooksreadRunbooks, the inputs each takes, and the valid node groups.
GET /runsreadThe 50 most recent runbook and workflow runs.
GET /runs/{id}readOne run with its steps, log and approval decision.
POST /runsoperateRequests a runbook run. See below.
POST /playbooksoperateUploads an Ansible playbook for the ansible-upload runbook. See below.
GET /groupsreadNode groups (built-in, Ansible and custom) with their online members.
GET /inventoryreadAsset inventory: domain, BitLocker, .NET, SELinux, disk, local admins, last boot.
GET /licensereadLicense state, type, node limit, expiry and nodes in use, with a message when something needs attention.
GET /savingsreadAutomation hours and money saved this month.
GET /metricsreadPrometheus metrics. See Monitoring.
GET /enrollmentsconfigureEnrollments, newest first. Tokens are never listed.
POST /enrollmentsconfigureOpens an enrollment: label, hours (1 to 2160), groups, site, proxy. Returns its token once.
GET /enrollments/{id}configureOne enrollment and its state (active, expired or revoked).
DELETE /enrollments/{id}configureCloses an enrollment. Machines that joined stay.
GET /enrollments/{id}/script?os=linux&node=NAME&groups=a,bconfigureA first-boot script for one machine (os is linux or windows). Contains the token.
GET /groups/{name}readOne node group: its Salt expression and members.
PUT /groups/{name}configureCreates or replaces a custom group: kind (nodes, os, match or compound) and its value.
DELETE /groups/{name}configureDeletes a custom group.
GET /states, GET /states/{name}readSaved states as published, with a short SHA-256 of each.
PUT /states/{name}configureSaves a state (content). The configuration keeper checks it first; it is published within seconds or refused.
DELETE /states/{name}configureDeletes a saved state.
GET /rules, GET /rules/{id}readEvent rules.
PUT /rules/{id}configureCreates or replaces an event rule. See Drift checks and event rules.
DELETE /rules/{id}configureDeletes an event rule.
GET /machines/{node}readWhether a machine has joined: its key state (accepted, pending, rejected, denied or none), OS and compliance.
DELETE /machines/{node}configureRemoves a machine from the fleet. Answers 202: the config keeper checks the request and the hourly limit, then the Salt master moves the machine's key to a holding folder for 30 days (the web service never deletes keys), so root can put it back with gardience machine restore NAME. At most 50 removals an hour by default (gardience machine limit N); over that, 429. Not available in attach mode. If the name joins again later it counts as a new machine.

Changes made with a configure key are recorded in the audit log under the key's owner, with "via API key NAME".

Request a run

curl -s -X POST https://gardience.example.com/gardience/api/v1/runs \
  -H "Authorization: Bearer gdn_..." -H "Content-Type: application/json" \
  -d '{"runbook": "run-command", "inputs": {"nodegroup": "Linux", "command": "uptime"}, "reason": "check load"}'
{"run_id": "...", "status": "awaiting approval", "console": "/gardience/workflows#run-..."}

The body takes runbook (a runbook ID from GET /runbooks), inputs (an object) and reason (shown to the approver and kept in the audit log). Every request is recorded as api.run_requested.

Upload a playbook

POST /playbooks takes name and content:

The answer gives a playbook value to pass as the playbook input of the ansible-upload runbook. Uploads are kept per owner and recorded as playbook.uploaded. The gdn playbook command does both steps for you.

Errors

Errors come back as JSON with a detail message:

CodeMeaning
400A bad input, for example an unknown runbook input or a node group with no online node.
401No key, an unknown, revoked or expired key, or a paused key.
402The license does not allow changes right now.
403A read key asked for a change, or the owner is not allowed to run that function on those nodes.
404No such node or run.
503The Salt master is starting or unreachable. Try again in a few seconds.

The MCP server

Gardience is also a Model Context Protocol (MCP) server. MCP is an open protocol that lets other tools, such as code editors, call a service's functions. Any MCP client that supports the HTTP transport with a custom header can connect.

A typical client configuration looks like this (the exact file depends on your client):

{ "servers": { "gardience": { "type": "http",
    "url": "https://gardience.example.com/gardience/mcp",
    "headers": { "Authorization": "Bearer gdn_..." } } } }

The console shows ready-made examples for common clients under Settings.

Tools

ToolScopeWhat it does
fleet_statusreadEvery node with pending updates, reboot status, baseline score, Salt agent version and compliance.
node_detailsreadOne node in full. Takes node.
compliance_failuresreadOnly the nodes out of compliance, with failing controls and pending updates.
drift_reportreadOpen drift per node, plus the 10 most recent automatic corrections.
search_audit_logreadSearches the audit log. Takes query and limit (default 25).
verify_audit_chainreadRecomputes the audit hash chain.
list_runbooksreadRunbooks, their inputs and the valid node groups.
inventoryreadAsset inventory for every node.
run_statusreadStatus, steps, approver and log of a run. Takes run_id.
request_runbookoperateRequests a runbook run. Takes runbook, reason and inputs.

A read key does not see request_runbook in the tool list. request_runbook follows exactly the same rules as POST /runs, including approval, and each call is recorded in the audit log as mcp.request_runbook. A tool's answer is cut off after 60,000 characters.

Gardience by Bouziden Management LLC.