orbotodocs
Admin guideIntegrations & data

Importing from other tools

Move existing work into orboto from Jira, Linear, GitHub, GitLab, Asana, Trello, Notion, ClickUp, Monday.com, Redmine, Azure DevOps or CSV - the full wizard, step by step.

Admin -> Import brings an existing project into orboto through one unified wizard: pick a source, configure it, choose a target project, review and fix the mapping, then apply. It's the same wizard regardless of which source you pick - only the configuration fields on step 2 change.

The import wizard

Supported sources and how to reach them

Added in v0.231.0 To move every project of a Jira Cloud site at once, with one people mapping and the links between projects, use Move a whole Jira site.

SourceWays inWhat you'll need
JiraCloud, live APIYour Jira base URL, the account email, an API token, and the project key (case doesn't matter - orboto uppercases it automatically)
JiraAn XML export fileThe exported XML file from Jira
NotionLive APIA Notion internal-integration token; share the source database with the integration first
ClickUpLive APIA ClickUp API token and the list to import
Monday.comLive APIA Monday API token (Admin → API, or your personal token) and the board
LinearLive APIA Linear API key and the team key (e.g. ENG)
LinearA JSON export fileThe exported JSON file
GitHub IssuesLive APIA token, the repository owner, and the repository name
GitHub IssuesA JSON export fileThe exported JSON file
GitLab IssuesLive APIA personal access token and the project path
AsanaLive APIAn Asana API token
AsanaA JSON export fileThe exported JSON file
TrelloLive APIA Trello API key + token
TrelloA board JSON export fileThe exported board JSON
Azure DevOps / TFSLive APIThe org/collection base URL (cloud or on-prem), the project name, and a Personal Access Token with Work Items: Read
RedmineLive APIYour Redmine base URL and an API key
CSVAny spreadsheet exportA .csv file - column headers can be anything, you bind them manually in step 4

Where both a live-API and an export-file path exist for the same source, the live-API path pulls richer data (attachments, full comment threads, live user directory for better matching) than a static export - prefer it whenever you can mint the credentials. The export path exists for when you can't get API access (a decommissioned instance, a source system your new employer won't grant you a fresh token for) or the source no longer exists at all and only a downloaded archive survives.

The five-step wizard

Step 1 - pick the source

A grid of cards, one per adapter. Click one to move to configuration.

Step 2 - configure

The form here is generated from the chosen adapter's own field definitions, so it only ever asks for what that specific source needs (see the table above). A few things apply across every adapter:

  • Secret-looking fields (API tokens, passwords) render as password inputs so the value isn't visible on screen by default.
  • Whatever you type is cached on this device only - non-secret fields in local storage, tokens in session storage (cleared when you close the tab) - so re-importing from the same source later pre-fills the form. Clear saved config wipes this cache if you're on a shared machine or switching accounts.
  • A file-upload adapter (an export-based one, or CSV) shows a file picker instead of text fields; the file uploads and stages itself before you can continue, with a progress indicator and, once done, the filename and size shown back to you.
  • A link to that provider's own documentation for generating the credential you need sits right above the form, so you don't have to leave and hunt for it separately.

You can't continue until every required field is filled; optional fields are marked as such.

Step 3 - pick the target

Two choices, as radio options:

  • Create a new project - orboto names it after the source by default; you can rename it afterward. Optionally set the project key yourself here (2-10 uppercase letters/digits) - leave it empty and orboto derives one from the source name.
  • Merge into an existing project - pick from a searchable list of your existing projects. Added in v0.230.9 When that project already has tickets, the import is a merge: the preview says so and lists every ticket whose source number is already taken, and you confirm the merge twice before it runs (see step 5). Labels and milestones are matched to the target project's existing ones by name (see step 4's mapping tables for how to control this).

The default is a new, empty project: there every ticket keeps its source key.

Click Preview import to move on - this is where orboto actually talks to the source (or parses the uploaded file) for the first time.

Step 4 - preview and fix the mapping

The import preview step with the user, status and label mapping tables

