Stensul API (1.0.0)

Download OpenAPI specification:

Download Postman Collection: Download

This API uses OAuth 2.0 for authentication and adheres to the SCIM (System for Cross-domain Identity Management) protocol for user management.

Documentation Structure

This documentation is organized into the following structure:

Rate limiting

Our API implements rate limiting to ensure fair usage and prevent abuse. Specifically, we limit requests to 30 per second per IP address. This helps us maintain the stability and performance of our API by preventing any single IP address from overwhelming our servers with too many requests. Rate limiting also encourages responsible use of our API and helps protect it from potential malicious attacks.

Request origin (X-ST-Origin)

Every endpoint optionally accepts an X-ST-Origin header declaring which integration is making the call. It is used for usage metrics only — it never changes the behaviour of a request and is never returned in a response.

Accepted values: builder, figma, mcp, genstudio, unknown. When the header is absent, the origin is derived from the OAuth client that authenticated the request. An unrecognised value is ignored and the derived origin is used instead, so a malformed header never fails a call.

Additional Notes

{baseUrl} represents the URL of your Stensul instance, for example https://mycompany.stensul.com

Authentication

Obtain OAuth 2.0 Bearer tokens to authenticate requests to the Stensul API. Supports client_credentials for machine-to-machine access and authorization_code (with optional PKCE) for user-delegated access.

Get access token

Exchange credentials or an authorization code for a Bearer token. The token must be passed on all subsequent API requests.

Default token expiration: 6 hours (expressed in seconds). An API client can only use one grant type — not both.


grant_type: client_credentials

Machine-to-machine access. No Stensul user is associated with the token — only scope checks apply.

Pass client_id, client_secret, and grant_type=client_credentials. A token is issued immediately.


grant_type: authorization_code

User-delegated access. The token is bound to a specific Stensul user, so both scope checks and the user's Stensul permissions apply. This means some endpoints may return a 403 that they would not return under client_credentials (for example, copying an email requires the user to have the clone_campaign or clone_template permission).

The flow follows standard OAuth 2.0 Authorization Code:

  1. Redirect the user to the Stensul authorization page:

    GET {baseUrl}/api/v1/oauth/authorize
      ?response_type=code
      &client_id={client_id}
      &redirect_uri={redirect_uri}
      &state={random_string}
      &prompt=consent
      &code_challenge={BASE64URL(SHA256(code_verifier))}   # PKCE only
      &code_challenge_method=S256                          # PKCE only
    

    The user logs in to Stensul (if not already) and approves the authorization request.

  2. Receive the code — Stensul redirects the browser to your redirect_uri with code and state as query parameters:

    {redirect_uri}?code={authorization_code}&state={random_string}
    
  3. Exchange the code — call this endpoint with grant_type=authorization_code, client_id, client_secret, code, and redirect_uri (required if it was included in step 1).

PKCE (public clients)

PKCE (Proof Key for Code Exchange) is supported for clients configured without a secret. Use it when the client cannot securely store a client_secret (e.g. a single-page app or mobile app).

In step 1, additionally include:

  • code_challenge — BASE64URL(SHA256(code_verifier))
  • code_challenge_method — must be S256

In step 3, pass code_verifier instead of client_secret.


Authorizations:
bearerAuth
Request Body schema: application/json
grant_type
required
string
Enum: "client_credentials" "authorization_code"
client_id
required
string <uuid>
client_secret
string

Required for confidential clients (non-PKCE). Omit for PKCE clients.

redirect_uri
string

Required for authorization_code if redirect_uri was included in the authorize request.

code
string

The authorization code received at your redirect_uri. Required for authorization_code grant type.

code_verifier
string

PKCE only. The original random string whose SHA-256 hash was sent as code_challenge in the authorize request. Pass this instead of client_secret for PKCE clients.

Responses

Request samples

Content type
application/json
Example
{
  • "grant_type": "client_credentials",
  • "client_id": "1bdf2ba9-a5fa-42c5-81d3-beae2629e469",
  • "client_secret": "<client-secret>"
}

Response samples

Content type
application/json
{
  • "token_type": "Bearer",
  • "expires_in": 21600,
  • "access_token": "<access_token>"
}

Libraries

Retrieve Libraries within Stensul. A Library determines which Modules can be used to build an Email, along with the ESP configuration, branding rules, and available features. Reading Library details is typically the first step before creating Emails via the API.

Get Libraries

GET /external-api/v1/libraries

Required scope: libraries:read

This endpoint retrieves a list of libraries with the option to sort, filter and paginate the results.

Request Body

No request body parameters are required for this endpoint.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
query Parameters
filter[name]
string
Example: filter[name]=My Library

Allow filtering resource results by name.

filter[description]
string
Example: filter[description]=My Library Description

Allow filtering resource results by description.

sort
string
Example: sort=name

Allow sorting resource results. Provide a - (minus) before criteria for descending order. Allow comma-separated values.

Available values : name, created_at, updated_at

page[size]
integer
Example: page[size]=15

For paginated responses indicates the amount of resource results to be retrieved per page.

Maximum resources: 30. Default is 15.

page[number]
integer
Example: page[number]=1

For paginated responses indicates the page number to be retrieved.

fields[libraries]
string
Example: fields[libraries]=name,key,description

Specify which attributes to return for each library, separated by commas. Every attribute is returned if this parameter is not used.

Any other key is rejected with a 400. The unbracketed fields=... form is ignored and returns every attribute.

id is always returned, whether or not it is listed.

Valid attributes are: id, name, key, description, permission, tags, created_at, updated_at, created_by, updated_by.

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{}

Get a Library

GET /external-api/v1/libraries/{{libraryId}}

Required scope: libraries:read

This endpoint retrieves Library information based on the provided Library ID.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
path Parameters
libraryId
required
string
query Parameters
fields[libraries]
string
Example: fields[libraries]=name,key,description

Specify which attributes to return, separated by commas. Every attribute is returned if this parameter is not used.

Any other key is rejected with a 400. The unbracketed fields=... form is ignored and returns every attribute.

id is always returned, whether or not it is listed.

Valid attributes are: id, name, key, description, permission, tags, created_at, updated_at, created_by, updated_by.

modules and config, which this endpoint returns when the library has them, cannot be requested through this parameter and are omitted from the response whenever it is used. Omit fields[libraries] entirely to get them.

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Emails

Create, copy, and read Emails (drafts, finished, and templates) within Stensul, and update their content. Emails are assembled from Modules within a Library.

Create an Email

POST /external-api/v1/emails

Required scope: emails:write

This endpoint creates an email.

