API: AI

The AI endpoints expose the description assistant: admin-managed text transform actions that rewrite the text of a work package description field with the configured LLM. This tag covers listing the actions available in a given context and running an action on a text.

All AI endpoints are behind the feature flag ai_text_transform_actions and the administrative setting AI text transform actions enabled. When either one is off, or when no LLM connection is ready, the list endpoints answer with an empty collection. They never answer with an error for that reason, so a client can treat an empty collection as “assistant not available”.

Text transform action

An action is an entry of the administration’s AI action list. Only active actions are listed and they are ordered by their position.

Linked Properties

Link Description Type Constraints Supported operations
self This text transform action AITextTransformAction not null READ

Local Properties

Property Description Type Constraints Supported operations
id Action id Integer x > 0 READ
label Label shown to the user String not null READ
position Sort index of the action Integer READ
injectsTypeTemplate Whether the action injects the work package type’s description template Boolean READ

Availability rules

Which actions are listed depends on the context of the request:

  • GET /api/v3/ai_text_transform_actions has no context and lists only actions usable everywhere. Actions scoped to work package types are omitted.
  • GET /api/v3/work_packages/{id}/ai_text_transform_actions lists the actions for an existing work package. Actions scoped to all types or to the work package’s type are included.
  • GET /api/v3/projects/{id}/ai_text_transform_actions?typeId={typeId} lists the actions for a work package about to be created with the given type in the project.

An action that injects the type template is only listed when the type, as configured in the project, has a default description.

Methods

List ai text transform actions

Lists the active AI text transform actions that can be run without a context, that is actions configured to be usable everywhere. Actions scoped to work package types are omitted; use the work package or project variant of this endpoint to list them.

The collection is empty when the feature flag ai_text_transform_actions is off, when the administrative setting is off or when no LLM connection is ready. An empty collection means “assistant not available”.

Required permission: logged in

No parameters

200

OK

{
  "_type": "Collection",
  "total": 1,
  "count": 1,
  "_links": {
    "self": {
      "href": "/api/v3/ai_text_transform_actions"
    }
  },
  "_embedded": {
    "elements": [
      {
        "_type": "AITextTransformAction",
        "id": 1,
        "label": "Improve writing",
        "position": 1,
        "injectsTypeTemplate": false,
        "_links": {
          "self": {
            "href": "/api/v3/ai_text_transform_actions/1",
            "title": "Improve writing"
          }
        }
      }
    ]
  }
}
AITextTransformActionCollectionModel
{
  "allOf": [
    {
      "$ref": "#/components/schemas/CollectionModel"
    },
    {
      "type": "object",
      "required": [
        "_links",
        "_embedded"
      ],
      "properties": {
        "_links": {
          "type": "object",
          "required": [
            "self"
          ],
          "properties": {
            "self": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Link"
                },
                {
                  "description": "This text transform action collection\n\n**Resource**: AITextTransformActionCollectionModel"
                }
              ]
            }
          }
        },
        "_embedded": {
          "type": "object",
          "required": [
            "elements"
          ],
          "properties": {
            "elements": {
              "type": "array",
              "description": "The actions available in the requested context, ordered by position.\nAn empty array means that the assistant is not available.",
              "items": {
                "$ref": "#/components/schemas/AITextTransformActionModel"
              }
            }
          }
        }
      }
    }
  ],
  "example": {
    "_type": "Collection",
    "total": 2,
    "count": 2,
    "_links": {
      "self": {
        "href": "/api/v3/work_packages/42/ai_text_transform_actions"
      }
    },
    "_embedded": {
      "elements": [
        {
          "_type": "AITextTransformAction",
          "id": 1,
          "label": "Improve writing",
          "position": 1,
          "injectsTypeTemplate": false,
          "_links": {
            "self": {
              "href": "/api/v3/ai_text_transform_actions/1",
              "title": "Improve writing"
            }
          }
        },
        {
          "_type": "AITextTransformAction",
          "id": 2,
          "label": "Apply the type template",
          "position": 2,
          "injectsTypeTemplate": true,
          "_links": {
            "self": {
              "href": "/api/v3/ai_text_transform_actions/2",
              "title": "Apply the type template"
            }
          }
        }
      ]
    }
  }
}

