Create a document

View as Markdown

Upload the file content to a temporary upload on the server first, then create the document in one call that names the upload, the properties and the permissions, and checks the new document in.

Calls

  1. UploadTempFile: send the content in blocks. The first call has upload_id 0, offset 0 and the file's total_size_in_bytes, and returns the upload_id of a new upload; later calls pass that ID and the offset of their block. The samples send blocks of 4 MiB.
  2. UploadTempFileCommit with upload_id and logical_size, the number of bytes uploaded. An upload that is not committed cannot be used.
  3. AddObjectWithFiles with:
Field Value
object_type_id 0 (Document)
properties 0 Name or title (text), 100 Class (lookup, value list 1), 22 Single file (boolean true), and the properties the class requires
acl custom_component with has_named_acl true and named_acl_id = the named ACL to use; the samples use -1
files type OBJ_FILE_SOURCE_TYPE_UPLOADED_FILE, data.uploaded_file with upload_id, title, extension (no dot) and size
check_in true; false leaves the new document checked out to you

AddObjectWithFiles consumes the upload. The response's created_object.object_version has the new object's object_info.obj_id and the version information with the file.

Permissions

Always send acl. An object created without one gets an empty access control list: nobody can see it, not even the user who created it, and the call still succeeds. The samples link the new document to a named ACL with has_named_acl: true and named_acl_id: -1. In a default vault, -1 is "Full control for all internal users". Pick the named ACL that your application needs; the IDs of the others differ from vault to vault. See Permissions.

Code

Python

The upload:

# Upload the content to a temporary file on the server, in blocks. The first call
# (upload_id 0) starts the upload; the next ones continue it.
upload_id = 0
for offset in range(0, max(len(content), 1), BLOCK_SIZE):
    upload_id = objects.UploadTempFile(ops.UploadTempFileRequest(
        upload_id=upload_id,
        total_size_in_bytes=len(content),
        offset=offset,
        data=content[offset:offset + BLOCK_SIZE])).upload_id
objects.UploadTempFileCommit(ops.UploadTempFileCommitRequest(
    upload_id=upload_id, logical_size=len(content)))

Source: python/recipes/create_document.py

The document:

response = objects.AddObjectWithFiles(ops.AddObjectWithFilesRequest(
    object_type_id=0,  # Document
    properties=[
        property_value(0, text(title)),      # Name or title
        property_value(100, lookup(1, 1)),   # Class: value list 1, item 1 "Other Document"
        property_value(22, boolean(True)),   # Single file
    ],
    # Always send an ACL: without one, the new document has no permissions and not even
    # its creator can see it. Named ACL -1 is "Full control for all internal users".
    acl=named_acl(-1),
    files=structs.ObjFileSource(
        type=enums.OBJ_FILE_SOURCE_TYPE_UPLOADED_FILE,
        data=structs.ObjFileSourceUnion(
            uploaded_file=structs.ObjFileSourceUnion.UploadedFileData(
                upload_id=upload_id,
                title=title,  # a single-file document's file takes the document's title
                extension="txt",
                size=len(content)))),
    check_in=True))
created = response.created_object.object_version
print(f"Created {describe(created)}")

Source: python/recipes/create_document.py

C#

The upload:

// Upload the content to a temporary file on the server, in blocks. The first call
// (upload_id 0) starts the upload; the next ones continue it.
int uploadId = 0;
for (int offset = 0; offset == 0 || offset < content.Length; offset += BlockSize)
{
    var block = await objects.UploadTempFileAsync(new UploadTempFileRequest
    {
        UploadId = uploadId,
        TotalSizeInBytes = content.Length,
        Offset = offset,
        Data = ByteString.CopyFrom(content, offset, Math.Min(BlockSize, content.Length - offset)),
    });
    uploadId = block.UploadId;
}
await objects.UploadTempFileCommitAsync(new UploadTempFileCommitRequest
{
    UploadId = uploadId,
    LogicalSize = content.Length,
});

Source: csharp/Recipes/CreateDocument.cs

The document:

