Bundle format

A package is a set of files. All paths are relative to the root of the package, which can be a folder or a .zip archive.
Package layout
my-package/
├── meta-data.json            the manifest: which file holds which entity
├── resources/
│   ├── boards.json           a JSON array of records
│   ├── cards-0001.json       an entity can be split into any number of files
│   ├── cards-0002.json
│   └── users.json
└── files/
    └── report.txt            the bytes of an attachment
  • meta-data.json is the manifest. It lists every JSON file of the package together with the entity the file holds.
  • The JSON files hold the records, one entity per file. Their names and folders are up to you; the manifest tells what each holds. What you can import lists the entities, and the page of each describes its records.
  • files/ holds the bytes of attachments. The folder may be absent when the package has no files. Files in it that no record names are not imported.
Each entity has a name, such as cards or card_members. It is the name used in the manifest, in the resource property of every entry of resource_files, and in the references between records.
Manifest
meta-data.json names the format and lists the files of the package. It is encoded as UTF-8, and all properties are required.
FieldTypeRequiredDescription
profileobjectYesProfile of the package.
profile.namestringYesAlways external.

Constraints: always "external".

package_idUUIDYesImmutable identifier of the export snapshot; a new snapshot gets a new UUID.
sourceobjectYesWhere the data comes from. It describes the origin, not the target company.
source.systemstringYesjira, clickup, yougile, notion, custom or the name of the vendor.

Constraints: 1–128 characters.

source.namespacestringYesStable key space of the source.

Constraints: 1–512 characters.

source.exported_atTimestampYesTime of the snapshot.
timeline_modeenumYescurrent_state_only: no history, so the cards have no steps. explicit: activities and card_history are given, and the card_add of each card is its creation.

Constraints: one of current_state_only, explicit.

resource_filesobject[]YesJSON files of the package. A resource can have several files. The files are read in the order of this list and the records of a file in the order of its array; where the position of a record matters (cards in a column, columns on a board), that order decides. A JSON file outside files/ that is not listed here is an error; other files are ignored.

Constraints: 1–100000 items.

resource_files[].resourceenumYesName of the resource the file holds.

Constraints: one of activities, attachments, boards, card_blockers, card_children, card_history, card_links, card_members, card_planned_relations, card_time_logs, card_types, cards, checklist_items, checklists, columns, comments, custom_directories, custom_directory_records, custom_properties, document_comments, documents, folders, iteration_cards, iterations, lanes, roles, space_boards, spaces, tags, tree_entity_roles, user_groups, users.

resource_files[].pathstringYesSafe unique path of a JSON array file, relative to the package root.

Constraints: at least 1 character.

binary_filesobjectYesLocation of the files referenced by records. Files there that no record names are not imported.
binary_files.base_pathstringYesAlways files/. The directory may be absent.

Constraints: always "files/".

An example:
{
  "profile": {
    "name": "external"
  },
  "package_id": "b6cde3fd-5d39-4fbf-85b8-c57c09e42ff6",
  "source": {
    "system": "custom",
    "namespace": "acme:tracker",
    "exported_at": "2026-10-07T09:00:00Z"
  },
  "timeline_mode": "current_state_only",
  "resource_files": [
    {
      "resource": "cards",
      "path": "resources/cards-0001.json"
    },
    {
      "resource": "cards",
      "path": "resources/cards-0002.json"
    }
  ],
  "binary_files": {
    "base_path": "files/"
  }
}
timeline_mode is one for the whole package:
ValueMeaning
current_state_onlyThe package has no history. Activities and card_history are absent, so the cards have no steps.
explicitThe package carries the history of the cards: the activities, and the snapshots of every state of a card except the current one. Every card has one card_add action at its created_at, which is its creation; the import adds no other.
Entities that you do not use are not listed. A property that the manifest does not define is refused. package_id identifies the snapshot you exported: a new export gets a new UUID. It does not make a second import update the first one.
Entity files
  • A file is a JSON array of records, encoded as UTF-8. Records may span several lines. A file with one JSON value per line is not accepted. A JSON file outside files/ that the manifest does not list is an error; other files outside files/ are ignored.
  • An entity can have any number of files, for example cards-0001.json and cards-0002.json. List every file in the manifest. You do not split data into pages, sort it or compute service values.
  • Records of different files and entities can be in any order, and a record may refer to one that comes later.
  • Small values live inside a record: a text, a date, a size, the place of a card. Comments, tags, checklist items, history and links are records of their own, so a card stays small however much belongs to it.
  • An empty array means no records. An entity that is absent from the package changes nothing in the target. Deleting and updating existing objects are not supported: an import only adds.