401

Returned if no user is currently authenticated.

Required permission: logged in

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:Unauthenticated",
  "message": "You need to be authenticated to access this resource."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

Create ai text transform run

Starts an AI text transform action on the given content. The server assembles the prompt from the action and, when the action injects it, the work package type’s description template, and hands the run to a background job. The response is the run in status queued; poll it with GET /api/v3/ai_text_transform_runs/{id} to receive the generated text.

The context is optional. Pass workPackageId for the description of an existing work package, or projectId and typeId for a work package about to be created. Without a context, only actions usable everywhere can run. The context decides which actions are available and which template is injected; it is not stored on the run.

Runs are private to the user who created them and are deleted after a retention period.

Required permission: logged in. With workPackageId: edit work packages on that work package. With projectId: add work packages in that project.

No parameters
{
  "actionId": 1,
  "content": "Login page dont work on safari 17, i click submit and nothing happen.",
  "workPackageId": 42
}
{
  "actionId": {
    "type": "integer",
    "description": "Id of the AI text transform action to run",
    "minimum": 1
  },
  "content": {
    "type": "string",
    "description": "The text the action works on, usually the current content of the description field.\nMust not be blank and must not exceed 100,000 characters."
  },
  "workPackageId": {
    "type": "integer",
    "description": "Id of the work package whose description is edited. Requires the permission to edit the\nwork package. Cannot be combined with `projectId`.",
    "minimum": 1
  },
  "projectId": {
    "type": "integer",
    "description": "Id of the project a new work package is created in. Requires the permission to add work\npackages in that project and must be combined with `typeId`.",
    "minimum": 1
  },
  "typeId": {
    "type": "integer",
    "description": "Id of the type of the new work package. The type must be enabled in the project.\nMust be combined with `projectId`.",
    "minimum": 1
  }
}

202

Returned if the run was created and queued.