Request Body

  • library_key (text, required) - The library key. Can be obtained with the endpoint /external-api/v1/libraries endpoint.
  • name (text, required) - The email name.
  • type (text, optional) - The type of email, valid values include "draft" and "template". Default: "draft".
  • title (text, optional) - The title of the email. If not used, the Library default will be used (if set).
  • tags (array, optional) - The email tags. Tags must be available to the Library.
  • modules (array, optional) - The modules to include in the email. Modules must be available to the Library. Modules are added in the order of this array and can be repeated. Each item can be either:
    • A plain string with the module key (legacy format): "image"
    • An object with key (required), and optionally referenceEmailId + referenceModuleId to copy content from an existing email module. Both reference fields must be provided together or not at all.
  • preheader (text, optional) - The preheader of the email. If not used, the Library default will be used (if set).
  • subject_line (text, optional) - The subject line of the email. If not used, the Library default will be used (if set).
  • language (text, optional) - The email language. It must be one of the selected values on the library. If not used, the Library default will be used.
  • project_id (text, optional) - The project id the email should belong to.
  • active_variation_id (text, optional) - ID of the variation to activate on the new email. Must be one of the library's variations (see the Get Email layout endpoint's variations). Only accepted when the library selects one variation for the whole email (variations_mode: all); when omitted the library default applies.
Authorizations:
bearerAuth
query Parameters
include
string
Example: include=modules

Include related Resources. Valid resources for this endpoint are "modules".

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json
Request Body schema: application/json
library_key
string
name
string
type
string
Enum: "draft" "template"
title
string
tags
Array of strings
Array of strings or objects
preheader
string or null
subject_line
string or null
language
string or null
project_id
string
active_variation_id
string

ID of the variation to activate on the new email. Only accepted when the library selects one variation for the whole email (variations_mode: all). Omit to use the library default.

Responses

Request samples

