Draft Workflow
Endpoints for safely editing an Assistant without affecting its live version. A
draft is itself an Assistant row whose editingId points back at the original;
its name mirrors the original. You create a draft, edit it with the ordinary
Assistant routes, then commit the changes back onto the live Assistant or
discard the draft.
Every draft route is gated by ai.verify (AI must be enabled on the tenant AND
the caller must have AI access) and the write routes additionally require
permission.assistant.write (the caller must be a data wizard on the owning
principal). The {id} in each URL is the Assistant's primary-key UUID, resolved
through the read_access scope so an Assistant the caller cannot see answers
404.
Use drafts when making significant changes to an Assistant that is actively used in production chats.
POST /api/assistants/{id}/_edit
Create a draft copy of an Assistant for editing. The {id} is the original
(live) Assistant's id.
Authentication: Required (AI access via ai.verify)
Pre-blocks: assistant.lookup, permission.assistant.write
This route is idempotent: if a draft already exists it is returned as-is;
otherwise the draft is created in a transaction, copying the original's
datasets, secrets, skills, references, toolkits, and files. The draft's
editingId points at the original.
Response:
Responds 200 with the draft Assistant (the handler returns the row directly;
it does not use .created(), so the status is 200, not 201) and a
Location header pointing at the draft.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/_edit"
},
"inf:commit-draft": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/draft/_commit"
},
"inf:assistant-takeover": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000002/_takeover"
},
"inf:assistant-share": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/_edit/shares/{principalId}",
"templated": true
},
"inf:assistant-owner": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/owner"
},
"inf:assistant-datasets": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/datasets"
},
"inf:assistant-skills": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/skills"
},
"inf:assistant-toolkits": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/toolkits"
},
"inf:assistant-references": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/references"
},
"inf:assistant-shares": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/shares"
},
"inf:assistant-icon": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/icon"
},
"inf:assistant-secrets": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/secrets"
},
"inf:assistant-copy": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/_copy"
},
"inf:favorite": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/favorite"
},
"inf:assistant-files": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/files"
},
"inf:assistant-file-upload": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/files/_upload"
},
"inf:assistant-usage": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/usage"
},
"inf:create-image": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/_create-image"
},
"inf:chat-external": {
"href": "https://informer.example.com/assistants/admin%3Asales-assistant-1/chat"
}
},
"naturalId": "admin:sales-assistant-1",
"searchName": "sales assistant",
"permissions": {
"chat": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"assignTags": true
},
"id": "00000000-0000-4000-8000-000000000002",
"shared": false,
"embedded": false,
"tenant": "acme",
"name": "Sales Assistant",
"description": "Answers questions about the Order Desk pipeline.",
"token": null,
"welcome": null,
"instructions": "You are a helpful sales analytics assistant.",
"suggestions": null,
"data": null,
"modelId": "00000000-0000-4000-8000-000000000003",
"dispatcher": false,
"editingId": "00000000-0000-4000-8000-000000000001",
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"ownerId": "admin",
"slug": "sales-assistant-1",
"secrets": null,
"folderId": null,
"source": null,
"sourceId": null,
"libraryId": null
}
GET /api/assistants/{id}/draft
Retrieve the existing draft for an Assistant. The {id} is the original
Assistant's id.
Authentication: Required (AI access via ai.verify)
Pre-blocks: assistant.draft (resolves the draft, 404 when none exists)
Response:
Responds 200 with the draft Assistant, a Location header to the draft, and
an inf:original HAL link back to the Assistant being edited. When no draft
exists the route answers 404.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000002"
},
"inf:commit-draft": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/draft/_commit"
},
"inf:assistant-takeover": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000002/_takeover"
},
"inf:assistant-share": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000002/shares/{principalId}",
"templated": true
},
"inf:assistant-owner": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/owner"
},
"inf:assistant-datasets": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/datasets"
},
"inf:assistant-skills": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/skills"
},
"inf:assistant-toolkits": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/toolkits"
},
"inf:assistant-references": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/references"
},
"inf:assistant-shares": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/shares"
},
"inf:assistant-icon": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/icon"
},
"inf:assistant-secrets": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/secrets"
},
"inf:assistant-copy": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/_copy"
},
"inf:favorite": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/favorite"
},
"inf:assistant-files": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/files"
},
"inf:assistant-file-upload": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/files/_upload"
},
"inf:assistant-usage": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/usage"
},
"inf:create-image": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant-1/_create-image"
},
"inf:chat-external": {
"href": "https://informer.example.com/assistants/admin%3Asales-assistant-1/chat"
},
"inf:original": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001"
}
},
"naturalId": "admin:sales-assistant-1",
"searchName": "sales assistant",
"permissions": {
"chat": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"assignTags": true
},
"id": "00000000-0000-4000-8000-000000000002",
"name": "Sales Assistant",
"description": "Answers questions about the Order Desk pipeline.",
"slug": "sales-assistant-1",
"ownerId": "admin",
"welcome": null,
"modelId": "00000000-0000-4000-8000-000000000003",
"instructions": "You are a helpful sales analytics assistant.",
"suggestions": null,
"token": null,
"data": null,
"source": null,
"sourceId": null,
"folderId": null,
"editingId": "00000000-0000-4000-8000-000000000001",
"shared": false,
"embedded": false,
"dispatcher": false,
"libraryId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"datasets": [],
"model": {
"naturalId": "go_everyday",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"id": "00000000-0000-4000-8000-000000000003",
"model": null,
"slug": "go_everyday",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000004",
"name": "Anthropic",
"slug": "anthropic",
"type": "anthropic",
"key": null,
"managed": true,
"internal": false,
"settings": null,
"data": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
},
"icon": null
}
POST /api/assistants/{id}/draft/_commit
Apply the draft back onto the live Assistant and delete the draft, all in one transaction.
Authentication: Required (AI access via ai.verify)
Pre-blocks: assistant.lookup, permission.assistant.write
The commit copies the draft's editable fields plus its files, skills,
references, datasets, and secrets onto the original, logs an assistantUpdated
activity, and deletes the draft. After a successful commit the draft no longer
exists.
Response:
Responds 200 with the updated live Assistant. Runs in a database transaction.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/draft/_commit"
},
"inf:draft": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/draft"
},
"inf:edit": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/_edit"
},
"inf:comments": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/comments{?sort,limit}",
"templated": true
},
"inf:assistant-share": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/draft/_commit/shares/{principalId}",
"templated": true
},
"inf:assistant-owner": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/owner"
},
"inf:assistant-datasets": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/datasets"
},
"inf:assistant-skills": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/skills"
},
"inf:assistant-toolkits": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/toolkits"
},
"inf:assistant-references": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/references"
},
"inf:assistant-shares": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/shares"
},
"inf:assistant-icon": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/icon"
},
"inf:assistant-secrets": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/secrets"
},
"inf:assistant-copy": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/_copy"
},
"inf:favorite": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/favorite"
},
"inf:assistant-files": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/files"
},
"inf:assistant-file-upload": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/files/_upload"
},
"inf:assistant-usage": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/usage"
},
"inf:create-image": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/_create-image"
},
"inf:chat-external": {
"href": "https://informer.example.com/assistants/admin%3Asupport-assistant/chat"
}
},
"naturalId": "admin:support-assistant",
"searchName": "support assistant",
"permissions": {
"chat": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"assignTags": true
},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Support Assistant",
"description": "Triages inbound support questions.",
"slug": "support-assistant",
"ownerId": "admin",
"welcome": null,
"modelId": "00000000-0000-4000-8000-000000000002",
"instructions": "You are a helpful support assistant.",
"suggestions": null,
"token": null,
"data": null,
"source": null,
"sourceId": null,
"folderId": null,
"editingId": null,
"shared": false,
"embedded": false,
"dispatcher": false,
"libraryId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"model": {
"naturalId": "go_everyday",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"id": "00000000-0000-4000-8000-000000000002",
"model": null,
"slug": "go_everyday",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"name": "Anthropic",
"slug": "anthropic",
"type": "anthropic",
"key": null,
"managed": true,
"internal": false,
"settings": null,
"data": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
},
"icon": null
}
DELETE /api/assistants/{id}/draft
Discard the draft, leaving the live Assistant unchanged.
Authentication: Required (AI access via ai.verify)
Pre-blocks: permission.assistant.write
The draft is removed via the read_access scope; the original Assistant is
untouched.
Response:
Responds 200 with an empty body (Informer convention), not 204.
Worked Example
The draft lifecycle combines these draft routes with the ordinary Assistant routes documented elsewhere. The PUT and skills steps below are not draft-specific endpoints; they are the standard Assistant update and skills routes applied to the draft's id.
1. Create the draft
POST /api/assistants/{id}/_edit
Returns the draft Assistant (its editingId points at the original).
2. Edit the draft
Use the standard Assistant update route against the draft's id:
PUT /api/assistants/{draftId}
{
"instructions": "Updated instructions...",
"suggestions": ["New suggestion"]
}
3. Add skills to the draft
Use the standard skills route against the draft's id:
POST /api/assistants/{draftId}/skills
{
"type": "web-search",
"name": "Web Search"
}
4. Commit or discard
Commit the changes back onto the live Assistant:
POST /api/assistants/{id}/draft/_commit
Or discard the draft:
DELETE /api/assistants/{id}/draft