Skip to content

REST Channel

Standard HTTP/JSON. If your app can make a GET request, it can query the directory. The REST channel comes with an OpenAPI spec, interactive docs, conditional requests, and streaming exports.

The REST channel is disabled by default. Enable it to serve the data routes:

channels.rest.enabled = true

Key endpoints:

URLWhat you get
/apiOpenAPI UI (browser) or spec (JSON/YAML via content negotiation)
/api/entries/{type}Collection search
/api/entries/{type}/{id}Single entry lookup
/api/entries/{type}/{id}/changesPer-entry change history
/api/changesGlobal change feed
/api/changes/hotMost active entries in a time window

Browse /api in a browser for interactive API docs with code samples, live testing, and schema details. Download the spec at /api.json or /api.yaml.

REST paths and OpenAPI identifiers are derived from entry type names using singular/plural normalization. Startup enforces strict uniqueness across:

  • REST paths (/api/entries/{type}, /api/entries/{type}/{id}, /api/entries/{type}/{id}/changes)
  • OpenAPI operationId values (search*, lookup*, get*Changes)
  • OpenAPI schema component names (Entry_*, SearchResponse_*)

If two configured types collide after normalization (for example user and users), startup fails before serving traffic.

OpenAPI component names are sanitized to a conservative format for code generators: ^[A-Za-z][A-Za-z0-9_]*$. Reserved tokens (for example class) are suffixed (for example class_type). If sanitization causes a component-name collision, startup fails.

Filters auto-detect format. Use whichever fits your context:

FormatDetectionExample
JSONStarts with { or [{"cn":"john"}
LDAPStarts with ((cn=john*)
FleXDefaultcn = john
SCIMFallbackcn eq "john"
Terminal window
# Spaces in filter values are URL-encoded by curl when using --data-urlencode,
# or quote the entire URL as shown here
curl "/api/entries/users?filter=department%3DEngineering%20AND%20active%3Dtrue"
ValueReturns
cn,mail,snSpecific attributes
*All user attributes
+All operational attributes
1.1No attributes (IDs only)
Terminal window
?sort=cn # Ascending
?sort=-cn # Descending
?sort=sn,-cn # Multiple keys

When include, fields, sort, or pagination size are omitted, REST uses channels.rest.default-include, channels.rest.default-fields, channels.rest.default-sort, and channels.rest.default-limit. These inherit the shared query.* defaults unless the REST channel overrides them.

Relay-style cursor pagination:

ParameterDirection
first / afterForward
last / beforeBackward
limitAlias — resolves to first or last based on cursor
Terminal window
# First page
curl "/api/entries/users?first=25"
# Next page (use endCursor from previous response)
curl "/api/entries/users?first=25&after=eyJjbiI6Impv..."

Lookup endpoints accept any identifier format. DN values must be URL-encoded in paths.

Poll efficiently with ETags:

Terminal window
# First request returns ETag
curl -I "/api/entries/users/$UUID"
# ETag: W/"abc123..."
# Subsequent requests — 304 when unchanged
curl -H 'If-None-Match: W/"abc123..."' "/api/entries/users/$UUID"

If-Modified-Since is also supported. Search responses include Cache-Control: no-store; lookup responses include Cache-Control: private, max-age=0, must-revalidate.

Query changes via the global feed (/api/changes) or per-entry (/api/entries/{type}/{id}/changes).

To find entries with the most changes in a time window, use the hot-entries ranking:

Terminal window
# Top 20 most active entries in the last 24 hours
curl "/api/changes/hot?range=24h&first=20"
# MODIFY activity for users only, sorted by most recent change
curl "/api/changes/hot?range=7d&entryType=user&type=modify&sort=-lastTimestamp&first=10&include=pageInfo"
# Page forward using endCursor from pageInfo
curl "/api/changes/hot?range=24h&first=20&after=<cursor>&include=pageInfo"
Terminal window
# Changes in the last 24 hours
curl "/api/changes?range=24h&first=50"
# MODIFY events that changed the mail attribute
curl "/api/changes?type=modify&affects=mail&since=this week"

Time ranges accept temporal references: ISO timestamps, durations, yesterday, last 3 days, etc.

View an entry at any moment:

Terminal window
curl "/api/entries/users/$ID?at=2024-01-15T10:00:00Z"
curl "/api/entries/users/$ID?at=now-1h"

Change events support three data formats. Use ?include=nodes,patch,pageInfo to select which parts to return. For count-only queries (no data fetch), use ?include=count.

Stream search results to a file by adding filename to any search request:

Terminal window
curl -OJ "/api/entries/users?filename=users.csv&fields=cn,mail,department"

In export mode, Scribe bypasses pagination and streams the full result set.

FormatExtensionNotes
CSV.csvExcel-compatible, RFC 4180
TSV.tsvTab-delimited
JSON.jsonStreaming JSON array
NDJSON.ndjsonNewline-delimited JSON
JSON-seq.json-seqRFC 7464
JSON-LD.jsonldWith @id/@type
LDIF.ldifLDAP interchange format

Exports require an explicit field list — wildcards (*, +) are not allowed. Pass format options as JSON via the export parameter:

Terminal window
# Custom delimiter and null handling
curl -OJ '/api/entries/users?filename=data.csv&fields=cn,mail&export={"delimiter":"|","nulls":"N/A"}'

See Configuration Reference for export limits, delimited format options, and all other REST settings.

Control how the API handles unknown attributes with Prefer: handling=strict (returns 400 with the unknown names) or Prefer: handling=lenient (default — ignores unknowns silently).

See Signals for metrics, Error Handling for error codes.