Content type
application/json
{
  • "library_key": "my_library",
  • "name": "Test Email",
  • "type": "draft",
  • "title": "The Email Title",
  • "tags": [
    ],
  • "modules": [
    ],
  • "preheader": "The Email Preheader",
  • "subject_line": "The Subject Line",
  • "language": "en-US",
  • "project_id": "673cf6e17785702ce0dc3891"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

Get Emails

GET /external-api/v1/emails

Required scope: emails:read

This endpoint retrieves a list of emails with the option to sort, filter and paginate the results.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
query Parameters
sort
string
Example: sort=-created_at

Allow sorting resource results. Provide a - (minus) before criteria for descending order. Allow comma-separated values.

Available values: name, type, created_at, updated_at

page[number]
integer
Example: page[number]=1

For paginated responses indicates the page number to be retrieved.

page[size]
integer
Example: page[size]=20

For paginated responses indicates the amount of resource results to be retrieved per page.

Maximum resources: 30. Default is 15.

filter[name]
string

Allow filtering resource results by name.

filter[types][]
string
Example: filter[types][]=draft

Allow filtering resource results by type, available types are "draft", "finished" or "template". This filter can be added more than once to include results with different types.'

filter[library_keys][]
string
Example: filter[library_keys][]=library_1

Allow filtering results by Library Key. This filter can be added more than once to include results with different libraries.

filter[tags][]
string
Example: filter[tags][]=translation

Allow filtering by tags. This filter can be added more than once to include results with different tags.

filter[tags_match_criteria]
string
Default: "any"
Enum: "any" "all"
Example: filter[tags_match_criteria]=all

Define whether the tags filter should work as "any" or "all". For "any", only results having any of the passed tags will be retrieved. For "all", only results having all of the passed tags will be retrieved.

filter[language]
string
Example: filter[language]=en-US

Allow filtering by language code as defined by ISO 639-1 including additional language tags representing regional subtypes defined in IETF's BCP 47.

filter[has_modules_locked]
integer

Filter emails by whether their modules have been locked or not. Valid values are 0 or 1.

By default all emails will be returned.

filter[has_been_uploaded]
integer
Example: filter[has_been_uploaded]=1

Allow filtering for emails uploaded to an ESP. Valid values are 0 or 1.

By default all emails will be returned.

filter[is_archived]
integer
Example: filter[is_archived]=1

Allow filtering for archived emails. Valid values are 0 or 1.

By default all emails will be returned.

filter[project_id]
string
Example: filter[project_id]=673cf6e17785702ce0dc3891

Allow filtering resource results by project Id.

q
string
Example: q=My search terms

Allows searching for emails by Email Name, Author, Tags and Library name.

fields[campaigns]
string
Example: fields[campaigns]=name,type,tags,created_by,library

Specify which attributes to return for each email, separated by commas. Every attribute is returned if this parameter is not used.

The key is campaigns, not emails. Any other key is rejected with a 400. The unbracketed fields=... form is ignored and returns every attribute.

id is always returned, whether or not it is listed.

Valid attributes are: id, name, type, title, tags, project_id, language, preheader, subject_line, is_archived, is_exportable_to_esp, is_translatable, has_modules_locked, has_been_uploaded, has_active_proof, has_autosave_enabled, has_outdated_modules, has_translation_process_started, downloadable_as, library, images, tracking, approvals_workflow_state, modules_locked_by, original_language_email_id, public_view_url, created_at, updated_at, created_by, updated_by.

library, images, tracking, approvals_workflow_state, created_by and updated_by are objects and are returned whole. To include schedule, outputs or modules use the include parameter of the single-email endpoint instead — they are relationships, not attributes.

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{}

Render Email as HTML

GET /external-api/v1/emails/{{emailId}}/render/html

Renders the email HTML through the output generator service. The response is self-describing: encoding is utf-8 and content holds the raw HTML.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
query Parameters
colorScheme
string
Default: "light"
Enum: "light" "partial-dark" "full-dark"

Simulates how an email client renders the email in dark mode. partial-dark only inverts elements whose effective background is light; full-dark inverts every element. Colours are rewritten as inline styles on the output; nothing about the scheme is stored on the email.

header Parameters
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Render Email as PDF

GET /external-api/v1/emails/{{emailId}}/render/pdf

Renders the email as a PDF through the output generator service. The response is self-describing: encoding is base64 and content holds the base64-encoded PDF bytes.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
query Parameters
colorScheme
string
Default: "light"
Enum: "light" "partial-dark" "full-dark"

Simulates how an email client renders the email in dark mode. partial-dark only inverts elements whose effective background is light; full-dark inverts every element. Colours are rewritten as inline styles on the output; nothing about the scheme is stored on the email.

header Parameters
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Render Email as PNG

GET /external-api/v1/emails/{{emailId}}/render/png

Renders the email as a PNG through the output generator service. The response is self-describing: encoding is base64 and content holds the base64-encoded PNG bytes.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
query Parameters
colorScheme
string
Default: "light"
Enum: "light" "partial-dark" "full-dark"

Simulates how an email client renders the email in dark mode. partial-dark only inverts elements whose effective background is light; full-dark inverts every element. Colours are rewritten as inline styles on the output; nothing about the scheme is stored on the email.

header Parameters
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Get Email layout

GET /external-api/v1/emails/{{emailId}}/layout

Required scope: emails:read

This endpoint retrieves the layout of an email.

An element carries a visibility object ({"value": <bool>}, its current on/off state) only when that state can be changed — that is, only for the elements the owning module allows to be toggled. When visibility is absent the element is permanently visible: sending visibility for it leaves it visible and returns a warning. So presence of the key, not a separate flag, tells you whether hiding is possible.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Update Email content

PATCH /external-api/v1/emails/{{emailId}}/content

Required scope: emails:write

This endpoint updates the content of an email.

Custom elements

A custom element is updated by setting the values of the variables it exposes:

{
  "save_version": 12,
  "modules": [
    {
      "id": 18300748,
      "elements": [
        {
          "id": 1349096506,
          "type": "custom",
          "content": { "variables": [ { "id": 618662, "value": "right" } ] }
        }
      ]
    }
  ]
}

Read the element first: the Get Email layout endpoint reports each variable's id, name, type and current value under content.variables, and what may be done to it under guardrails.variables, keyed by the same id.

Three things to know before calling it:

  • Values only, never markup. The element's htmlCode, placeholderCode and css cannot be set through this endpoint and are ignored if sent. Rendering is a server-owned {{name}} -> value substitution, so the element's guardrails hold for API writes exactly as they do in the builder.
  • Partial. Only the variables named in the payload change.
  • Per-variable, not per-request. Each value is checked against the persisted element - editability, options, color palette, hyperlink validations. A rejected variable keeps its previous value and produces a warning; the other variables and the rest of the email still save, and the response is still 200. Read data.warnings to find out what did not apply.

Custom elements are copied by value into a module and again into an email, so a write here changes this email only - it does not edit the module or the library's element definition.

A text link carries its own URL tracking on the link chunk itself, under content[].content[].text.link.url_tracking_parameters/url_tracking_disabled — not under the element's url_tracking_parameters/url_tracking_disabled, which only button and image elements use. See TextLink in the schema for the shape.

Unlike button/image values, a text link's tracking is stored then audited, never rejected pre-storage: whatever is sent is written into the link, and any value that fails the library's rules comes back under url_tracking.issues with a link object (index, href) identifying which anchor it is, since a text element can hold several.

Writing a text element's content replaces its links wholesale — there is no partial per-link update. To keep a link's existing tracking through an unrelated edit (a style change, a word fixed elsewhere in the same element), echo back the content the Get Email layout endpoint returned for that element, tracking fields included, rather than reconstructing it from scratch.

data-description, when set in the builder, is preserved on write but not yet exposed or settable through this endpoint — a fast-follow.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json
Request Body schema: application/json
active_variation_id
string

ID of the variation to activate on the email. Must be one of the IDs returned by the Get Email layout endpoint under variations. Optional — omit to leave the current selection unchanged. null is rejected. Only accepted when the library selects one variation for the whole email (variations_mode: all on the Get Email layout endpoint); libraries with variations_mode: individual select per module via modules.*.variation_id instead. The selection is also propagated to every module's stored variation, which is what rendering resolves.

Array of objects (Module)

Modules to update. Optional — omit when only changing active_variation_id.

object

Campaign-level URL tracking values, as parameter name: value — chosen once for the whole email. Every value must satisfy the matching definition in guardrails.url_tracking.url_tracking_parameters.campaign from the Get Email layout endpoint.

A value the library does not accept is refused, not stored: the previous value (or the library default) stands, and the refusal comes back under url_tracking.issues together with the value that was rejected. Omitted parameters keep whatever they already had.

save_version
integer or null >= 0

Optimistic-concurrency token: the save_version returned by the Get Email layout endpoint at the time the content was read. When the emails.SAVE_VERSION_CHECK feature flag is enabled and this value no longer matches the stored version, the update is rejected with 409 (error_code: save_version_conflict) instead of overwriting content saved in the meantime — re-read the layout and verify the changes are still applicable. Omit (or send null) to skip the conflict check.

Responses

Request samples

Content type
application/json
{
  • "active_variation_id": "6a0370f838ad31136e0b6528",
  • "modules": [
    ],
  • "url_tracking": {
    },
  • "save_version": 7
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

Delete an Email module

DELETE /external-api/v1/emails/{{emailId}}/modules/{{moduleId}}

Required scope: emails:write

Removes a module, with all of its elements, from an email. This is destructive and cannot be undone.

Deleting a module is deliberately a separate call: PATCH /external-api/v1/emails/{{emailId}}/content is a merge, so modules that are absent from its payload are preserved. Omitting a module there never removes it — the only way to remove one is to name it in this endpoint.

moduleId is the module instance id, i.e. the id reported for each module by the /external-api/v1/emails/{{emailId}}/layout endpoint. The remaining modules keep their order, their ids and their content, so element references held for other modules stay valid.

Rejected requests

  • 403 — the email has its modules locked, or the module is the library's fixed header or footer.
  • 404 — the email does not exist, or it has no module with that instance id.
  • 409 — the email is currently being edited by another user in the builder, or the deletion was refused because the email had been written since it was read (error_code: save_version_conflict). The latter covers both a stale save_version sent by the caller and a write that landed while this request was being served: the removal is persisted as a conditional update, so a lost race is reported rather than overwriting the other writer. Nothing is deleted in either case.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
moduleId
required
integer
Example: 18300748

Module instance id, as reported by the Get Email layout endpoint.

query Parameters
save_version
integer >= 0
Example: save_version=7

Optimistic-concurrency token: the save_version returned by the Get Email layout endpoint at the time the email was read. When the emails.SAVE_VERSION_CHECK feature flag is enabled and this value no longer matches the stored version, the deletion is rejected with 409 (error_code: save_version_conflict) instead of removing a module whose content may have changed in the meantime — re-read the layout and verify the module should still be removed. Omit to skip the check. Sent as a query parameter because bodies on DELETE are not carried reliably by every client or proxy.

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{}

Copy an Email

POST /external-api/v1/emails/{{emailId}}/copies

Required scope: emails:write

This endpoint copies an existing email.

Optional fields will inherit the value of the original email unless they are specified in the payload.

Note — authorization_code grant only: When the request is made with an authorization_code token, the associated Stensul user's permissions are enforced in addition to the scope check. The user must have the clone_campaign (for drafts) or clone_template (for templates) permission, and duplicate_email_between_libraries if copying across libraries. These checks do not apply to client_credentials tokens.

Request Body

  • name (text, required) - The email name.
  • library_key (text, optional) - Override the library key. Can be obtained with the endpoint /external-api/v1/libraries endpoint.
  • type (text, optional) - Override the type of email, valid values include "draft" and "template".
  • title (text, optional) - Override the title of the original email.
  • tags (array, optional) - Override the email tags of the original email. Tags must be available to the Library.
  • preheader (text, optional) - Override the preheader of the original email.
  • subject_line (text, optional) - Override the subject line of the original email.
  • language (text, optional) - Override the email language. It must be one of the selected values on the library.
  • project_id (text, optional) - Override the project id the email should belong to.
Authorizations:
bearerAuth
path Parameters
emailId
required
string
query Parameters
include
string
Example: include=modules

Include related Resources. Valid resources for this endpoint are "modules".

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json
Request Body schema: application/json
object

Responses

Request samples

Content type
application/json
{
  • "name": "Test Email",
  • "library_key": "my_library",
  • "type": "template",
  • "title": "The Email Title",
  • "tags": [
    ],
  • "preheader": "The Email Preheader",
  • "subject_line": "The Subject Line",
  • "language": "en-US",
  • "project_id": "673cf6e17785702ce0dc3891"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

Get an Email

GET /external-api/v1/emails/{{emailId}}

Required scope: emails:read

This endpoint retrieves email information based on the provided email ID.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
query Parameters
include
string
Example: include=outputs,schedule,modules

Include related Resources. Valid resources are "outputs", "schedule" and "modules". Multiple resources can be separated by commas.

fields[campaigns]
string
Example: fields[campaigns]=name,type,tags,created_by,library

Specify which attributes to return, separated by commas. Every attribute is returned if this parameter is not used.

The key is campaigns, not emails. Any other key is rejected with a 400. The unbracketed fields=... form is ignored and returns every attribute.

id is always returned, whether or not it is listed. Resources requested through include are not affected by this parameter.

Valid attributes are: id, name, type, title, tags, project_id, language, preheader, subject_line, is_archived, is_exportable_to_esp, is_translatable, has_modules_locked, has_been_uploaded, has_active_proof, has_autosave_enabled, has_outdated_modules, has_translation_process_started, downloadable_as, library, images, tracking, approvals_workflow_state, modules_locked_by, original_language_email_id, public_view_url, created_at, updated_at, created_by, updated_by.

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Update Email settings

PATCH /external-api/v1/emails/{{emailId}}

Required scope: emails:write

This endpoint updates the email's own settings: its name, title, subject line and preheader. Module content is updated with PATCH /external-api/v1/emails/{{emailId}}/content instead.

Only the fields present in the request body are written; anything omitted is left as it is. Sending an explicit null or "" for title, subject_line or preheader clears that field. At least one of name, title, subject_line or preheader is required.

title, subject_line and preheader must be enabled for the email's library, and a library may cap their length below the 255-character maximum or mark the subject line or preheader as required. A value that breaks one of those rules is rejected with 422 and the library's own limit is named in the error.

Authorizations:
bearerAuth
path Parameters
emailId
required
string
header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json
Request Body schema: application/json
non-empty
name
string <= 255 characters

The email's name. Always available, and cannot be set to an empty value.

title
string or null <= 255 characters

The email's title. Requires the library to have the title field enabled. Send null or "" to clear it.

subject_line
string or null <= 255 characters

The email's subject line. Requires the library to have the subject line enabled, and must fit the library's maximum length. Send null or "" to clear it, unless the library marks the subject line as required.

preheader
string or null <= 255 characters

The email's preheader. Requires the library to have the preheader enabled, and must fit the library's maximum length. Send null or "" to clear it, unless the library marks the preheader as required.

save_version
integer or null >= 0

Optimistic-concurrency token: the save_version the email was read at. When the emails.SAVE_VERSION_CHECK feature flag is enabled and this value no longer matches the stored version, the update is rejected with 409 (error_code: save_version_conflict) instead of overwriting a change saved in the meantime. Omit (or send null) to skip the conflict check.

Responses

Request samples

Content type
application/json
{
  • "name": "Q3 Product Launch Announcement",
  • "title": "Product Launch",
  • "subject_line": "Meet the new Acme Widget",
  • "preheader": "The upgrade you have been waiting for is here.",
  • "save_version": 7
}

Response samples

Content type
application/json
{}

Images

Upload images to a Stensul Email, or to the shared Studio module directory. Images can be provided as binary file uploads or as remote URLs.

Upload image files for an Email or for Studio modules

Required scope: images:write

This endpoint allows multiple image uploads. Up to 5 images can be uploaded at a time using multipart/form-data.

Images can be provided either as binary file uploads (file) or as remote URLs (url). Exactly one of these must be present; they cannot be combined in the same request.

type selects where the images are stored:

  • email (default) — the target email's own folder. email_id is required.
  • studio — the directory shared by every Studio module, so the image can be used as the source of an image element in POST /external-api/v1/modules. email_id must be omitted, and each returned file carries the path it was stored at, to be sent as that source. Requires the modules:images:write scope, and the authorizing user must be allowed to manage Studio modules.
Authorizations:
bearerAuth
Request Body schema: multipart/form-data
required
One of
object (File or URL)

Exactly one of file or url must be present; they cannot be combined.

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Generate a single-use signed upload URL for an Email

Returns a short-lived, single-use signed URL that an unauthenticated client can use to upload a single image to the given Email. Authorization is enforced here and bound into the URL's signature, so the URL cannot be retargeted to another Email.

Authorizations:
bearerAuth
Request Body schema: application/json
required
email_id
required
string

Email ID the eventual upload will be associated with

count
integer [ 1 .. 5 ]
Default: 1

How many images this single link should accept, uploaded together in one POST. Bound into the signature so it cannot be raised by tampering. Defaults to 1.

labels
Array of strings <= 5 items [ items <= 60 characters ]

Optional ordered per-slot guidance labels (e.g. ["Top image","Middle image"]) shown on the browser upload page so the user knows which image goes where. Position i maps to the i-th uploaded image. Bound into the signature.

Responses

Request samples

Content type
application/json
{
  • "email_id": "string",
  • "count": 1,
  • "labels": [
    ]
}

Response samples

Content type
application/json
{}

Retrieve the result of a signed image upload by upload_id

Returns the server-generated filename of an image uploaded via a single-use signed URL, correlated by the upload_id (nonce) returned from images/upload-url. Because the upload happens out-of-band (a browser POSTs directly to the signed URL), the API client never sees that response; poll this endpoint after the user uploads. Returns status: pending until the upload completes (or if the result has expired).

Authorizations:
bearerAuth
query Parameters
email_id
required
string
upload_id
required
string

Responses

Response samples

Content type
application/json
{
  • "status": "pending",
  • "email_id": "string",
  • "files": [
    ],
  • "count": 0
}

Render the browser upload page for a single-use signed URL

Returns a self-contained HTML page that lets a human pick an image and upload it to the Email bound in the signed URL. Same URL and signature as the POST upload; the GET only renders the page and does not consume the single-use nonce. No OAuth token is required.

query Parameters
email_id
required
string
nonce
required
string
count
integer

Max images this link accepts (1–5). Part of the signed query string.

labels
Array of strings

Ordered per-slot guidance labels for the upload page. Part of the signed query string.

expires
required
integer
signature
required
string

Responses

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

Upload one or more images using a single-use signed URL

Uploads one or more images (sent under the multipart field "file[]") using a URL previously minted via images/upload-url. The number allowed is the signed count. No OAuth token is required: the request is authorized by the URL signature and its single-use nonce. The target Email is taken from the signed query string.

query Parameters
email_id
required
string
nonce
required
string
count
integer

Max images this link accepts (1–5). Part of the signed query string.

labels
Array of strings

Ordered per-slot guidance labels for the upload page. Part of the signed query string.

expires
required
integer
signature
required
string
Request Body schema: multipart/form-data
required
file
required
Array of strings <binary> [ 1 .. 5 ] items [ items <binary > ]

One or more images, sent under the multipart field "file[]". The number allowed is bound into the signed URL's count.

Responses

Response samples

Content type
application/json
{
  • "email_id": "string",
  • "files": [
    ],
  • "count": 1
}

Modules

Manage Stensul Modules

Create a Module

POST /external-api/v1/modules

Creates a standalone module (draft, Studio type) with the given structure.

Request Body

  • name (string, required) — Module name. Must be unique across all non-deleted modules.
  • style (object, optional) — Module-level style.
    • background_color (string, optional) — Hex color code (e.g. #FFFFFF).
    • background_image (string, optional) — Background image reference, not a URL. Sending the key at all (an empty string included) marks the module as having background-image intent: the Studio background-image editor plugins are enabled for it, even before a real image is set.
    • border_radius (object, optional) — { value: number, unit: "px" }.
    • border_top_width / border_right_width / border_bottom_width / border_left_width (object, optional) — { value: number, unit: "px" }.
    • border_top_style / border_right_style / border_bottom_style / border_left_style (solid | dashed | dotted | double | hidden). Defaults to solid when a width greater than 0 is given without a style.
    • border_top_color / border_right_color / border_bottom_color / border_left_color (hex string). Defaults to #000000 when a width greater than 0 is given without a color.
  • rows (array, required, min 1) — Ordered list of rows.
    • style (object, optional) — Row container style.
      • background_color (string, optional) — Hex color.
      • padding_top / padding_right / padding_bottom / padding_left (object, optional) — { value: number, unit: "px" }.
      • border_top_width / border_right_width / border_bottom_width / border_left_width (object, optional) — { value: number, unit: "px" }.
      • border_top_style / border_right_style / border_bottom_style / border_left_style (solid | dashed | dotted | double | hidden). Defaults to solid when a width greater than 0 is given without a style.
      • border_top_color / border_right_color / border_bottom_color / border_left_color (hex string). Defaults to #000000 when a width greater than 0 is given without a color.
    • columns (array, required, min 1) — Ordered list of columns within the row.
      • style (object, optional) — Column container style.
        • width (object, optional) — Percentage width: { value: number, unit: "%" }. Only the % unit is supported. When omitted, columns are distributed equally (e.g. two columns → 50%/50%).
        • background_color (string, optional) — Hex color.
        • padding_top / padding_right / padding_bottom / padding_left (object, optional) — { value: number, unit: "px" }.
        • border_radius (object, optional) — { value: number, unit: "px" }.
        • border_top_width / border_right_width / border_bottom_width / border_left_width (object, optional) — { value: number, unit: "px" }.
        • border_top_style / border_right_style / border_bottom_style / border_left_style (solid | dashed | dotted | double | hidden). Defaults to solid when a width greater than 0 is given without a style.
        • border_top_color / border_right_color / border_bottom_color / border_left_color (hex string). Defaults to #000000 when a width greater than 0 is given without a color.
      • elements (array, optional) — Ordered list of elements within the column. Omit it or send [] to create an empty column.
        • type (string, required) — Element type: text, button, image, or divider.

        • visibility (boolean, optional) — Whether the element is visible. Default: true.

        • style (object, optional) — Element style. Available fields depend on element type:

          • All types: background_color (hex string), padding_top / padding_right / padding_bottom / padding_left ({ value, unit }).
          • text: font_size ({ value, unit }), font_family (string), font_weight (normal | 100–900), color (hex string), text_align (left | center | right | justify), letter_spacing ({ value: number, unit: "em" | "px" }) — always stored as em; when px is provided it is converted using the element font size as base, line_height ({ value: number, unit: "%" }) — stored as (value - 100)% internally (e.g. { value: 120, unit: "%" } → "20%").
          • button: font_size ({ value, unit }), font_family (string), font_weight (normal | 100–900), color (hex string), width ({ value, unit }), height ({ value: number | "auto", unit }) — height.value accepts a positive number or "auto", letter_spacing ({ value: number, unit: "em" | "px" }) — always stored as em; when px is provided it is converted using the element font size as base, line_height ({ value: number, unit: "%" }) — stored as (value - 100)% internally, border_radius ({ value: number, unit: "px" }), border_top_width / border_right_width / border_bottom_width / border_left_width ({ value: number, unit: "px" }), border_top_style / border_right_style / border_bottom_style / border_left_style (solid | dashed | dotted | double | hidden) — defaults to solid when a width greater than 0 is given without a style, border_top_color / border_right_color / border_bottom_color / border_left_color (hex string) — defaults to #000000 when a width greater than 0 is given without a color, button_padding_top / button_padding_right / button_padding_bottom / button_padding_left ({ value, unit }) — inner padding applied to the button itself (container padding uses the common padding_* fields), align (left | center | right) — horizontal alignment within the column, defaults to center.
          • image: align (left | center | right) — horizontal alignment within the column, width ({ value, unit }), height ({ value: number | "auto", unit }) — height.value accepts a positive number or "auto".
          • divider: align (left | center | right) — horizontal alignment within the column. Defaults to center.

          align applies to image, button and divider; text elements use text_align instead. Button and divider default to center when omitted.

        • content — Rich-text content for text and button (array of content blocks); image metadata object for image; omitted for divider.

        • link (object, optional, button only) — { url: string, title: string }.

Content blocks (text / button)

Each content block is an object with a type field:

  • paragraph / heading_1 … heading_6 — requires a content array of inline chunks.
  • unordered_list / ordered_list — requires an items array.

Each inline chunk can have a text object ({ content, link }) and a style object ({ bold, italic, underline, strikethrough, color }).

Image content object

  • source (string, optional) — Either an image URL, or the path returned by POST /external-api/v1/images with type=studio (e.g. customer/modules/studio/689d2b3630861-17551306781988.jpg).
  • source_mobile (string, optional) — Same as source, for the mobile image.
  • alt (string, optional) — Alt text.
  • href (string, optional) — Link URL.
Authorizations:
bearerAuth
header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json
Request Body schema: application/json
required
name
required
string <= 255 characters
object
required
Array of objects non-empty

Responses

Request samples

Content type
application/json
{
  • "name": "Hero Module",
  • "style": {
    },
  • "rows": [
    ]
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

SCIM - User Provisioning

Create, read, update, and delete Stensul user accounts using the SCIM 2.0 protocol. Also supports assigning users to Roles and granting Library access (entitlements).

Get a user resource

GET /external-api/scim/v2/Users/{userId}

Required scope: users:read

This endpoint retrieves user information based on the provided user ID.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
path Parameters
userId
required
string
query Parameters
attributes
string
Example: attributes=userName,name,active

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. userName, name) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:User:userName). Selecting individual sub-attributes (e.g. name.givenName) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=groups,entitlements

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. name.givenName) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:User:groups). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{}

Update a user

PUT /external-api/scim/v2/Users/{userId}

Required scope: users:write

This endpoint allows you to update the details of a user.

For security reasons password cannot be set via API.

Request Body

  • schemas (array, required): An array of schema URLs.

  • userName (string, required): The username of the user.

  • name (object, required): The name of the user, including given name and family name.

    • givenName (string, required): The given name of the user.

    • familyName (string, required): The family name of the user.

  • externalId (string): The external ID of the user.

  • active (boolean): Indicates whether the user is active.

  • emails (array of objects, optional): Included for compatibility with other SCIM implementations. Stensul uses userName as the user's email address; this field is ignored if userName is present.

    • value (string): The email address.

    • type (string): The type of email (e.g. work).

    • primary (boolean): Indicates whether this is the primary email.

  • groups (array, required): An array of groups that the user belongs to.

    • value (string, required): The id of the group.
  • entitlements (array, required): An array of library permissions the user has access to.

    • value (string, required): The name of the permission.
Authorizations:
bearerAuth
path Parameters
userId
required
string
query Parameters
attributes
string
Example: attributes=userName,name,active

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. userName, name) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:User:userName). Selecting individual sub-attributes (e.g. name.givenName) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=groups,entitlements

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. name.givenName) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:User:groups). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json
Request Body schema:
id
string
object
userName
string
object
active
boolean
Array of objects

