The web UI uses the console's HTTPS API, under /api/v2. Each handler in
console-server/src/main/java/com/pointblue/console/server/http/ lists its own routes at the top of its source.
This page covers the conventions they share, and the directory-object routes as an example.
- Sessions:
- Sign in with
POST /api/v2/session. The console sets a__Host-session cookie. - Writes need the session's
X-CSRF-Tokenheader, and must come from the console's own origin.
- Sign in with
- Rights: every call runs on the person's own directory connection, so eDirectory applies their rights. The
console's roles narrow what they may do:
- any role reads;
editorwrites objects;operatorruns Identity Manager;adminchanges the console's settings.
- Sensitive changes: these need a sign-in within the last 10 minutes; otherwise the answer asks for one:
- changes to the console's own settings: trust, directories, roles, single sign-on, sign-in to other directories, reverse proxies, certificate expiry, syslog, updates, the console's ACME certificate (settings and getting one now), and uploading the console's certificate;
- restoring an earlier configuration, downloading a backup and staging a restore;
- exporting a certificate with its private key.
- Production directories: changes need the
X-Confirm-Directoryheader with the directory's name. Exports with a private key need a recent sign-in instead; a password policy check changes nothing and needs neither. - Paths:
{tree}in/api/v2/trees/{tree}/…is the directory's id. The paths still saytrees; the UI now says directory. - Errors: problem details (RFC 9457) with a stable
titlecode, such asconfirm-directoryorversion-conflict. - Host: every path but the health checks refuses a
Hostthat is not the console's (421, against DNS rebinding)./api/v2/health/liveand/readyanswer anyHost, for probes sent by IP address. - Objects: objects are addressed by GUID; DNs appear only in JSON.
- Concurrent edits: writes to an object need
If-Matchwith the ETag of the last read (*overrides). - Audit: writes are audited with attribute names, never values.
Until it is set up, the console answers only health checks and the setup API. Setup calls need the one-time token
from the log in an X-Setup-Token header:
POST /api/v2/setup/first-sign-in {host, port?, dn, password, accept?: {probeId, confirm}}
The web UI's first sign-in uses that call. For automation, the step-by-step calls are:
GET /api/v2/setup what is done so far
PUT /api/v2/setup/directory {id, name, host, port, tier}
POST /api/v2/setup/probe the directory's certificate chain
POST /api/v2/setup/trust {probeId, index, confirm} or {pem}
POST /api/v2/setup/authority {dn, password}: a tree administrator
PUT /api/v2/setup/service-account {dn, password} (optional)
PUT /api/v2/setup/login {duplicates, searchBases}
POST /api/v2/setup/finish
GET /api/v2/trees/{tree}/roots
GET /api/v2/trees/{tree}/objects?dn=… resolve a DN (any spelling)
GET /api/v2/trees/{tree}/objects/{guid} read, with an ETag
GET /api/v2/trees/{tree}/objects/{guid}/children ?offset=&count=&startAt=&kind=containers|leaves|all
GET /api/v2/trees/{tree}/objects/{guid}/rights the signed-in person's effective rights
POST /api/v2/trees/{tree}/search structured filter, or one ldapFilter expression
PATCH /api/v2/trees/{tree}/objects/{guid} {"changes": [{"op", "attribute", "values"}]}
POST /api/v2/trees/{tree}/objects/{guid}/children create: {"objectClass", "name": {"type", "value"}, "attributes"}
POST /api/v2/trees/{tree}/objects/{guid}/rename {"name"}
POST /api/v2/trees/{tree}/objects/{guid}/move {"newParent": guid}
DELETE /api/v2/trees/{tree}/objects/{guid} ?subtree=true with X-Confirm-Count: the count from …/subtree
GET /api/v2/trees/{tree}/objects/{guid}/subtree {count, capped}: what a subtree delete would remove
GET /api/v2/trees/{tree}/objects/{guid}/servers the servers holding a replica of the object, and its values on each
GET /api/v2/trees/{tree}/schema/classes[/{name}], /schema/attributes[/{name}]
Account and group tasks (Tasks.java), and task presets (Presets.java):
POST /api/v2/trees/{tree}/objects/{guid}/password {"password", "mustChange"?}
GET /api/v2/trees/{tree}/objects/{guid}/account sign-in status and restrictions (login, intruder lockout, expiry, grace, time map)
PATCH /api/v2/trees/{tree}/objects/{guid}/account the same fields, those to change
POST /api/v2/trees/{tree}/objects/{guid}/unlock clear intruder lockout
GET /api/v2/trees/{tree}/objects/{guid}/memberships a user's groups; POST {"add": [guid], "remove": [guid]}
GET /api/v2/trees/{tree}/objects/{guid}/members a group's members; POST {"add": [guid], "remove": [guid]}
GET /api/v2/trees/{tree}/presets the presets granted to the caller, with where
POST /api/v2/trees/{tree}/objects/{guid}/presets/{id} {"password", "mustChange", "unlock", "enabled", "attributes": {name: value|null}}
Group changes write both sides (the group's member and the user's groupMembership), as eDirectory expects.
Lists are sorted windows with a total:
- small results are sorted by the console;
- large ones use eDirectory's server-side sort and virtual list view.
They are split by naming attribute, because eDirectory's sort leaves out entries that lack the sort attribute.
PUT /api/v2/trees/{tree}/edir/servers/{id}/indexes/{name}/state {"state": "online|offline"}: user and auto-added indexes
POST /api/v2/trees/{tree}/edir/servers/{id}/indexes/{name}/copy {"servers": [guid]}: a user-defined index, built by limber there
GET /api/v2/trees/{tree}/edir/ldap LDAP servers and groups
GET /api/v2/trees/{tree}/edir/ldap/servers/{id} | ldap/groups/{id}
PATCH /api/v2/trees/{tree}/edir/ldap/servers/{id} | ldap/groups/{id} {"settings": {attribute: value|null}}
POST /api/v2/trees/{tree}/edir/ldap/servers/{id}/refresh | reload on the LDAP server's own host
GET /api/v2/trees/{tree}/edir/servers/{id}/audit the server's CEF audit settings
PUT /api/v2/trees/{tree}/edir/servers/{id}/audit the whole configuration, as GET gives it
DELETE /api/v2/trees/{tree}/edir/servers/{id}/audit back to eDirectory's defaults
GET /api/v2/trees/{tree}/edir/snmp
PATCH /api/v2/trees/{tree}/edir/snmp/{id} {"trapInterval"?, "trapsDisabled"?, "traps"?: {number: {active?, failure?, interval?}}}
GET /api/v2/trees/{tree}/edir/encryption encrypted attribute policies and replication (read-only)
POST /api/v2/trees/{tree}/edir/encryption/policies {"parent", "name", "attributes": [{attribute, scheme?}], "requiresSecureChannel"?}
PATCH /api/v2/trees/{tree}/edir/encryption/policies/{id} {"attributes"?, "requiresSecureChannel"?}
DELETE /api/v2/trees/{tree}/edir/encryption/policies/{id} only a policy no server uses
PUT /api/v2/trees/{tree}/edir/servers/{id}/encryption-policy {"policy": guid|null}, then limber on that server
GET /api/v2/trees/{tree}/edir/servers/{id}/replica-filter
PUT /api/v2/trees/{tree}/edir/servers/{id}/replica-filter {"classes": [{class, attributes}]}; [] clears it
POST /api/v2/trees/{tree}/security/pki/server-certificates/{guid}/export {password, scheme}: PKCS#12
POST /api/v2/trees/{tree}/security/objects/{guid}/certificates/{name}/export the same, for a user's own certificate
POST /api/v2/trees/{tree}/security/pki/servers/{guid}/certificates/import {"name", "pkcs12": base64, "password"}: only files in eDirectory's export form
POST /api/v2/trees/{tree}/security/pki/trusted-root-containers {"parent", "name"}
DELETE /api/v2/trees/{tree}/security/pki/trusted-root-containers/{guid} only an empty one
POST /api/v2/trees/{tree}/security/pki/trusted-root-containers/{guid}/roots {"certificate": PEM or base64 DER, "name"?}
DELETE /api/v2/trees/{tree}/security/pki/trusted-roots/{guid}
An export answers {fileName, pkcs12}, with the file base64-encoded. The password is at least 6 characters, and
the scheme is PBES2 unless pbes1 is asked for.
PATCH /api/v2/trees/{tree}/idm/jobs/{guid}/definition {"version", "disabled"?, "schedule"?, "servers"?, "parameters"? {name: value}, "scope"? [{dn, scope}]}
GET /api/v2/trees/{tree}/idm/jobs/{guid}/passwords ?server=: the job's named passwords on that server's engine
POST /api/v2/trees/{tree}/idm/jobs/{guid}/passwords ?server= {"name", "displayName"?, "value"}
DELETE /api/v2/trees/{tree}/idm/jobs/{guid}/passwords ?server= {"name"}
A parameter's value is checked against the job's own definition (a list is an array; an enum one of its
choices); only each changed <value> is rewritten. scope: [] removes the objects unless the job type needs
some. A password-ref parameter's value is the name of the job's named password, set with the passwords route.
POST /api/v2/trees/{tree}/security/objects/{guid}/password-check {"password"}: {passes, code, reason, policy}
GET /api/v2/trees/{tree}/security/objects/{guid}/password-policy {own, containers, loginPolicy, governing}
The check is NMAS's Password Policy Check (2.16.840.1.113719.1.39.42.100.17): nothing is set and nobody signs in.
code is NMAS's or eDirectory's (0 when it passes; -216 too short, -16000 too long, -16057 digits or special
characters the policy does not allow, and so on).
GET /api/v2/console/version {version}; admins also get {update}
PUT /api/v2/console/updates {"enabled"}
POST /api/v2/console/updates/check
GET /api/v2/console/expiry settings (secrets shown only as set), the last check's findings and errors
PUT /api/v2/console/expiry {enabled, warnDays (1-365, default 30), email?: {host, port?, security: starttls|tls|none, user?, password?, from, to: […]}, webhooks: [{url, secret?, clearSecret?}] (at most 5)}
POST /api/v2/console/expiry/check check now
POST /api/v2/console/expiry/test send a test notice to every recipient and webhook
GET /api/v2/console/syslog settings and counters: sent, dropped, waiting, last error
PUT /api/v2/console/syslog {enabled, host, port?, transport: tls|tcp|udp, facility (default authpriv)}
POST /api/v2/console/syslog/test
GET /api/v2/console/acme settings (the TSIG secret shown only as set), the current certificate, the last attempt
PUT /api/v2/console/acme {enabled, directoryUrl (https), email?, names: [...], dns: {host, port?, zone, keyName, algorithm: hmac-sha256|hmac-sha512, secret?}}
POST /api/v2/console/acme/dns-test add a test TXT record, read it back from the server, remove it
POST /api/v2/console/acme/issue get a certificate now and install it
POST /api/v2/console/certificate upload: {pkcs12: base64, password} or {certificate: PEM, key: PEM, password?}, anyName?; refused (409) while ACME is on
GET /api/v2/audit ?event (prefix)&actor&outcome&text&from&to&before (seq)&limit (≤500): {entries, more}, newest first
GET /api/v2/audit/export the same filters, every match, oldest first: ?format=csv|jsonl
GET /api/v2/audit/verify the hash chain checked end to end
GET /api/v2/config/history the configuration's versions, the current one first
GET /api/v2/config/history/{v} that version (secrets redacted) and what changed from the one before
POST /api/v2/config/history/{v}/restore make it current again, as a new version
POST /api/v2/console/backup {passphrase (12+), audit?}: the .dcbackup file
POST /api/v2/console/restore {backup: base64, passphrase}: checked and staged for the next start
GET /api/v2/console/restore {pending}: what is staged, or null; DELETE cancels it
Webhooks receive a JSON POST with these fields: event (certificates.expiring or test), subject, text,
certificates (each with kind, name, where, notAfter, days and level), console and sentAt. When a
secret is set, the X-Console-Signature header is sha256= followed by the hex HMAC-SHA256 of the body with that
secret. A webhook URL is https://; http:// is accepted only for this host.
| Prefix | Handler |
|---|---|
/api/v2/trees/{tree}/idm/… |
Idm.java, with Jobs, JobTypes, Associations, Trace, MappingTables, DriverProperties, Cache, Statistics, Versions |
/api/v2/trees/{tree}/edir/… |
Edir.java, with LdapObjects and Monitoring: partitions, replicas, servers, indexes, schema changes, LDAP servers and groups, CEF auditing, SNMP, encryption policies, replica filters |
/api/v2/trees/{tree}/security/… |
Security.java: certificates, the CA, PKCS#12 export and import, trusted roots, password and login policies, password checks |
/api/v2/directories/{id}/… |
Settings.java: a directory's tier, session limits, service account, sign-in options, roles, presets, single sign-on |
/api/v2/console/trees |
Trees.java: the directories people choose from at sign-in, added, renamed and removed |
/api/v2/console/version, /updates |
Updates.java |
/api/v2/console/expiry |
Expiry.java |
/api/v2/console/syslog |
Syslog.java |
/api/v2/console/acme, /api/v2/console/certificate |
AcmeService.java: the console's own certificate, by ACME (DNS-01) or uploaded |
/api/v2/audit, /api/v2/config/history, /api/v2/console/backup, /restore |
Records.java: the audit log, configuration history, backup and restore |
/api/v2/console/settings, /api/v2/sign-in/options, /api/v2/session/other |
OtherDirectory.java: sign-in to other directories, trusted proxies |
/api/v2/session…, /api/v2/oidc/…, /api/v2/config, /api/v2/audit/verify, /api/v2/health/live and /ready |
Server.java |
/api/v2/trust/… |
Server.java: the console's trust store |