DXL Extension API guide
Important
The DXL Extension API is experimental and is provided for users to try and evaluate. It is not yet supported for production use.
The DXL Extension API is disabled by default. To enable it, see Enable CalDav, CardDav, and DXL extension APIs.
For any feedback, questions, or issues, you may post them in the OpenNTF Discord channel .
The DXL Extension API (/api/dxl) provides developers with programmatic access to Domino database design elements. It supports operations to read, modify, delete, and import individual design elements, as well as database-level operations such as ACL management, property updates, and bulk DXL export and import.
Common concepts
Base URL
/api/dxl
Authentication
All endpoints require a JWT bearer token, except the schema file itself.
Authorization: Bearer <token>
Obtain a token via the POST /api/v1/auth endpoint using your Domino credentials.
nsfPath parameter
Every endpoint accepts nsfPath as a required query parameter. It is the relative path
to the NSF file on the Domino server.
For example:
?nsfPath=mail/user.nsf
?nsfPath=apps/myapp.nsf
Required access levels
| Operation | Minimum ACL level |
|---|---|
| Read / List / Export / Validate | READER |
| Import / Create / Update / Delete design elements | DESIGNER |
| Create / Update / Delete help documents (About, Using) | DESIGNER |
| ACL operations / Database property writes | MANAGER |
Design element types
The following type names are used in path parameters and query parameters throughout the API.
| Type name | Domino element |
|---|---|
form |
Form |
subform |
Subform |
view |
View |
folder |
Folder |
frameset |
Frameset |
page |
Page |
agent |
Agent |
scriptlibrary |
Script Library |
sharedfield |
Shared Field |
sharedcolumn |
Shared Column |
navigator |
Navigator |
outline |
Outline |
imageresource |
Image Resource |
fileresource |
File Resource |
Typical workflows
Migrate a design element between databases
# 1. Export the element from the source database
curl -H "Authorization: Bearer $TOKEN" \
"http://server:8880/api/dxl/form/OrderForm?nsfPath=source.nsf" \
| jq -r .dxl > OrderForm.dxl
# 2. Import the element into the target database
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: text/xml" \
--data-binary @OrderForm.dxl \
"http://server:8880/api/dxl/form/OrderForm?nsfPath=target.nsf"
Validate before importing
# Validate first
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"dxl\": $(jq -Rs . < export.dxl)}" \
"http://server:8880/api/dxl/validate?nsfPath=target.nsf"
# If valid, kick off async import
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"dxl\": $(jq -Rs . < export.dxl)}" \
"http://server:8880/api/dxl/import?nsfPath=target.nsf"
Update outline view targets after a hybrid-mode copy
When an outline is copied from a reference database, the view names may differ in the target database. Use the entries API to read and rewrite them without touching DXL.
# 1. Read the current entries
curl -H "Authorization: Bearer $TOKEN" \
"http://server:8880/api/dxl/outline/MainOutline/entries?nsfPath=apps/myapp.nsf" \
> entries.json
# 2. Edit entries.json (update target names, reorder, add children, etc.)
# 3. Write the modified entries back
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data-binary @entries.json \
"http://server:8880/api/dxl/outline/MainOutline/entries?nsfPath=apps/myapp.nsf"
Migrate the About document between databases
# 1. Export the About document from the source database
curl -H "Authorization: Bearer $TOKEN" \
"http://server:8880/api/dxl/helpdoc/about?nsfPath=source.nsf" \
| jq -r .dxl > about.dxl
# 2. Import the About document into the target database
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: text/xml" \
--data-binary @about.dxl \
"http://server:8880/api/dxl/helpdoc/about?nsfPath=target.nsf"
Copy the database icon note between databases
If a database workspace icon is missing (for example, the icon appears in Domino Designer but not in the Notes workspace), the database's icon note may be missing or invalid. Copy the icon note from a database with a working workspace icon to restore it.
# 1. Export the icon note from the source database
curl -H "Authorization: Bearer $TOKEN" \
"http://server:8880/api/dxl/dbicon?nsfPath=nifty50/n50-base.nsf" \
| jq -r .dxl > dbicon.dxl
# 2. Import the icon note into the target database
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: text/xml" \
--data-binary @dbicon.dxl \
"http://server:8880/api/dxl/dbicon?nsfPath=nifty50/n50-risk.nsf"
Set a database to open a frameset on launch
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"notes": {"whenOpened": "openframeset", "framesetName": "MainFrameset"}}' \
"http://server:8880/api/dxl/database?nsfPath=apps/myapp.nsf"
Error reference
| HTTP status | Meaning |
|---|---|
| 400 | Bad request — missing required parameter, invalid value, or malformed DXL |
| 401 | Missing or invalid JWT token |
| 403 | Insufficient ACL access for this operation |
| 404 | Resource not found (design element, frameset, import job) |
| 500 | Internal server error — check the Domino KEEP log |
All error responses include a JSON body with a message field describing the problem.
Agent DXL reference
This section documents all valid values for agent DXL elements and attributes, sourced
directly from the Domino 14.5 DXL schema (domino_14_5.dtd).
<agent> attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
name |
string | — | Agent name (required) |
alias |
string | — | Alternate name |
comment |
string | — | Description shown in Designer |
enabled |
boolean | true |
Whether the agent is enabled |
restrictions |
see details | restricted |
Security restriction level |
runaswebuser |
boolean | false |
Run with the effective web user's identity |
runonbehalfof |
string | — | Run on behalf of this username |
activatable |
boolean | — | For scheduled agents: can be toggled enabled/disabled |
showinsearch |
boolean | false |
Show agent's search in the search bar |
clientbackgroundthread |
boolean | false |
Run in a background thread on the client |
allowremotedebugging |
boolean | false |
Allow remote debugger to attach |
storehighlights |
boolean | false |
Store search highlights |
formulatype |
see details | modifydocs |
For formula agents: how the formula operates |
profile |
boolean | false |
Profile agent execution each run |
restrictions values
| Value | Description |
|---|---|
restricted |
Restricted operations only |
unrestricted |
Unrestricted operations allowed |
fulladminunrestricted |
Full admin unrestricted (requires server trust) |
formulatype values
For formula agents only.
| Value | Description |
|---|---|
modifydocs |
Formula modifies documents |
createdocs |
Formula creates new documents |
selectdocs |
Formula selects documents |
<trigger> element
This is a required element that specifies the event or mechanism that triggers the agent.
<trigger type='actionsmenu'/>
For scheduled agents, the <trigger> element contains a <schedule> child element.
type values
| Value | Description |
|---|---|
actionsmenu |
Manually from Actions menu |
agentlist |
Manually from agent list |
beforenewmail |
Before new mail arrives |
afternewmail |
After new mail has arrived |
docupdate |
When documents are created or modified |
docpaste |
When documents are pasted |
scheduled |
On a specified schedule (requires <schedule> child) |
serverstart |
When the Domino server starts up |
<schedule> element
This is a required element when trigger type='scheduled'. This element is a child of <trigger>.
<trigger type='scheduled'>
<schedule type='daily' runlocation='any' onweekends='false'>
<starttime><datetime>T090000,00</datetime></starttime>
<endtime><datetime>T170000,00</datetime></endtime>
</schedule>
</trigger>
Optional child elements of <schedule>:
<starttime><endtime><startdate><enddate>
Each optional child element contains a <datetime> element.
<schedule> attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
type |
see details | — | Schedule frequency (required) |
runlocation |
see details | — | Where the agent runs |
runserver |
string | — | Server name when runlocation='specific' |
hours |
integer | — | Hours between runs (use with type='byminutes') |
minutes |
integer | — | Minutes between runs (use with type='byminutes') |
onweekends |
boolean | true |
Allow runs on weekends |
dayofweek |
see details | — | Required when type='weekly' |
dateinmonth |
integer | — | Day of month (1–31); Required when type='monthly' |
type values
| Value | Description |
|---|---|
automatic |
Schedule implied by trigger, such as docupdate |
byminutes |
More than once a day; use hours and/or minutes attributes |
daily |
Once per day |
weekly |
Once per week; requires dayofweek attribute |
monthly |
Once per month; requires dateinmonth attribute |
never |
Disabled schedule |
runlocation values
| Value | Description |
|---|---|
any |
Any server |
choose |
User chooses when enabling the agent |
specific |
Specific server named in runserver attribute |
local |
(Deprecated since ND 8.52) Local workstation |
server |
(Deprecated since ND 8.52) A server |
dayofweek values
sundaymondaytuesdaywednesdaythursdayfridaysaturday
<documentset> element
This is an optional element that specifies which documents that agent operates on. Omit this element for agents whose document set is implied by the <trigger> element's type attribute beforenewmail, afternewmail, and serverstart.
<documentset type='all'/>
type values
| Value | Description |
|---|---|
modified |
All new and modified documents |
unreadinview |
All unread documents in a view |
allinview |
All documents in a view |
selected |
Selected documents |
runonce |
Run once (current document) |
all |
All documents in database |
implicit |
Document set implied by trigger (required for docpaste; not valid for manual triggers) |
<code> elements
One or more <code> elements hold the agent's source code. Each <code> element has event
attribute that specify which section it represents.
| Event | Description |
|---|---|
options |
Option Public / Option Declare section |
declarations |
Module-level variable declarations |
initialize |
Sub Initialize — main entry point |
terminate |
Sub Terminate — cleanup on exit |
action
The LotusScript content goes in a <lotusscript> child element, while the Java content goes in a
<javaproject> child element.
<code event='options'><lotusscript>Option Public
Option Declare
</lotusscript></code>
<code event='initialize'><lotusscript>Sub Initialize
MsgBox "Hello World"
End Sub</lotusscript></code>
Minimal create payloads
The following examples show the minimal payloads required to create agents. They include only the required elements and omit optional metadata.
Manually run:
<agent xmlns='http://www.lotus.com/dxl' name='MyAgent'>
<trigger type='actionsmenu'/>
<documentset type='runonce'/>
<code event='initialize'><lotusscript>Sub Initialize
MsgBox "Hello World"
End Sub</lotusscript></code>
</agent>
Manually run:
<agent xmlns='http://www.lotus.com/dxl' name='MyJavaAgent'>
<trigger type='actionsmenu'/>
<documentset type='runonce'/>
<code event='action'><javaproject class='JavaAgent.class'>
<java name='JavaAgent.java'>import lotus.domino.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
System.out.println("Hello World");
} catch(Exception e) {
e.printStackTrace();
}
}
}</java>
</javaproject></code>
</agent>
Manually run:
<agent xmlns='http://www.lotus.com/dxl' name='MyFormulaAgent'>
<trigger type='actionsmenu'/>
<documentset type='runonce'/>
<code event='action'>
<simpleaction action='runformula'><formula>@Prompt([Ok]; "Hello World Prompt"; "Hello World!")</formula></simpleaction>
</code>
</agent>
Runs daily on any server:
<agent xmlns='http://www.lotus.com/dxl' name='MyScheduledAgent' enabled='true'>
<trigger type='scheduled'>
<schedule type='daily' runlocation='any' onweekends='false'>
<starttime><datetime>T020000,00</datetime></starttime>
<endtime><datetime>T030000,00</datetime></endtime>
</schedule>
</trigger>
<documentset type='all'/>
<code event='initialize'><lotusscript>Sub Initialize
' Agent logic here
End Sub</lotusscript></code>
</agent>
Additional information
Java agents
- The
code eventmust beaction. Do not useinitialize, which is used for LotusScript agents. - The
javaproject classpoints to the compiled entry point, which is alwaysJavaAgent.classfor standard agents. - The
codepathattribute that appears in an exported DXL is a Domino Designer metadata and should be omitted on import. - The
$JavaCompilerSourceand$JavaCompilerTargetitems in an exported DXL are Domino Designer generated, and should be omitted. Domino sets them on compile. - Source is embedded as a
<java name='JavaAgent.java'>child element. Make sure the class name and filename match.
Formula agents
- The
code eventmust beaction, the same as in Java agents. - The formula goes inside
<simpleaction action='runformula'><formula>...</formula></simpleaction>. There should be no<lotusscript>or<javaproject>wrapper. - There is no compilation step. The formula agents work immediately after import with no server-side issues.
- The
SELECT @Allclause seen in the Domino Designer-exported DXL is the document selection formula. It can be omitted when using<documentset type='runonce'/>.
DXL format
- Do not include an XML declaration. The Domino DXL importer's XML parser is strict about where
<?xml version='1.0' ...?>may appear. When our code wraps your element fragment inside a<database>element before importing, an XML declaration in your payload ends up inside the root element. This is illegal XML and causes an immediate fatal parse error:
Fatal Error: No processing instruction starts with 'xml'
This applies to all endpoints that accept DXL, such as PUT /{type}/{name}, POST /import, and POST /validate. Simply omit the declaration entirely as it is never required here.
- Do not include a DOCTYPE declaration. The same reason with the XML declaration, the importer rejects it.
- The exported DXL from GET /{type}/{name} and GET /export does not include either declaration, so round-tripping exported DXL is safe.
- The Lotus DXL namespace declaration is required on the root element:
xmlns='http://www.lotus.com/dxl'.
- For PUT /{type}/{name}, supply only the element fragment, such as <form ...>, and not a full <database> wrapper.
- For POST /import and POST /validate, the DXL must be wrapped in <database>...</database>.
- A leading UTF-8 BOM is accepted and stripped by the importer and validator. This
handles files generated by tools like Windows PowerShell Out-File.
Known limitations
Java compilation on import
When creating a Java agent using PUT /{type}/{name}, Domino attempts to compile the Java source immediately. On some server configurations, compilation can fail silently because of a wildcard classpath issue: libs/* is passed literally to javac instead of being shell-expanded.
If compilation fails, the agent note is still created and signed correctly, but contains only the source and no compiled bytecode and will not run. The import response includes a warning similar to the following:
Java compile errors: error: illegal argument for --class-path: Illegal char <*>
The workaround is to open the agent in Domino Designer after import, which triggers recompilation in the Domino Designer environment where the classpath is handled correctly.
Note
LotusScript agents are not affected by this issue.
Ampersand in action button titles
The Domino C API DxlImporter silently drops <action> elements whose title attribute contains & (the XML entity for &). For example, a button titled Save & Close is encoded in valid XML as <action title='Save & Close'>, but the DxlImporter discards the entire element during import without any error raised and without any written log entry.
The issue originates in the Notes C API, not in the DXL specification or this extension. To prevent import failures, DXL-EXT automatically sanitizes affected action button titles before passing DXL to the importer. For example, a title containing & is rewritten to use and (Save & Close becomes Save and Close).
When DXL-EXT makes this change, the import response includes a "sanitized" array that lists each modified value:
"sanitized": [
{ "type": "actionTitleSanitized", "original": "Save & Close", "replaced": "Save and Close" }
]
This applies to PUT /{type}/{name} (synchronous — in the response body) and POST /import (asynchronous — in the job status when polled). If your action titles must avoid the word and, rename them before submitting the DXL.