Included for compatibility with other SCIM implementations. Stensul uses userName as the user's email address; this field is ignored if userName is present.

Array of objects
Array of objects
schemas
Array of strings

Responses

Request samples

Content type
{
  • "schemas": [
    ],
  • "userName": "johndoe@example.com",
  • "name": {
    },
  • "externalId": "some-unique-id",
  • "active": true,
  • "emails": [
    ],
  • "groups": [
    ],
  • "entitlements": [
    ]
}

Response samples

Content type
application/scim+json
{
  • "id": "663a829c778347154f045a7c",
  • "externalId": "some-unique-id",
  • "meta": {},
  • "userName": "johndoe@example.com",
  • "name": {
    },
  • "active": true,
  • "emails": [
    ],
  • "groups": [],
  • "entitlements": [
    ],
  • "schemas": [
    ]
}

Delete a user

DELETE /external-api/scim/v2/Users/{userId}

Required scope: users:write

This endpoint is used to delete a specific user by their ID.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
path Parameters
userId
required
string
header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
text/plain
null

Update some user's fields

PATCH /external-api/scim/v2/Users/{userId}

Required scope: users:write

This endpoint is used to update a specific user's information using the SCIM (System for Cross-domain Identity Management) protocol.

Request Body

  • schemas (array of strings, required): An array of URNs that indicate the schema used for the request.

  • Operations (array of objects, required): An array of operations to be performed on the user's information.

    • op (string, required): The operation to be performed, e.g., "replace", "add" or "remove".

    • value (object, required): The updated value for the specified attribute.

      • active (boolean): Indicates whether the user is active or not.

      • userName (string): The username of the user.

      • externalId (string): The unique identifier for the user outside Stensul.

      • groups (array of objects): An array of groups to which the user belongs.

        • value (string, required): The unique identifier of the group.
      • entitlements (array, required): An array of library permissions the user has access to.

        • value (string, required): The name of the permission.
    • path (string, required if "op" is "add" or "remove"): The path of the attribute to be updated, e.g., "name.givenName".

    • value (string, required): The updated value for the specified attribute.