{
  "_type": "AITextTransformRun",
  "id": "6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d",
  "status": "queued",
  "events": [],
  "_links": {
    "self": {
      "href": "/api/v3/ai_text_transform_runs/6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d"
    },
    "cancel": {
      "href": "/api/v3/ai_text_transform_runs/6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d/cancel",
      "method": "post"
    }
  }
}
AITextTransformRunModel
{
  "type": "object",
  "required": [
    "_type",
    "id",
    "status",
    "events",
    "_links"
  ],
  "properties": {
    "_type": {
      "type": "string",
      "enum": [
        "AITextTransformRun"
      ]
    },
    "id": {
      "type": "string",
      "format": "uuid",
      "description": "Run id. Only the user who created the run can read it."
    },
    "status": {
      "type": "string",
      "description": "Lifecycle of the run. `succeeded`, `failed` and `cancelled` are terminal.",
      "enum": [
        "queued",
        "running",
        "succeeded",
        "failed",
        "cancelled"
      ]
    },
    "events": {
      "type": "array",
      "description": "The run's events after the requested cursor, ordered by `seq`. Each event carries one of\nfour kinds with its own payload:\n\n| kind         | payload                                       | meaning                                                                                   |\n|--------------|-----------------------------------------------|-------------------------------------------------------------------------------------------|\n| `status`     | `{ \"status\": \"running\" }`                     | The job picked up the run.                                                                |\n| `text_delta` | `{ \"delta\": \"<chunk>\" }`                      | A chunk of generated text, bundled over roughly half a second. Render it progressively.   |\n| `completed`  | `{ \"text\": \"<full text>\" }`                   | The full final text. Build the result and any diff from this, never from the deltas.      |\n| `error`      | `{ \"message\": \"<text>\", \"reason\": \"<code>\" }` | The run failed. `message` is translated for the user, `reason` is one of `not_available`, `connection_failed`, `timeout`, `rate_limited`, `context_too_long`, `upstream_error`. |",
      "items": {
        "type": "object",
        "required": [
          "seq",
          "kind",
          "payload"
        ],
        "properties": {
          "seq": {
            "type": "integer",
            "description": "Position of the event in the run, starting at 1. Use the highest seen value as the `after` cursor.",
            "minimum": 1
          },
          "kind": {
            "type": "string",
            "enum": [
              "status",
              "text_delta",
              "completed",
              "error"
            ]
          },
          "payload": {
            "type": "object",
            "description": "Depends on `kind`, see the table above.",
            "properties": {
              "status": {
                "type": "string",
                "description": "Only for kind `status`."
              },
              "delta": {
                "type": "string",
                "description": "Only for kind `text_delta`."
              },
              "text": {
                "type": "string",
                "description": "Only for kind `completed`."
              },
              "message": {
                "type": "string",
                "description": "Only for kind `error`."
              },
              "reason": {
                "type": "string",
                "description": "Only for kind `error`.",
                "enum": [
                  "not_available",
                  "connection_failed",
                  "timeout",
                  "rate_limited",
                  "context_too_long",
                  "upstream_error"
                ]
              }
            }
          }
        }
      }
    },
    "_links": {
      "type": "object",
      "required": [
        "self"
      ],
      "properties": {
        "self": {
          "allOf": [
            {
              "$ref": "#/components/schemas/Link"
            },
            {
              "description": "This run.\n\n**Resource**: AITextTransformRun"
            }
          ]
        },
        "cancel": {
          "allOf": [
            {
              "$ref": "#/components/schemas/Link"
            },
            {
              "description": "Requests cancellation of the run. Only present while the run is not terminal.\n\n# Conditions\n\n**Permission**: the run belongs to the current user"
            }
          ]
        }
      }
    }
  },
  "example": {
    "_type": "AITextTransformRun",
    "id": "6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d",
    "status": "running",
    "events": [
      {
        "seq": 1,
        "kind": "status",
        "payload": {
          "status": "running"
        }
      },
      {
        "seq": 2,
        "kind": "text_delta",
        "payload": {
          "delta": "The login page does not work "
        }
      },
      {
        "seq": 3,
        "kind": "text_delta",
        "payload": {
          "delta": "on Safari 17."
        }
      },
      {
        "seq": 4,
        "kind": "completed",
        "payload": {
          "text": "The login page does not work on Safari 17."
        }
      }
    ],
    "_links": {
      "self": {
        "href": "/api/v3/ai_text_transform_runs/6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d"
      },
      "cancel": {
        "href": "/api/v3/ai_text_transform_runs/6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d/cancel",
        "method": "post"
      }
    }
  }
}

400

Returned if the request is malformed: a required property is missing, workPackageId and projectId are both given, or projectId and typeId are not given together.

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:BadRequest",
  "message": "Bad request: workPackageId, projectId are mutually exclusive"
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

403

Returned if the client does not have sufficient permissions.

Required permission: logged in; edit work packages on the work package; add work packages in the project

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
  "message": "You are not authorized to access this resource."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

404

Returned if the work package or project does not exist or is not visible to the client, or if the type is not enabled in the project.

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
  "message": "The requested resource could not be found."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

422