var response = await objects.AddObjectWithFilesAsync(new AddObjectWithFilesRequest
{
    ObjectTypeId = 0,  // Document
    Properties =
    {
        Property(0, Text(title)),          // Name or title
        Property(100, Lookup(1, 1)),       // Class: value list 1, item 1 "Other Document"
        Property(22, Boolean(true)),       // Single file
    },
    // Always send an ACL: without one, the new document has no permissions and not even
    // its creator can see it. Named ACL -1 is "Full control for all internal users".
    Acl = new AccessControlList
    {
        CustomComponent = new AccessControlListComponent { HasNamedAcl = true, NamedAclId = -1 },
    },
    Files = new ObjFileSource
    {
        Type = ObjFileSourceType.UploadedFile,
        Data = new ObjFileSourceUnion
        {
            UploadedFile = new ObjFileSourceUnion.Types.UploadedFileData
            {
                UploadId = uploadId,
                Title = title,  // a single-file document's file takes the document's title
                Extension = "txt",
                Size = content.Length,
            },
        },
    },
    CheckIn = true,
});
var created = response.CreatedObject.ObjectVersion;
Console.WriteLine($"Created {RecipeHelpers.Describe(created)}");

Source: csharp/Recipes/CreateDocument.cs

Go

The upload:


// upload uploads content to a temporary file on the server, in blocks, and returns its upload
// ID. The first call (upload_id 0) starts the upload; the next ones continue it.
func upload(ctx context.Context, objects mfiles.IRPCObjectOperationsClient,
	content []byte) (int32, error) {
	var uploadID int32
	for offset := 0; offset == 0 || offset < len(content); offset += blockSize {
		block, err := objects.UploadTempFile(ctx, &mfiles.UploadTempFileRequest{
			UploadId:         uploadID,
			TotalSizeInBytes: int64(len(content)),
			Offset:           int64(offset),
			Data:             content[offset:min(offset+blockSize, len(content))],
		})
		if err != nil {
			return 0, err
		}
		uploadID = block.GetUploadId()
	}
	_, err := objects.UploadTempFileCommit(ctx, &mfiles.UploadTempFileCommitRequest{
		UploadId:    uploadID,
		LogicalSize: int64(len(content)),
	})
	return uploadID, err
}

Source: go/recipes/create_document/main.go

The document:

response, err := objects.AddObjectWithFiles(ctx, &mfiles.AddObjectWithFilesRequest{
	ObjectTypeId: 0, // Document
	Properties: []*mfiles.PropertyValue{
		mfilesclient.PropertyValue(0, mfilesclient.Text(title)),    // Name or title
		mfilesclient.PropertyValue(100, mfilesclient.Lookup(1, 1)), // Class: "Other Document"
		mfilesclient.PropertyValue(22, mfilesclient.Boolean(true)), // Single file
	},
	// Always send an ACL: without one, the new document has no permissions and not even its
	// creator can see it. Named ACL -1 is "Full control for all internal users".
	Acl: mfilesclient.NamedACL(mfilesclient.NamedACLFullControlForAllInternalUsers),
	Files: &mfiles.ObjFileSource{
		Type: mfiles.ObjFileSourceType_OBJ_FILE_SOURCE_TYPE_UPLOADED_FILE,
		Data: &mfiles.ObjFileSourceUnion{Data: &mfiles.ObjFileSourceUnion_UploadedFile{
			UploadedFile: &mfiles.ObjFileSourceUnion_UploadedFileData{
				UploadId:  uploadID,
				Title:     title, // a single-file document's file takes the document's title
				Extension: "txt",
				Size:      int64(len(content)),
			},
		}},
	},
	CheckIn: true,
})
if err != nil {
	return err
}
created := response.GetCreatedObject().GetObjectVersion()
fmt.Println("Created", recipe.Describe(created))

Source: go/recipes/create_document/main.go

Output (the recipe deletes the document at the end unless you pass --keep):

Created [docs-test] Created by the Python sample 2026-10-31 14:55:56 (ID 611, version 1, modified 2026-10-31 14:55:56 UTC)
  File: [docs-test] Created by the Python sample 2026-10-31 14:55:56.txt, 96 bytes
Deleted object 0-611

Pitfalls

See also