Authorizations:
bearerAuth
path Parameters
userId
required
string
query Parameters
attributes
string
Example: attributes=userName,name,active

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. userName, name) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:User:userName). Selecting individual sub-attributes (e.g. name.givenName) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=groups,entitlements

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. name.givenName) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:User:groups). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json
Request Body schema: application/scim+json
schemas
Array of strings
Array of objects

Responses

Request samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "Operations": [
    ]
}

Response samples

Content type
application/json
{
  • "schemas": [
    ],
  • "id": "68cac6e3d58975f2f40595a6",
  • "meta": {},
  • "userName": "johndoe@example.com",
  • "externalId": "externalId1",
  • "active": true,
  • "name": {
    },
  • "emails": [
    ],
  • "groups": [],
  • "entitlements": [
    ]
}

Create a user

POST /external-api/scim/v2/Users

Required scope: users:write

This endpoint is used to create a new user in the system.

For security reasons passwords cannot be set via API, upon first login the user will be forced to set a new password.

Request Body

  • schemas (array of strings, required): An array of strings indicating the names of the SCIM schemas supported.

  • externalId (string, optional): An optional Id used to identify the user in a system other than Stensul.

  • userName (string, required): Email used to identify the user in Stensul.

  • name (object, required): The user's name object containing the given name and family name.

    • givenName (string, required): The user's given name.

    • familyName (string, required): The user's family name.

  • active (boolean): Indicates whether the user is active.

  • emails (array of objects, optional): Included for compatibility with other SCIM implementations. Stensul uses userName as the user's email address; this field is ignored if userName is present.

    • value (string): The email address.

    • type (string): The type of email (e.g. work).

    • primary (boolean): Indicates whether this is the primary email.

  • groups (array of objects, required): An array of group objects that the user belongs to.

    • value (string, required): The identifier of the group.
  • entitlements (array, required): An array of library permissions the user has access to.

    • value (string, required): The name of the permission.