Returned if the content is blank or too long, or if the action cannot run in this context. In the latter case _embedded.details.reason carries a stable, untranslated code:

  • feature_disabled: the feature flag ai_text_transform_actions is off
  • assistant_disabled: the administrative setting is off
  • llm_unavailable: no LLM connection is ready
  • unknown_action: no action with the given id exists
  • action_inactive: the action is deactivated
  • context_required: the action is scoped to work package types but no context was given
  • type_mismatch: the action is not enabled for the work package’s type
  • template_missing: the action injects the type template but the type has none
{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:UnprocessableContent",
  "message": "This action is not available.",
  "_embedded": {
    "details": {
      "reason": "llm_unavailable"
    }
  }
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

View ai text transform run

Returns the run with its status and the events recorded after the after cursor. The events are an append-only log; a client reads the generated text by polling this endpoint until the status is terminal.

Polling

  • Send the highest seq seen so far as after. The first request uses after=0 or omits the parameter. The response then contains only events the client has not seen.
  • Keep one request in flight at a time. Start polling after about 400 ms and increase the interval by 150 ms per poll up to 1000 ms.
  • Ignore a response whose requested cursor is no longer the highest seen seq.
  • Stop when status is succeeded, failed or cancelled. The terminal status can arrive in the same response as the last events.
  • Pause polling while the document is hidden and resume when it becomes visible.
  • Render text_delta payloads progressively. Once completed arrives, replace the rendered text with its text and build any diff from it, never from the concatenated deltas.
  • Show the message of an error event to the user.

Only the user who created the run can read it. Everybody else, administrators included, receives a 404.

Required permission: logged in, owner of the run

id
string

required path

Run id

Example:
6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d

after
integer

optional query

Cursor: only events with a seq greater than this value are returned. Defaults to 0, which returns every event.

Default:
0

Example:
3

200

OK

{
  "_type": "AITextTransformRun",
  "id": "6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d",
  "status": "succeeded",
  "events": [
    {
      "seq": 4,
      "kind": "completed",
      "payload": {
        "text": "The login page does not work on Safari 17."
      }
    }
  ],
  "_links": {
    "self": {
      "href": "/api/v3/ai_text_transform_runs/6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d"
    }
  }
}
AITextTransformRunModel
{
  "type": "object",
  "required": [
    "_type",
    "id",
    "status",
    "events",
    "_links"
  ],
  "properties": {
    "_type": {
      "type": "string",
      "enum": [
        "AITextTransformRun"
      ]
    },
    "id": {
      "type": "string",
      "format": "uuid",
      "description": "Run id. Only the user who created the run can read it."
    },
    "status": {
      "type": "string",
      "description": "Lifecycle of the run. `succeeded`, `failed` and `cancelled` are terminal.",
      "enum": [
        "queued",
        "running",
        "succeeded",
        "failed",
        "cancelled"
      ]
    },
    "events": {
      "type": "array",
      "description": "The run's events after the requested cursor, ordered by `seq`. Each event carries one of\nfour kinds with its own payload:\n\n| kind         | payload                                       | meaning                                                                                   |\n|--------------|-----------------------------------------------|-------------------------------------------------------------------------------------------|\n| `status`     | `{ \"status\": \"running\" }`                     | The job picked up the run.                                                                |\n| `text_delta` | `{ \"delta\": \"<chunk>\" }`                      | A chunk of generated text, bundled over roughly half a second. Render it progressively.   |\n| `completed`  | `{ \"text\": \"<full text>\" }`                   | The full final text. Build the result and any diff from this, never from the deltas.      |\n| `error`      | `{ \"message\": \"<text>\", \"reason\": \"<code>\" }` | The run failed. `message` is translated for the user, `reason` is one of `not_available`, `connection_failed`, `timeout`, `rate_limited`, `context_too_long`, `upstream_error`. |",
      "items": {
        "type": "object",
        "required": [
          "seq",
          "kind",
          "payload"
        ],
        "properties": {
          "seq": {
            "type": "integer",
            "description": "Position of the event in the run, starting at 1. Use the highest seen value as the `after` cursor.",
            "minimum": 1
          },
          "kind": {
            "type": "string",
            "enum": [
              "status",
              "text_delta",
              "completed",
              "error"
            ]
          },
          "payload": {
            "type": "object",
            "description": "Depends on `kind`, see the table above.",
            "properties": {
              "status": {
                "type": "string",
                "description": "Only for kind `status`."
              },
              "delta": {
                "type": "string",
                "description": "Only for kind `text_delta`."
              },
              "text": {
                "type": "string",
                "description": "Only for kind `completed`."
              },
              "message": {
                "type": "string",
                "description": "Only for kind `error`."
              },
              "reason": {
                "type": "string",
                "description": "Only for kind `error`.",
                "enum": [
                  "not_available",
                  "connection_failed",
                  "timeout",
                  "rate_limited",
                  "context_too_long",
                  "upstream_error"
                ]
              }
            }
          }
        }
      }
    },
    "_links": {
      "type": "object",
      "required": [
        "self"
      ],
      "properties": {
        "self": {
          "allOf": [
            {
              "$ref": "#/components/schemas/Link"
            },
            {
              "description": "This run.\n\n**Resource**: AITextTransformRun"
            }
          ]
        },
        "cancel": {
          "allOf": [
            {
              "$ref": "#/components/schemas/Link"
            },
            {
              "description": "Requests cancellation of the run. Only present while the run is not terminal.\n\n# Conditions\n\n**Permission**: the run belongs to the current user"
            }
          ]
        }
      }
    }
  },
  "example": {
    "_type": "AITextTransformRun",
    "id": "6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d",
    "status": "running",
    "events": [
      {
        "seq": 1,
        "kind": "status",
        "payload": {
          "status": "running"
        }
      },
      {
        "seq": 2,
        "kind": "text_delta",
        "payload": {
          "delta": "The login page does not work "
        }
      },
      {
        "seq": 3,
        "kind": "text_delta",
        "payload": {
          "delta": "on Safari 17."
        }
      },
      {
        "seq": 4,
        "kind": "completed",
        "payload": {
          "text": "The login page does not work on Safari 17."
        }
      }
    ],
    "_links": {
      "self": {
        "href": "/api/v3/ai_text_transform_runs/6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d"
      },
      "cancel": {
        "href": "/api/v3/ai_text_transform_runs/6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d/cancel",
        "method": "post"
      }
    }
  }
}

400

Returned if after is not a non-negative integer.

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:BadRequest",
  "message": "Bad request: after does not have a valid value"
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

404

Returned if the run does not exist, has been deleted after its retention period, or belongs to another user.

Required permission: owner of the run

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
  "message": "The requested resource could not be found."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

Cancel ai text transform run

Asks the background job to stop the run. The job checks the request whenever it flushes generated text and then finishes the run with status cancelled; a client keeps polling until it sees that status. The request is idempotent: repeating it or sending it for a run that has already finished answers 204 and changes nothing.

The request has no body, but a Content-Type: application/json header is still required.

Required permission: logged in, owner of the run

id
string

required path

Run id

Example:
6f0f2b3c-5a8e-4b2c-9c3d-1e2f3a4b5c6d

204

Returned if the cancellation was recorded or the run had already finished.

404

Returned if the run does not exist, has been deleted after its retention period, or belongs to another user.

Required permission: owner of the run

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
  "message": "The requested resource could not be found."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

List ai text transform actions for a new work package

Lists the active AI text transform actions that can be run on the description of a work package about to be created in the given project with the given type: actions usable everywhere, actions scoped to all work package types and actions scoped to that type. Actions that inject the type template are listed only when the type, as configured in the project, has a default description.

The collection is empty when the feature flag ai_text_transform_actions is off, when the administrative setting is off or when no LLM connection is ready. An empty collection means “assistant not available”.

Required permission: add work packages

id
integer

required path

Project id

Example:
1

typeId
integer

required query

Id of the type the work package is about to be created with. The type has to be enabled in the project.

Example:
3

200

OK

AITextTransformActionCollectionModel
{
  "allOf": [
    {
      "$ref": "#/components/schemas/CollectionModel"
    },
    {
      "type": "object",
      "required": [
        "_links",
        "_embedded"
      ],
      "properties": {
        "_links": {
          "type": "object",
          "required": [
            "self"
          ],
          "properties": {
            "self": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Link"
                },
                {
                  "description": "This text transform action collection\n\n**Resource**: AITextTransformActionCollectionModel"
                }
              ]
            }
          }
        },
        "_embedded": {
          "type": "object",
          "required": [
            "elements"
          ],
          "properties": {
            "elements": {
              "type": "array",
              "description": "The actions available in the requested context, ordered by position.\nAn empty array means that the assistant is not available.",
              "items": {
                "$ref": "#/components/schemas/AITextTransformActionModel"
              }
            }
          }
        }
      }
    }
  ],
  "example": {
    "_type": "Collection",
    "total": 2,
    "count": 2,
    "_links": {
      "self": {
        "href": "/api/v3/work_packages/42/ai_text_transform_actions"
      }
    },
    "_embedded": {
      "elements": [
        {
          "_type": "AITextTransformAction",
          "id": 1,
          "label": "Improve writing",
          "position": 1,
          "injectsTypeTemplate": false,
          "_links": {
            "self": {
              "href": "/api/v3/ai_text_transform_actions/1",
              "title": "Improve writing"
            }
          }
        },
        {
          "_type": "AITextTransformAction",
          "id": 2,
          "label": "Apply the type template",
          "position": 2,
          "injectsTypeTemplate": true,
          "_links": {
            "self": {
              "href": "/api/v3/ai_text_transform_actions/2",
              "title": "Apply the type template"
            }
          }
        }
      ]
    }
  }
}

