= insert()
:description: Creates a new ECM object (dms.XMLInsert) and returns object_id and object_type_id. Use insert_and_get() to receive the full populated instance immediately.
:keywords: insert, XMLInsert, object_id, object_type_id, create object, ECMFolderModel, ECMDocumentModel
:page-tags: api, dms

Creates a new object on the server and returns `(object_id, object_type_id)`. Internally uses `dms.XMLInsert`. The passed model instance is not mutated.

If the fully populated instance is needed directly after creation, xref:api/dms/insert_and_get.adoc[insert_and_get()] is the more compact alternative.

== Signature

[tabs]
====
Sync::
+
[source,python]
----
ecm.dms.insert(
    model: T,
    files: list[JobRequestFile] | None = None,
    *,
    folder_id: int | ECMFolderModel | None = None,
    register_id: int | ECMRegisterModel | None = None,
    check_mandatory: bool = True,
) -> tuple[int, int]
----

Async::
+
[source,python]
----
await ecm.dms.insert(
    model: T,
    files: list[JobRequestFile] | None = None,
    *,
    folder_id: int | ECMFolderModel | None = None,
    register_id: int | ECMRegisterModel | None = None,
    check_mandatory: bool = True,
) -> tuple[int, int]
----
====

== Parameters

[cols="1,1,3"]
|===
|Name |Type |Description

|`model`
|`ECMFolderModel \| ECMRegisterModel \| ECMDocumentModel`
|The model instance to create, with the desired field values set. The instance is not mutated.

|`files`
|`list[JobRequestFile] \| None`
|Optional list of files to attach to the new document. Only allowed for `ECMDocumentModel` — raises `TypeError` for folder or register models. Default: `None`.

|`folder_id`
|`int \| ECMFolderModel \| None`
|Folder to place the object in — either a numeric ID or an `ECMFolderModel` instance (its `id` is used). Only valid for registers and documents. Default: `None`.

|`register_id`
|`int \| ECMRegisterModel \| None`
|Register to file the document in (`ECMDocumentModel`) or parent register (`ECMRegisterModel`) — either a numeric ID or an `ECMRegisterModel` instance. Default: `None`.

|`check_mandatory`
|`bool`
|When `True` (default), validates client-side that all `mandatory=True` `ECMField` descriptors have a value. When `False`, both client-side and server-side obligation checks are disabled (`CHECKOBLIGATION=0`).
|===

== Return value

`tuple[int, int]` — `(object_id, object_type_id)` of the newly created object.

== Exceptions

`ECMException`:: The server rejected the insert (`ObjectID == -1`).
`ECMMissingArgumentException`:: `folder_id` is missing for a register or document model. Subclass of `ECMException`.
`TypeError`:: `files` was provided for a folder or register model.
`ValueError`:: `check_mandatory=True` and a required field is not set.

== Examples

=== Simple folder

[tabs]
====
Sync::
+
[source,python]
----
object_id, object_type_id = ecm.dms.insert(
    InvoiceFolder(Title="Invoice 2024", Year=2024)
)
print(object_id)
----

Async::
+
[source,python]
----
object_id, object_type_id = await ecm.dms.insert(
    InvoiceFolder(Title="Invoice 2024", Year=2024)
)
print(object_id)
----
====

=== Register inside a folder

[tabs]
====
Sync::
+
[source,python]
----
object_id, _ = ecm.dms.insert(
    InvoiceRegister(Name="Incoming invoices"),
    folder_id=folder.system.id,
)
----

Async::
+
[source,python]
----
object_id, _ = await ecm.dms.insert(
    InvoiceRegister(Name="Incoming invoices"),
    folder_id=folder.system.id,
)
----
====

=== Document with file and filing location

[tabs]
====
Sync::
+
[source,python]
----
from ecmind_blue_client.rpc import JobRequestFileFromPath

object_id, _ = ecm.dms.insert(
    InvoiceDocument(Title="Invoice No. 42"),
    files=[JobRequestFileFromPath("/tmp/invoice.pdf")],
    folder_id=folder.system.id,
    register_id=register.system.id,
)
print(object_id)
----

Async::
+
[source,python]
----
from ecmind_blue_client.rpc import JobRequestFileFromPath

object_id, _ = await ecm.dms.insert(
    InvoiceDocument(Title="Invoice No. 42"),
    files=[JobRequestFileFromPath("/tmp/invoice.pdf")],
    folder_id=folder.system.id,
    register_id=register.system.id,
)
print(object_id)
----
====

=== Passing model instances as folder_id / register_id

Instead of a numeric ID, a model instance can be passed directly — `insert()` extracts the ID automatically:

[tabs]
====
Sync::
+
[source,python]
----
folder = ecm.dms.insert_and_get(InvoiceFolder(Title="Invoice 2024"))
register = ecm.dms.insert_and_get(
    InvoiceRegister(Name="Incoming"),
    folder_id=folder,          # ECMFolderModel instance instead of int
)
object_id, _ = ecm.dms.insert(
    InvoiceDocument(Title="Invoice No. 42"),
    folder_id=folder,          # ECMFolderModel instance
    register_id=register,      # ECMRegisterModel instance
)
----

Async::
+
[source,python]
----
folder = await ecm.dms.insert_and_get(InvoiceFolder(Title="Invoice 2024"))
register = await ecm.dms.insert_and_get(
    InvoiceRegister(Name="Incoming"),
    folder_id=folder,
)
object_id, _ = await ecm.dms.insert(
    InvoiceDocument(Title="Invoice No. 42"),
    folder_id=folder,
    register_id=register,
)
----
====

=== Disabling mandatory field validation

[tabs]
====
Sync::
+
[source,python]
----
# check_mandatory=False: no error even if required fields are missing
object_id, _ = ecm.dms.insert(
    InvoiceFolder(Title="Draft"),
    check_mandatory=False,
)
----

Async::
+
[source,python]
----
object_id, _ = await ecm.dms.insert(
    InvoiceFolder(Title="Draft"),
    check_mandatory=False,
)
----
====

== See also

* xref:api/dms/insert_and_get.adoc[insert_and_get()] — combines `insert()` and `get()` in one call when the full instance is needed immediately
* xref:api/dms/update.adoc[update()] — updates an existing object