Authorizations:
bearerAuth
query Parameters
attributes
string
Example: attributes=userName,name,active

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. userName, name) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:User:userName). Selecting individual sub-attributes (e.g. name.givenName) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=groups,entitlements

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. name.givenName) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:User:groups). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json
Request Body schema: application/scim+json
schemas
required
Array of strings
userName
required
string
required
object
Array of objects

Included for compatibility with other SCIM implementations. Stensul uses userName as the user's email address; this field is ignored if userName is present.

active
required
boolean
externalId
string
Array of objects
Array of objects

Responses

Request samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "externalId": "some-unique-id",
  • "userName": "johndoe@example.com",
  • "name": {
    },
  • "active": true,
  • "emails": [
    ],
  • "groups": [
    ],
  • "entitlements": [
    ]
}

Response samples

Content type
application/json
{
  • "schemas": [
    ],
  • "id": "68cac6e3d58975f2f40595a6",
  • "meta": {},
  • "userName": "johndoe@example.com",
  • "externalId": "externalId1",
  • "active": true,
  • "name": {
    },
  • "emails": [
    ],
  • "groups": [],
  • "entitlements": [
    ]
}

Get all user resources

GET /external-api/scim/v2/Users

Required scope: users:read

This endpoint retrieves a list of users with the ability to paginate the results based on the filter criteria.