Identifiers and references
  • external_id is a string of 1 to 512 characters. It is unique within its entity across all of its files, case matters, and the value is used as it is. A number is written as a string: "42". A repeated value is an error, not an update.
  • A reference is the external_id of a record of another entity. The entity is fixed by the field: card_ref refers to a card. The field table of every entity tells the target.
  • A reference that may point to one of several entities is an object with the name of the entity and the identifier. The prefix of an identifier, such as space:, says nothing about its entity.
  • Every reference must resolve inside the package. References to identifiers of the target company are not allowed. People are matched to the members of the target company by email, and the others are invited to the target space when the import runs.
  • A field that the entity does not define is refused. A field you leave out gets its documented default; null is accepted only where the field says so.
{
  "card_ref": "card:42"
}
{
  "parent_ref": {
    "resource": "spaces",
    "external_id": "space:delivery"
  }
}
Common types
TypeDescription
DateValueAn object with precision and value. A day without a time: {"precision": "date", "value": "2026-03-01"} (YYYY-MM-DD). A moment: {"precision": "date_time", "value": "2026-03-01T14:00:00Z"} (with a time zone). A date stays a date: it is shown without a time and never turned into midnight.
ExternalIdIdentifier of a record inside the package: a string of 1 to 512 characters, unique within its resource, case sensitive, for example "k-mrr". Numeric identifiers are passed as strings, for example "42". The import also keeps the external_id of boards, cards, columns, custom properties, their options, lanes and spaces as the external id of the objects it creates.
FilePayloadFields of a stored file: file_path, name and size, with an optional mime_type and sha256, for example {"file_path": "kpi/report.pdf", "name": "report.pdf", "size": 48213}. The bytes are placed under files/ at file_path. Card, comment and custom property files may instead name a url, and then the file stays in the cloud.
#RRGGBBColor as #RRGGBB, for example #3366FF. It is replaced with the nearest color of the target palette.
LocalDateCalendar date without time in the form YYYY-MM-DD, for example 2026-10-07.
PolymorphicRefReference to a record of one of several resources: an object with exactly resource and external_id, for example {"resource": "cards", "external_id": "k-mrr"}. The allowed resources are listed by the field.
Ref<resource>Reference to a record of another resource by its external_id, for example "board_ref": "b-kpi". The target resource is fixed by the field.
RichTextAn object with format and text, for example {"format": "markdown", "text": "**Done** in Q1"}. format is plain_text, markdown or html; formats can be mixed in one package. Inside the text, attachment://<external_id> shows an attachment, card://<external_id> links a card and document://<external_id> a document of the package; an unknown external_id is an error.
TimestampPoint in time in RFC 3339 with a time zone, for example 2026-10-07T09:00:00Z or 2026-10-07T12:00:00+03:00. Digits of a second after the milliseconds are dropped.
Rich text and dates are objects:
{
  "format": "markdown",
  "text": "Write the **release notes**."
}
[
  {
    "precision": "date",
    "value": "2026-10-08"
  },
  {
    "precision": "date_time",
    "value": "2026-10-08T18:00:00Z"
  }
]
Formats of rich text can be mixed in one package; the product keeps them in a single format. Numbers are finite, and integers stay within the range that JavaScript represents exactly. A type followed by a question mark accepts null.
Files
An attachment is a record of Attachments plus the bytes of the file, without base64, or a link to a file in the cloud given by url. The record names the file with file_path, a path inside files/, and declares size and, optionally, sha256. Convertinator compares them with the bytes. A path is never a URL, an absolute path or a path outside the folder: segments such as .., backslashes and links are refused. A path also cannot start with emails/ or index/, cannot be exactly undefined, and cannot contain % followed by two hexadecimal digits or a ~ segment, because the target keeps or changes those names. Case matters. Several records can refer to the same bytes.
A text shows a file of the package, such as a picture, by a link to its attachments record, written as attachment://<external_id>; an unknown identifier is an error. The text of a card (its description, its history and its comments) may show the files attached to the card, to its comments and to its property values. An external_id that contains a space, a quote, a parenthesis, a bracket, < or > must be written percent-encoded in the link. The file_path of a linked file cannot contain ", <, > or &. The data of a document shows the attachments owned by that document the same way, with attachment://<attachments external_id>.
Card history
The cards hold the current state, which is version N of a card. The history of a card is made of snapshots and actions, and the two must agree.
  • With explicit, the package carries the actions of every card and, for a card above version 1, the snapshots of the versions 1 to N-1. The action of version V moves the card from snapshot V-1 to the state V; version 1 is a card_add action without a snapshot. It is the creation of the card; the import adds no other. Versions, times and places must agree with the neighbouring states. Nothing is guessed or repaired, and a conflict stops the import.
  • With current_state_only, activities and card history are absent, and a card has no version or version 1.
  • The actions are card_add, card_move, card_leave_board, card_join_board, card_assign_responsible, card_relieve_responsible, card_assign_member, card_remove_member. A move inside one board is one card_move with the same board in from and to. A change of board is a card_leave_board (sequence 1) and a card_join_board (sequence 2) with the same card version and time; a card_move between boards is not allowed. Actions about people are card_assign_responsible, card_relieve_responsible, card_assign_member and card_remove_member. They name the person in payload.user_ref, are not changes of the card, make no version and no snapshot, and show the card as it is at their time. A relieved responsible person stays a member, so a person who leaves the card is relieved and then removed. Comments are records of Comments, not actions.