400

Returned if the typeId query parameter is missing or not an integer.

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:BadRequest",
  "message": "Bad request: typeId is missing"
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

403

Returned if the client does not have sufficient permissions.

Required permission: add work packages

Note that you will only receive this error, if you are at least allowed to see the corresponding project.

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
  "message": "You are not authorized to access this resource."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

404

Returned if the project does not exist, the client does not have sufficient permissions to see it, or the type is not enabled in the project.

Required permission: view project

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
  "message": "The requested resource could not be found."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

List ai text transform actions for a work package

Lists the active AI text transform actions that can be run on the description of the given work package: actions usable everywhere, actions scoped to all work package types and actions scoped to the work package’s type. Actions that inject the type template are listed only when the work package’s type, as configured in its project, has a default description.

The collection is empty when the feature flag ai_text_transform_actions is off, when the administrative setting is off or when no LLM connection is ready. An empty collection means “assistant not available”.

Required permission: edit work packages

id
integer

required path

Work package id

Example:
42

200

OK

AITextTransformActionCollectionModel
{
  "allOf": [
    {
      "$ref": "#/components/schemas/CollectionModel"
    },
    {
      "type": "object",
      "required": [
        "_links",
        "_embedded"
      ],
      "properties": {
        "_links": {
          "type": "object",
          "required": [
            "self"
          ],
          "properties": {
            "self": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Link"
                },
                {
                  "description": "This text transform action collection\n\n**Resource**: AITextTransformActionCollectionModel"
                }
              ]
            }
          }
        },
        "_embedded": {
          "type": "object",
          "required": [
            "elements"
          ],
          "properties": {
            "elements": {
              "type": "array",
              "description": "The actions available in the requested context, ordered by position.\nAn empty array means that the assistant is not available.",
              "items": {
                "$ref": "#/components/schemas/AITextTransformActionModel"
              }
            }
          }
        }
      }
    }
  ],
  "example": {
    "_type": "Collection",
    "total": 2,
    "count": 2,
    "_links": {
      "self": {
        "href": "/api/v3/work_packages/42/ai_text_transform_actions"
      }
    },
    "_embedded": {
      "elements": [
        {
          "_type": "AITextTransformAction",
          "id": 1,
          "label": "Improve writing",
          "position": 1,
          "injectsTypeTemplate": false,
          "_links": {
            "self": {
              "href": "/api/v3/ai_text_transform_actions/1",
              "title": "Improve writing"
            }
          }
        },
        {
          "_type": "AITextTransformAction",
          "id": 2,
          "label": "Apply the type template",
          "position": 2,
          "injectsTypeTemplate": true,
          "_links": {
            "self": {
              "href": "/api/v3/ai_text_transform_actions/2",
              "title": "Apply the type template"
            }
          }
        }
      ]
    }
  }
}

403

Returned if the client does not have sufficient permissions.

Required permission: edit work packages

Note that you will only receive this error, if you are at least allowed to see the corresponding work package.

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
  "message": "You are not authorized to access this resource."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}

404

Returned if the work package does not exist or the client does not have sufficient permissions to see it.

Required permission: view work packages

{
  "_type": "Error",
  "errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
  "message": "The requested resource could not be found."
}
ErrorResponse
{
  "type": "object",
  "required": [
    "_type",
    "errorIdentifier",
    "message"
  ],
  "properties": {
    "_embedded": {
      "type": "object",
      "properties": {
        "details": {
          "type": "object",
          "properties": {
            "attribute": {
              "type": "string",
              "example": "project"
            }
          }
        }
      }
    },
    "_type": {
      "type": "string",
      "enum": [
        "Error"
      ]
    },
    "errorIdentifier": {
      "type": "string",
      "example": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation"
    },
    "message": {
      "type": "string",
      "example": "Project can't be blank."
    }
  }
}