Request Body

  • Method: GET

  • URL: {baseUrl}/external-api/scim/v2/Users

  • Query Parameters:

    • filter (string, optional): The filter criteria for retrieving users.

    • startIndex (integer, optional): The index of the first result to return.

    • count (integer, optional): The number of results to return.

    • sortBy (string, optional): The attribute to sort the results by. Supported values are "id", "externalId", "meta.created", "meta.lastModified", "userName", "name.familyName" and "name.givenName".

    • sortOrder (string, optional): The order to sort the results in. Allowed values are "ascending" or "descending".

Authorizations:
bearerAuth
query Parameters
startIndex
integer
count
integer
Example: count=10
sortBy
string
Enum: "id" "userName" "externalId" "meta.created" "meta.lastModified" "name.familyName" "name.givenName"
Example: sortBy=userName

The attribute to sort the results by. Supported values are "id", "externalId", "meta.created", "meta.lastModified", "userName", "name.familyName" and "name.givenName".

sortOrder
string
Enum: "ascending" "descending"
Example: sortOrder=ascending

The order to sort the results in. Allowed values are "ascending" or "descending".

filter
string
Example: filter=userName eq "bob@example.com"

Filter results by a specific word or phrase. Filter values are case-sensitive.

Note: You must URL-encode the + character (%2B) if you include it in the filter.

Example: userName eq "bob@example.com" or userName eq "alice@example.com"

attributes
string
Example: attributes=userName,name,active

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. userName, name) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:User:userName). Selecting individual sub-attributes (e.g. name.givenName) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=groups,entitlements

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. name.givenName) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:User:groups). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{}

SCIM - Group Provisioning

Create, read, update, and delete Stensul Roles using the SCIM 2.0 protocol. Roles control what users can do within Stensul and which Libraries they can access.

Get all group resources

GET /external-api/scim/v2/Groups

Required scope: roles:read

This endpoint retrieves a list of groups with the ability to paginate the results based on the filter criteria.

Request Body

  • Method: GET

  • URL: {baseUrl}/external-api/scim/v2/Groups

  • Query Parameters:

    • filter (string, optional): The filter criteria for retrieving groups. Supported fields are "id", "displayName" and "externalId". "members" filtering is not supported. Filter values are case-sensitive.

    • startIndex (integer, optional): The index of the first result to return.

    • count (integer, optional): The number of results to return.

    • sortBy (string, optional): The attribute to sort the results by. Supported values are "id", "displayName", "meta.created", "meta.lastModified".

    • sortOrder (string, optional): The order to sort the results in. Allowed values are "ascending" or "descending".

Authorizations:
bearerAuth
query Parameters
startIndex
integer

The index entry by which to begin the list of returned results.

count
integer
Example: count=10

Limit the number of results returned in a single response. By default, the system returns a list of 100 users.

filter
string
Example: filter=displayName eq "admin"

Filter results by a specific word or phrase. Filter values are case-sensitive.

Supported filterable fields: id, displayName, externalId.

Note: members filtering is not supported and will return an error.

Supported operators: eq, ne, co, sw, ew, pr, gt, ge, lt, le.

Logical operators and, or, and not (...) are supported.

Examples:

  • displayName eq "admin"
  • displayName co "admin"
  • externalId eq "okta-group-123"
  • displayName eq "admin" and externalId pr
sortBy
string
Enum: "id" "displayName" "meta.created" "meta.lastModified"
Example: sortBy=displayName

The attribute to sort the results by. Supported values are "id", "displayName", "meta.created", "meta.lastModified".

sortOrder
string
Enum: "ascending" "descending"
Example: sortOrder=ascending

The order to sort the results in. Allowed values are "ascending" or "descending".

attributes
string
Example: attributes=displayName

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. displayName, members) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:displayName). Selecting individual sub-attributes (e.g. members.value) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=members

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. members.display) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:members). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{}

Create a group

POST /external-api/scim/v2/Groups

Required scope: roles:write

This endpoint is used to create a new group in the system.

Request Body

  • schemas (array of strings, required): An array of strings indicating the names of the SCIM schemas supported.

  • displayName (string, required): Group name.

  • members (array of objects, optional): An array of user objects.

    • value (string, required): The identifier of the user.
Authorizations:
bearerAuth
query Parameters
attributes
string
Example: attributes=displayName

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. displayName, members) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:displayName). Selecting individual sub-attributes (e.g. members.value) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=members

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. members.display) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:members). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json
Request Body schema: application/scim+json
schemas
Array of any
Default: ["urn:ietf:params:scim:schemas:core:2.0:Group"]
Items Value: "urn:ietf:params:scim:schemas:core:2.0:Group"
displayName
string
Array of objects

Responses

Request samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "displayName": "SCIM Group",
  • "members": [
    ]
}

Response samples

Content type
application/scim+json
{}

Update a group

PUT /external-api/scim/v2/Groups

Required scope: roles:write

This endpoint allows you to update the details of a group.

Request Body

  • schemas (array, required): An array of schema URLs.

  • displayName (string, required): The name of the group.

  • members (array, optional): An array of members of the group.

    • value (string, required): The id of the user.
Authorizations:
bearerAuth
path Parameters
groupId
required
string
query Parameters
attributes
string
Example: attributes=displayName

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. displayName, members) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:displayName). Selecting individual sub-attributes (e.g. members.value) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=members

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. members.display) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:members). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json
Request Body schema: application/scim+json
schemas
Array of any
Default: ["urn:ietf:params:scim:schemas:core:2.0:Group"]
Items Value: "urn:ietf:params:scim:schemas:core:2.0:Group"
displayName
string
Array of objects

Responses

Request samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "displayName": "SCIM Group",
  • "members": [
    ]
}

Response samples

Content type
application/scim+json
{}

Update a group's field

PATCH /external-api/scim/v2/Groups/{groupId}

Required scope: roles:write

This endpoint is used to update a specific group's information using the SCIM (System for Cross-domain Identity Management) protocol.

Request Body

  • schemas (array of strings, required): An array of URNs that indicate the schema used for the request.

  • Operations (array of objects, required): An array of operations to be performed on the group's information.

    • op (string, required): The operation to be performed, e.g., "replace", "add" or "remove".

    • value (object, required): The updated value for the specified attribute.

      • displayName (string): The name of the group.

      • members (array of objects): An array of users for the group.

        • value (string, required): The unique identifier of the user.
    • path (string, required if "op" is "add" or "remove"): The path of the attribute to be updated, e.g., "members".

    • value (string, required): The updated value for the specified attribute.

Authorizations:
bearerAuth
path Parameters
groupId
required
string
query Parameters
attributes
string
Example: attributes=displayName

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. displayName, members) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:displayName). Selecting individual sub-attributes (e.g. members.value) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=members

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. members.display) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:members). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json
Request Body schema: application/scim+json
object

Responses

Request samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "Operations": [
    ]
}

Response samples

Content type
application/scim+json
{}

Get a group resource

GET /external-api/scim/v2/Groups/{groupId}

Required scope: roles:read

This endpoint retrieves information about a specific group identified by the groupId.