Large packages and limits
The package is read one record at a time. A file can hold any number of records; what is limited is the size of a single record. Convertinator needs free disk space for the temporary files it writes while it compiles a large package.
LimitValueDescription
Length of external_id512An external_id is a string of 1 to this many characters.
Size of a record8 MiBA record is at most this many bytes as UTF-8 JSON. A file can hold any number of records, so the size of a package is not limited by this value.
Nesting depth of a record16Objects and lists inside a record are nested at most this many levels, the record itself being the first level.
Number of files in resource_files100000The manifest lists at most this many JSON files. This is an operational limit, checked before and during processing.
Size of meta-data.json64 MiBmeta-data.json is at most this many bytes. This is an operational limit, checked before the manifest is read.
Limits of single fields, such as the length of a title, are listed on the pages of the entities, for example Cards. A record that does not fit what the server accepts stops the import before anything is sent.
Validation and errors
Convertinator checks the whole package on your computer before it sends anything. A package must be valid: a problem in the package itself stops the import in both error-handling modes. Every problem is reported with the entity, the file, the number of the record in it counted from 1, the identifier of the record and the field, when they apply. The properties that do not apply are null.
{
  "code": "reference_not_found",
  "resource": "comments",
  "file": "resources/comments.json",
  "record_index": 12,
  "external_id": "comment:12",
  "field": "card_ref",
  "message": "В пакете отсутствует карточка с external_id card:404"
}
PropertyDescription
codeThe error code, one of the codes listed below.
resourceThe entity the problem belongs to, as named in resource_files, or null.
fileThe path of the file with the problem, relative to the root of the package, or null.
record_indexThe number of the record in the file, counted from 1. Line numbers are not used because a record may span several lines. Null when the problem is not about a record.
external_idThe external_id of the record, or null.
fieldThe field with the problem; a dotted path for a field inside an object or a list, or null.
messageA readable explanation in the language of Convertinator.
The error codes:
CodeMeaning
attachment_checksum_mismatchsha256 differs from the real checksum of the file.
attachment_declarations_conflictRecords describe the same file with different size or checksum.
attachment_missingA record refers to a file that does not exist under files/.
attachment_path_invalidA file_path is unsafe (absolute, with .., a backslash, NUL or a link) or uses a name the target reserves or changes.
attachment_size_mismatchsize differs from the real size of the file.
cancelledThe compilation was cancelled.
chain_too_longA dependency chain is longer than 255 links.
compile_busyAnother process is already compiling this package.
cycle_detectedRecords form a cycle.
disk_fullThe working disk ran out of space while compiling.
disk_space_insufficientThe working disk has too little free space.
external_id_duplicateThe same external_id is used twice in one resource.
field_invalidA field has a value of the wrong type or outside its limits.
field_requiredA required field is missing.
field_unknownA record has a field the resource does not define.
file_listed_twiceThe same path is listed more than once in resource_files.
file_missingA file listed in resource_files does not exist.
file_not_listedA JSON file outside files/ is not listed in resource_files.
file_path_invalidA path in resource_files is unsafe or malformed.
history_invalidThe actions, snapshots, positions or times of a card contradict the history rules.
json_duplicate_keyAn object has the same key twice.
json_invalidThe file is not valid JSON.
json_not_arrayThe file is not a single JSON array (NDJSON is not accepted).
json_not_utf8The file is not valid UTF-8.
json_too_deepA record is nested deeper than 16 levels.
manifest_invalidThe manifest does not match its schema.
manifest_too_largeThe converted package description exceeds the limit of the target.
number_out_of_rangeA number cannot be represented exactly.
package_mixedThe manifest carries signs of both a ready-made format and the external profile.
package_not_recognizedThe folder has no meta-data.json that identifies a package.
profile_invalidThe profile section of the manifest is missing or malformed, or the manifest has no resource_files.
record_not_objectAn element of the array is not an object.
record_too_largeA record is larger than 8 MiB.
reference_not_foundA reference points to a record that is not in the package.
reference_resource_invalidA polymorphic reference names a resource the field does not allow.
relation_invalidRelated records contradict each other, for example a column of another board.
resource_unknownresource_files names a resource that does not exist.
row_too_largeA converted row does not fit a page of the target.
source_changedA source file changed while it was being processed.
target_incompatibleThe target server cannot take this kind of import.
target_unsupportedThe target does not accept a value that the package carries.
timeline_mode_conflictThe records contradict timeline_mode of the manifest.
value_not_uniqueA value that must be unique repeats.
workdir_unavailableThe working directory cannot be used.
Strict and non-strict mode
The error-handling mode is chosen when the import is started, see Convertinator. It changes only what happens after the package has been accepted: in strict mode the import stops on the first error and removes what it had written, in non-strict mode it skips the rows the database refuses, where it can, and continues. Errors of the package itself are fatal in both modes.
JSON Schemas
JSON Schemas (draft-07) for the manifest and for the records of every entity. They are the schemas the checks above use:
Compatibility
  • The format has no version number. The manifest names only the profile, external, and these pages describe the format as it is now.
  • Before it compiles a package, Convertinator makes sure that the target installation describes the format exactly as Convertinator knows it. When the two differ, or the installation does not offer this format, the package is refused with a message and nothing is sent. Use a Convertinator release that supports your installation.
logo
Kaiten
If you have any questions or need help with integration feel free to write us at support@kaiten.ru