You land here with a source summary (counts: users, milestones, labels, tickets, comments, time entries, dependencies) and any warnings orboto already noticed (e.g. a field it couldn't map automatically). Below that, a mapping table per entity type - only the tables relevant to what the source actually contains appear:

  • Users - one row per distinct source user. For each, pick from a dropdown: an existing orboto account (matched by email where possible, including previously-deactivated accounts from an earlier import so a re-import can land on the same person instead of forking a duplicate), Create placeholder user (no sign-in ability, but every ticket and comment they authored keeps correct attribution), or Skip this user (drops anything they were assigned, and their comments get re-attributed to you, the person running the import).
  • Ticket statuses - one row per distinct status value found in the source. Map each to one of the target project's real statuses, or leave it on the default ("project's first To Do status") if you don't care about preserving the exact workflow state on import.
  • Labels - one row per distinct label. Create from source name (default) or match it to an existing label in the target project.
  • Milestones - same pattern as labels: create from source name, or match to an existing milestone.

Added in v0.230.0 A label or milestone you match to an existing one must belong to the project you import into. A mapping that names a row of another project is refused with 400 (errors.admin_import.mapping_label_not_in_project or errors.admin_import.mapping_milestone_not_in_project) before anything is imported, on the direct and on the background-job path alike. An import that creates a new project has no existing labels or milestones to match, so there the only choice is Create from source name.

CSV only gets an extra screen before this one: column binding. orboto shows every column header it found in your file and asks you to pick which column feeds which orboto field (title, description, status, priority, type, assignee email, labels, milestone, due date, source key, source number). Title is the only required binding; leave the rest unbound to skip that field entirely for every row. Added in v0.230.9 With only the source key bound, the number is the key's trailing integer (ABC-12 -> 12).

Added in v0.230.9 Ticket keys. The preview shows the key the tickets get and how many keep their source number. A new project gets the source project key (Jira project key, Linear team key, repository name); if that key is taken or not a valid orboto key (2-10 letters or digits), the preview says why and proposes another one, which you can overwrite. Tickets keep their source numbers - Jira PROJ-280 stays PROJ-280, and gaps from deleted issues stay gaps. Tickets the source gives no number get the next numbers after the highest one. For a merge the preview lists every collision: the source key, the orboto ticket that already has that number, and the key the imported ticket gets instead.

Fix whatever the mapping table doesn't already get right, then click Apply import.

Step 5 - apply and review the result

Added in v0.230.9 A merge needs two confirmations before Apply import is enabled: tick I confirm the merge and type the target project key. Without both, the API refuses the import (409, errors.admin_import.merge_not_confirmed) and returns the collision list; the same two confirmations exist on the API (confirmMerge, confirmProjectKey), the MCP tool orboto_import_apply, the CLI (orboto import apply ... --confirm-merge --confirm-project-key KEY) and the in-app assistant. The result lists every ticket that got a different number, with its source key; the audit log records the same list.

Small imports apply immediately. Larger ones run as a background job instead, with a live progress bar so the browser tab never has to stay open and blocked on a long-running request.

Added in v0.230.5 The progress is written about once a second while the job runs, whatever the size of the import, and names the phase it is in:

PhaseWhat runsThe bar counts
WaitingThe job is queued for the import worker-
SetupThe project, users, milestones and labels are created-
TicketsEach ticket with its comments, worklogs and attachmentstickets applied / total
LinksParent tickets and dependencies are linkedlinks done / total
FinishingEvery staged ticket is checked as imported or failed-

Below the bar you see the comments and worklogs written so far and how many attachments were imported or skipped. Attachments download during the Tickets phase, so an import with many files spends most of its time there.

When it finishes you get:

  • A created count broken down by entity type.
  • Any warnings collected along the way.
  • For a background-job import specifically, a reconciliation line: how many of the staged rows actually landed vs. how many are unaccounted for. If any are missing, the specific source rows and the reason each one failed are listed so you can fix the underlying problem (a bad attachment reference, a field that didn't validate) and decide whether to re-run just that portion.
  • A direct Open project link into the freshly imported (or topped-up) project.

Added in v0.230.5 Admin -> Import lists your earlier imports under Recent imports, newest first. Open one to see its progress again while it runs, or its result after it finished, including the attachments it skipped.

Imports are transactional per project - if the apply step fails partway through, it does not leave a half-imported project behind; you get a clean failure to fix and retry, not a mess to clean up by hand.

Source keys on imported tickets

Added in v0.230.9 Every imported ticket remembers where it came from: the source system, its key there and its id there. The ticket shows Imported from Jira: PROJ-280 next to its dates. Search finds a ticket by its source key, OQL filters with sourceKey = "PROJ-280" or sourceSystem = "jira", and the ticket API, MCP and CLI return sourceSystem, sourceKey and sourceId.

Commits, branches and pull requests link by ticket key. Because the keys are kept, a commit that names PROJ-280 links to the imported PROJ-280. The live key of a ticket always wins; only a key no ticket holds is looked up as a source key - first in the project the repository is connected to, then in the whole workspace, and not at all when several tickets carry it - so a ticket a merge had to renumber is still found.

Projects imported before 0.230.9 keep their numbers: an update never renumbers a ticket. A project that was imported with the wrong numbers is deleted and imported again.

SourceKey keptNumber kept
Jira (API and XML)PROJ-280280
LinearENG-77
GitHubrepo#1212
GitLabgroup/project#1212 (iid)
Redmineidentifier#123123
Azure DevOpswork item idwork item id
Trello#12 (card number)12
ClickUpcustom task id, when enabledits number
Notionthe database's unique ID property, when it has oneits number
CSVthe bound key columnthe bound number column or the key's number
Asana, monday.com- (no ticket keys)-

What converts from Jira

Added in v0.232.0 orboto converts Jira descriptions, comments, worklog notes and rich-text custom fields into the orboto editor's format. Formatting, links and tables stay intact.

In JiraIn orboto
Bold, italic, strikethrough, inline codethe same formatting
Underline, subscript, superscriptthe same formatting, in the ticket view and in the editor
Text and background colourplain text
Linkslinks with the same target
Links and smart links (inline, block and embed cards) to an issue of the same Jira sitean orboto ticket link to the imported ticket, also when it got another key (a project key you changed, or a number already taken in a merge)
Headings (levels 1 to 6)headings of the same level
Bulleted and numbered lists, nested listslists, nested the same way; numbered lists keep their start number
Action items and decisionschecklist lines (- [ ] / - [x]) with their done state; you can turn them into a ticket checklist
Code blockscode blocks with their language
Quotes and dividersquotes and dividers
Info, note, warning, error and success panelsquotes that start with the panel type in your workspace language, for example Warning or Warnung
Expandsa bold title followed by the content
Tablestables; a table with lists, code or merged cells keeps them inside its cells, header cells stay header cells or read bold
Mentionsan orboto mention of the person the Jira account is mapped to (an existing user, or the user the import creates); a person you skip in the mapping stays @Name text. The import sends no mention notifications
Emojithe emoji; custom site emoji keep their short name, for example :party:
Status lozengescoloured status badges
Datesthe date as YYYY-MM-DD, the same day for every reader
Images and attachmentsimages and files of the imported ticket, as before

Anything orboto has no equivalent for (for example app macros) keeps its text. The import preview and the import result list each such element type with how often it occurred, so nothing disappears without notice. In the Jira site import they appear as content warnings per issue.

Jira XML export

Imports from a Jira XML export convert Jira wiki markup the same way: headings, text effects, links (including [KEY-123] issue links and [~user] mentions), tables, lists, code and noformat blocks, quotes and panels.

Tickets imported earlier

Tickets imported before 0.232.0 keep the text they were imported with until you repair them:

  • Jira Cloud (live API) imports: open the finished import's result in the admin import page and run Jira layout (or POST /admin/import/jobs/<token>/layout/restore with the Jira credentials). It rewrites every description and comment nobody edited since the import with the current conversion, from Jira. Edited text stays as it is and is listed.
  • Jira site imports and Jira XML exports: delete the imported project and import it again.

Attachments

The live-API sources download each attachment while its ticket is written, with the credentials you entered, sent only to the source's own address. A file above 50 MB, or a file after 2 GB of attachments in one run, is skipped with a warning.

Added in v0.230.5 Jira Cloud attachments are requested with redirect=false, so Jira returns the file itself instead of a redirect to its media service. Imports before 0.230.5 skipped every Jira attachment with the warning Attachment <name> (<id>) HTTP 406; skipped.

Recovering skipped attachments

Added in v0.230.5 When an import skipped attachments, its result shows Skipped attachments: every skipped file with its ticket, whether it sits on the ticket or on a comment, its state and the reason it was skipped. To fetch them into the tickets that were already imported, without importing the project again:

  1. Open the import under Admin -> Import -> Recent imports.
  2. Under Skipped attachments, enter the source credentials again (for Jira: base URL, account email, API token and project key). They are used for this run only, sent only to the address the import came from, and never stored.
  3. Click Fetch missing attachments. orboto downloads the files in batches of 25 and shows how many were recovered, which still fail and why.

Each file lands on the ticket or comment it belonged to, and links to it in the description or the comment point at the new file. Running the recovery again is safe: orboto records every file it recovers, and an attachment an earlier run already recovered is skipped, so nothing is duplicated. Two files with the same name are two attachments and are both fetched. Credentials for a different instance than the one the import came from are refused. If the import's staged data can no longer be read completely, the recovery refuses to run (409, errors.admin_import.recovery_staged_incomplete) instead of attaching files to the wrong tickets.

The recovery is also reachable through the API (permission admin:import, each run is recorded in the audit log):

  • GET /admin/import/jobs - the imports of this instance, newest first.
  • GET /admin/import/jobs/{token}/attachments - the skipped attachments of an import with their state.
  • POST /admin/import/jobs/{token}/attachments/recover with { "config": { ...the adapter's fields... }, "from": 0 } - fetches up to 25 missing files per call and answers next; call again with from set to next until it is null.

Agents reach these endpoints through the generic API tools of the MCP server.

Embedded images and files

Added in v0.230.6 An image or file embedded in a description or a comment links to the attachment it shows, at the place it had in the source:

  • An image renders inline: on its own line when it stood on its own line in the source, inside the text when it sat in a sentence. Any other file (a PDF, a video, a file card) becomes a link with the file name.
  • Jira Cloud names an embedded file by its media file id, not by its attachment. orboto asks Jira which attachment belongs to that id, with the credentials of the import and only at the Jira address. Content Jira never linked to a media file (often text migrated from Jira Server) names the file only by its name; orboto picks the attachment with that name, and when several share it, the one attached last, which is the one Jira shows too.
  • Jira XML: !name.png! images and [^name.pdf] file links resolve by the same rule.
  • Azure DevOps: images pasted into a work item are imported with its description or comment.
  • An image from an external address keeps that address.
  • A file orboto cannot match to any attachment of the ticket shows as a Missing attachment badge followed by the file name, never as a broken image. The preview and the import result count each one in their warnings (Embedded attachment <name> ... could not be resolved).
  • When Jira gives no definite answer for a media file id (an error or a timeout), the image stays as a placeholder instead of the badge, and the import result warns about it; relink the import later to link it.

Relinking embedded images of an earlier import

Added in v0.230.6 Imports from Jira Cloud before 0.230.6 left every embedded image or file as a placeholder such as ![grafik.png](attachment:UNKNOWN_MEDIA_grafik.png), which shows no image. To link them to the attachments without importing again:

  1. Open the import under Admin -> Import -> Recent imports.
  2. If Skipped attachments lists missing files, fetch them first (see Recovering skipped attachments).
  3. Under Embedded images and files, check the counts: how many can be linked now, how many have no matching attachment, how many match several files with the same name, how many still wait for the recovery and how many need the source credentials.
  4. Placeholders that carry a Jira media file id need the source credentials (base URL, account email, API token and project key); they are used for this run only, sent only to the address the import came from, and never stored. Placeholders that carry a file name link without them.
  5. Click Link embedded images and files. orboto rewrites the descriptions and comments in batches of 25 tickets.

A placeholder whose file has no attachment on the ticket becomes the Missing attachment badge with the file name; one whose file several attachments of the ticket share under the same name, and that the recovery did not fetch, becomes the badge too, since the import cannot tell those files apart. A placeholder whose file is still missing stays until a later run after the recovery links it. A media file id Jira gave no definite answer for (an error or a timeout) stays as well and is counted separately; run the relink again later. A comment that changes keeps its previous text as a revision. Running the relink again changes nothing that is already linked.

Through the API (permission admin:import, each run is recorded in the audit log):

  • GET /admin/import/jobs/{token}/embedded-media - the placeholders of an import with their state and the counts.
  • POST /admin/import/jobs/{token}/embedded-media/relink with { "from": 0 }, or { "config": { ...the adapter's fields... }, "from": 0 } for media file ids - relinks up to 25 tickets per call and answers next; call again with from set to next until it is null.

Restoring the Jira layout of an earlier import

Added in v0.230.9 Imports from Jira Cloud before 0.230.6 glued block images to each other and to the paragraph that followed them, so the images render as small pictures at text height inside one line, even after the relink above linked them. orboto only stored the converted text, so the original layout is read again from Jira:

  1. Fetch any skipped attachments and relink the embedded images first (the two steps above).
  2. Under Jira layout, check the counts: how many images render as blocks, how many sit in a line of text and how many sit in a line with another image.
  3. Enter the Jira credentials (base URL, account email, API token and project key). They are used for this run only, sent only to the address the import came from, and never stored.
  4. Click Restore the Jira layout. orboto reads each imported issue's description and comments from Jira, in batches of 10 tickets, and rewrites them with the current conversion, every block image in its own paragraph.

orboto rewrites a description or comment only when its text is still exactly what the import and the relink wrote. Everything else stays as it is and is listed with the reason:

  • Edited since the import - someone changed the text in orboto.
  • Changed in Jira since the import - the text is unchanged in orboto, but the issue or comment changed in Jira; restoring it would bring in that change, so it is left alone.
  • No longer in Jira - the issue or comment was deleted, or the account cannot see it.
  • Jira gave no definite answer - an error or a timeout; run the restore again later.
  • An embedded file is still missing - fetch the skipped attachments, then run the restore again.

A comment that changes keeps its previous text as a revision, and no notification is sent. Running the restore again changes nothing that is already restored. Images inside text stay small on purpose; every image in a description, a comment or a doc opens full size when you click it (Esc closes it).

Through the API (permission admin:import, each run is recorded in the audit log):

  • GET /admin/import/jobs/{token}/layout - the images of the import by placement (block, next to text, next to another image), the figure to compare before and after.
  • POST /admin/import/jobs/{token}/layout/restore with { "config": { ...the adapter's fields... }, "from": 0 } - restores up to 10 tickets per call (limit up to 50), lists what it left as is in items and answers next; call again with from set to next until it is null.

Notes

  • Added in v0.230.9 Imported tickets keep their source key and number (see "Source keys on imported tickets"), so an old link - a Jira issue key, a GitHub issue number someone bookmarked - points at the same ticket in orboto.
  • AI features (semantic search, duplicate detection) index imported content automatically once the import completes - there's no separate "reindex after import" step to remember.
  • Re-running an import creates new items every time - it does not detect or skip anything it already imported in a previous run. Deduplicate at the source before re-importing the same data twice, or merge deliberately into the same target project and accept the duplicates if that's actually what you want.
  • Added in v0.230.0 Every answer of the source system is read up to 16 MB, and a request to it ends after 60 seconds, its body included. An answer above the cap fails that request and the import reports the error. See Connected services.
  • Imports write content in the workspace's expected language (Admin -> System settings -> Workspace language). Content that arrives in a different language still imports successfully, but degrades search and AI features for that content - watch for a repeated language-mismatch warning across a batch as a sign the batch itself may be the wrong language for this workspace, not a bug in the import.

Troubleshooting

  • The configure step rejects your credentials before you even get to preview - double-check the base URL for any self-hosted source (Jira Server/Data Center, GitLab self-managed, Redmine, Azure DevOps Server all need their OWN instance URL, never the vendor's cloud default), and confirm the token actually has read access to the specific project/team you named, not just to your account in general.
  • CSV preview shows zero tickets - the column-binding step hasn't run yet, or the Title column specifically wasn't bound to anything. Go back one step and bind it - it's the only required column.
  • A user keeps showing "create placeholder" even though they clearly already have an orboto account - the source's email for them doesn't exactly match the existing account's email (a common cause: they changed email addresses since the source system was set up). Pick them manually from the mapping dropdown instead of relying on the automatic email match.
  • Unmapped statuses all collapsed onto "To Do" - that's the documented fallback for anything left unmapped in the Statuses table; go back and map them explicitly before applying if preserving the exact workflow state matters, since it's far easier to fix here than to bulk-move tickets after the fact.
  • Every Jira attachment was skipped with HTTP 406 - the import ran on a version before 0.230.5. Update, open the import under Recent imports and fetch the missing attachments (see Recovering skipped attachments).
  • Images in imported Jira descriptions or comments show nothing - the import ran on a version before 0.230.6. Fetch any skipped attachments, then relink the placeholders (see Relinking embedded images of an earlier import).
  • Imported Jira images are tiny and stuck to the next line of text - the import ran on a version before 0.230.6. Restore the Jira layout (see Restoring the Jira layout of an earlier import).
  • The result screen shows tickets "unaccounted for" - only happens on the background-job path; it means the reconciliation pass found staged rows that neither landed as tickets nor were recorded as failures. Read the listed reasons for the specific rows, fix the underlying issue, and re-run just that source data if it's worth the effort - otherwise treat it as a small number of rows to recreate by hand.

On this page