Request Body

No request body is required for this endpoint.

Authorizations:
bearerAuth
path Parameters
groupId
required
string
query Parameters
attributes
string
Example: attributes=displayName

A comma-separated list of attribute names to return in the response. id, meta, and schemas are always returned.

Attribute names can be top-level (e.g. displayName, members) or URN-qualified (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:displayName). Selecting individual sub-attributes (e.g. members.value) is not supported. Unknown attribute names are ignored.

excludedAttributes
string
Example: excludedAttributes=members

A comma-separated list of attribute names to exclude from the response.

Sub-attributes can be referenced using dot notation (e.g. members.display) or a URN-qualified name (e.g. urn:ietf:params:scim:schemas:core:2.0:Group:members). Unknown attribute names are ignored.

header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{}

Delete a group

DELETE /external-api/scim/v2/Groups/{groupId}

Required scope: roles:write

This endpoint is used to delete a specific group by its ID.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
path Parameters
groupId
required
string
header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
text/plain
null

SCIM - Schemas

Retrieve the SCIM 2.0 schema definitions that describe the attributes supported for User and Group resources within Stensul.

User

GET /external-api/scim/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:User

Required scope: users:read

This endpoint retrieves the schema for the User resource in the SCIM API.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "id": "urn:ietf:params:scim:schemas:core:2.0:User",
  • "meta": {},
  • "name": "User",
  • "description": "User resource.",
  • "attributes": [
    ]
}

Group

GET /external-api/scim/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:Group

Required scope: roles:read

This endpoint retrieves the schema for the SCIM group resource.

Request Body

This endpoint does not require any request body.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "id": "urn:ietf:params:scim:schemas:core:2.0:Group",
  • "meta": {},
  • "name": "Group",
  • "description": "Group resource.",
  • "attributes": [
    ]
}

List

GET /external-api/scim/v2/Schemas

Required scope: Any SCIM scope (users:read, users:write, roles:read, or roles:write)

This endpoint retrieves the SCIM (System for Cross-domain Identity Management) schemas.

Request Body

This endpoint does not require any request body.

Authorizations:
bearerAuth
header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{
  • "totalResults": 2,
  • "itemsPerPage": 2,
  • "startIndex": 1,
  • "schemas": [
    ],
  • "Resources": [
    ]
}

SCIM - Resource Types

Retrieve the SCIM 2.0 resource type definitions for Users and Groups, including their endpoint URLs and supported schema URNs.

Get resource types

GET /external-api/scim/v2/ResourceTypes

Required scope: Any SCIM scope (users:read, users:write, roles:read, or roles:write)

This endpoint retrieves the resource types available in the system.

Valid resource types include Users and Groups.

Request Body

No request body is required for this endpoint.

Authorizations:
bearerAuth
header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{}

Get User Resource Type

GET /external-api/scim/v2/ResourceTypes/User

Required scope: users:read

This endpoint retrieves the details of a specific resource type, in this case, the "User" resource type.

Request Body

No request body is required for this endpoint.

Authorizations:
bearerAuth
header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{}

Get Group Resource Type

GET /external-api/scim/v2/ResourceTypes/Group

Required scope: roles:read

This endpoint retrieves the details of a specific resource type, in this case, the "Group" resource type.

Request Body

No request body is required for this endpoint.

Authorizations:
bearerAuth
header Parameters
Content-Type
string

Responses

Response samples

Content type
application/scim+json
{}

SCIM - Configuration

Retrieve the SCIM 2.0 Service Provider Configuration for Stensul, describing supported features such as filtering, sorting, bulk operations, and authentication schemes.

Get service provider configuration

GET /external-api/scim/v2/ServiceProviderConfig

Required scope: Any SCIM scope (users:read, users:write, roles:read, or roles:write)

This endpoint retrieves the service provider configuration.

Request Body

This endpoint does not require any request body.

Authorizations:
bearerAuth
header Parameters
Content-Type
string
Example: application/scim+json

Responses

Response samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "patch": {
    },
  • "bulk": {
    },
  • "filter": {
    },
  • "changePassword": {
    },
  • "sort": {
    },
  • "etag": {
    },
  • "authenticationSchemes": [],
  • "meta": {}
}

SCIM - Bulk Actions

Create or update multiple Users and Roles within Stensul in a single request. Requires both users:write and roles:write scopes.

Bulk Actions

POST /external-api/scim/v2/Bulk

Required scopes: users:write AND roles:write

This endpoint is used to perform bulk operations on SCIM resources.

Request Body

  • schemas (array of strings, required): An array of strings indicating the names of the SCIM schemas supported.

  • method (string, required) - The method for the operation.

  • bulkId (string, optional) - The ID for the bulk operation.

  • path (string) - The path for the operation.

  • data (object, required) - The data for the operation.

    • schemas (array, required) - An array of strings.

    • userName (string, required) - The username for the operation.

    • name (object) - The name object.

      • givenName (string) - The given name.

      • familyName (string) - The family name.

    • active (boolean) - The status of the operation.

    • emails (array of objects, optional): Included for compatibility with other SCIM implementations. Stensul uses userName as the user's email address; this field is ignored if userName is present.

      • value (string): The email address.

      • type (string): The type of email (e.g. work).

      • primary (boolean): Indicates whether this is the primary email.

    • groups (array) - An array of groups that the user belongs to.

      • value (string) - The id of the group.
    • entitlements (array, required): An array of library permissions the user has access to.

      • value (string, required): The name of the permission.
Authorizations:
bearerAuth
header Parameters
Content-Type
string
Example: application/scim+json
Request Body schema: application/scim+json
schemas
Array of strings
Array of objects

Responses

Request samples

Content type
application/scim+json
{
  • "schemas": [
    ],
  • "Operations": [
    ]
}

Response samples

Content type
application/scim+json
{}

Capabilities

Inspect the authenticated user's capabilities on a resource

Get resource capabilities

GET /external-api/v1/capabilities

Returns which actions the authenticated user (derived from an authorization_code token) can perform on the given resource type. This is informational only: it does not replace the actual authorization checks enforced by the corresponding write/read endpoints.

An authorization_code token must have the capabilities:read scope. Userless client_credentials callers are allowed through but receive false for every capability, since there is no authenticated user's permissions to report.

Request Body

No request body parameters are required for this endpoint.

Authorizations:
bearerAuth
query Parameters
resource[type]
required
string
Enum: "module" "email" "library"
Example: resource[type]=module

The type of resource to check capabilities for.

resource[id]
string
Example: resource[id]=123

Optional identifier of the specific resource instance. For library and email, supplying it additionally checks access to that specific instance (on top of, never instead of, the type-level permission); a nonexistent id resolves capabilities to false rather than a 404. module capabilities are always type-level regardless of resource[id].

header Parameters
Content-Type
string
Example: application/json
Accept
string
Example: application/json

Responses

Response samples

Content type
application/json
{
  • "resource": {
    },
  • "capabilities": {
    }
}