Skip to content

Create legal document

POST
/api/v1/admin/legal-documents
Code sample: Shell / cURL
curl --request POST \
--url http://localhost:9090/api/v1/admin/legal-documents \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "kind": "must_accept", "shortName": "example", "title": "example", "markdown": "example" }'

Create a legal document holding a draft. Nothing is shown to users until the draft is published. The kind is fixed from then on: to change it, retire the document and create another.

The short name is the document’s public address, /legal/<short-name>: lowercase letters, digits and hyphens, starting and ending with a letter or a digit, at most 64 characters, and unique among documents.

Media typeapplication/json
object
kind
required
string
Allowed values: must_accept for_information
shortName
required

Lowercase letters, digits and hyphens, starting and ending with a letter or a digit, at most 64 characters, unique among documents.

string
title
required

At most 200 UTF-16 code units. Leading and trailing spaces are removed.

string
markdown

The draft’s text, kept as written. At most 100,000 UTF-16 code units.

string

Legal document created, with its draft

Media typeapplication/json
object
legalDocument
required
object
id
required
integer format: int64
createdAt
required
string format: date-time
nullable
updatedAt
required
string format: date-time
nullable
shortName
required

The document’s public address, /legal/<short-name>.

string
kind
required

Must_accept is terms of use, which users accept; for_information is a privacy notice, shown and linked and never accepted.

string
Allowed values: must_accept for_information
title
required

The current version’s title, or the draft’s when the document was never published.

string
currentVersion
required

The current version’s number, or 0 when the document was never published.

integer
publishedAt
required

When the current version was published, or null.

string format: date-time
nullable
hasDraft
required
boolean
retired
required
boolean
retiredAt
required
string format: date-time
nullable
appliesTo
required

All_apps, the default, or selected_apps, the apps clientIds lists. A document set to selected_apps with no client ids applies to nobody.

string
Allowed values: all_apps selected_apps
clientIds
required

The apps a selected_apps document applies to; [] for all_apps, never null.

Array<integer>
draft
required

The unpublished draft, or null when the document has none.

object
title
required
string
markdown
required
string
versions
required

The published versions, oldest first.

Array<object>
object
version
required
integer
title
required
string
publishedAt
required
string format: date-time
nullable

Example

{
"legalDocument": {
"kind": "must_accept",
"appliesTo": "all_apps"
}
}

Invalid request body or parameters

Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for codes named after the sentence’s catalog key (e.g. validator.email.required). Never translated, whatever the request’s language.

string
error_description
required

A sentence for people to read: in the request’s language, from the ui_locales query parameter or else the Accept-Language header, when the server has the sentence in that language, and in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}
WWW-Authenticate
string

Bearer challenge when token transport is malformed; ordinary validation errors omit it.

Missing or invalid access token (ACCESS_TOKEN_REQUIRED, INVALID_TOKEN), or a refused DPoP proof (INVALID_DPOP_PROOF)

Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for codes named after the sentence’s catalog key (e.g. validator.email.required). Never translated, whatever the request’s language.

string
error_description
required

A sentence for people to read: in the request’s language, from the ui_locales query parameter or else the Accept-Language header, when the server has the sentence in that language, and in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}
WWW-Authenticate
string

A Bearer challenge, then a DPoP challenge naming the accepted proof algorithms, on token refusals, the error in the challenge of the scheme the token was sent with: Bearer realm="goiabada", error="invalid_token", error_description="...", DPoP realm="goiabada", algs="ES256 ...". An operation may also return a handler-level 401 without this header.

The token is valid but does not authorise this request. A caller tells the refusals apart by error_code.

INSUFFICIENT_SCOPE comes from the route’s authorisation middleware, before the handler runs: an Admin operation needs one of the scopes its route names, and an Account operation needs authserver:manage-account.

USER_CONTEXT_REQUIRED comes from the same middleware on the Account operations, which also require the token to have been issued for a user: one obtained through the client credentials grant carries no auth_time claim and is refused here.

FORBIDDEN comes from the handler, on the account endpoints that resolve a resource by id and then check it belongs to the caller, so a valid token for the wrong user reaches this rather than a 404.

CLIENT_NOT_ALLOWED comes from the route on the two Account operations only the admin console’s own client may call, deleteAccount and exportAccount. ACCOUNT_DELETION_DISABLED comes from deleteAccount while an administrator has turned off Let users delete their own account.

MANAGE_SCOPE_REQUIRED comes from the handler, on the Admin operations the administrative policy guards. Only authserver:manage creates an administrator, changes one, or changes what reaches one, so no granular scope will ever be enough: the remedy is a token holding authserver:manage, not requesting the route’s scope as for INSUFFICIENT_SCOPE. An administrator is a user, group or client holding any of the six administrative permissions (manage, admin-read, manage-users, manage-clients, manage-settings, browser-sessions), a user directly or through any of its groups, the admin console’s own client whatever it holds, and a client allowed to request the administrative scopes. A granular scope is refused here when it:

  • grants or revokes an administrative permission, directly or by moving a user into or out of a group that holds one, or deletes such a group;
  • writes to an administrator user (profile, credentials, enabled, sessions, consents, attributes, memberships, permissions, deletion), an administrative group (settings, attributes, members, permissions, deletion), or an administrator client (settings, authentication, flows, redirect URIs, sign-out redirect URIs, back-channel logout, DPoP, web origins, token settings, permissions, introspection resources, logo, deletion);
  • switches whether a client may request the administrative scopes, on or off, on any client;
  • adds the authserver resource to a client’s introspection resources;
  • reads an administrator client’s secret, or reads or sets the secret of a client listed for the authserver resource among its introspection resources;
  • sets or changes a client’s back-channel logout URI;
  • changes the email or the audit-log settings;
  • changes an administrative permission’s description. Granular scopes still read administrators. The refusal is answered after the request’s 400 and 404, writes nothing, carries the insufficient_scope challenge of the scheme the token was sent with, such as WWW-Authenticate: Bearer realm="goiabada", error="insufficient_scope", error_description="...", scope="authserver:manage", and leaves an administrator_change_refused audit record.
Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for codes named after the sentence’s catalog key (e.g. validator.email.required). Never translated, whatever the request’s language.

string
error_description
required

A sentence for people to read: in the request’s language, from the ui_locales query parameter or else the Accept-Language header, when the server has the sentence in that language, and in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}
WWW-Authenticate
string

An insufficient_scope challenge in the scheme the token was sent with, Bearer or DPoP, on every refusal but FORBIDDEN and ACCOUNT_DELETION_DISABLED, which omit it.

The request failed inside the server, most often a storage error. error_code is INTERNAL_SERVER_ERROR: no detail about the failure, only the request id an operator can find the log line by, and retrying is reasonable. Key rotation’s 500 also answers KEY_SET_INCOMPLETE, which names its cause and no retry clears.

Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for codes named after the sentence’s catalog key (e.g. validator.email.required). Never translated, whatever the request’s language.

string
error_description
required

A sentence for people to read: in the request’s language, from the ui_locales query parameter or else the Accept-Language header, when the server has the sentence in that language, and in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}