Todoist Export Nushell

Editor’s Note: Fixed some typos and the list numbering not working. See diff

I have recently changed how I use Todoist, but before doing so, I exported all (okay, I think it was more like most of) my data.

Since I exported all of my data once, I now want to export and back up my Todoist data regularly.

Here is how to get most of your data from Todoist using Nushell:

I’m going to assume you have Nushell installed. If not, install Nushell.

I would probably recommend doing so in Homebrew:

brew install nushell

But I’m not sure, because I installed Nushell before I realized I should be installing as much of my software through a package manager as possible.

  1. Get your API key from Todoist.

    Be aware that this API key has, as far as I can tell, admin-level permissions for your Todoist account.

    Whatever you can do through the GUI, the API key allows you authorization to do. You can only have 1 API key at a time. You can’t restrict the API key in any way.

    You can revoke the API key by clicking the Issue a new API token button (on the same page). But that is going to log you out of all Todoist sessions, which is super annoying if you are logged into Todoist in Chrome, your phone and have a bunch of scripts and widgets using that API key.

  2. Set the API key as the TODOIST_API_TOKEN environment variable

  3. Copy this in as sync.nu:

     #! /usr/bin/env nu
    
     use std log
    
     const COMPLETED_TASKS_MAX_LIMIT = 200
     const ARCHIVED_SECTIONS_MAX_LIMIT = 100
    
     def get-sync-data [] {
         log info "Getting sync data"
         let result = http post --headers [ "Authorization" $"Bearer ($env.TODOIST_API_TOKEN)" ] --content-type "application/x-www-form-urlencoded" https://api.todoist.com/sync/v9/sync { sync_token: "*", resource_types: '["all"]' }
         $result
     }
    
     def get-completed-tasks-with-offset [offset: int] {
         log info $"Getting completed tasks with offset: ($offset)"
         const annotate_notes = true
         const annotate_items = true
         const limit = $COMPLETED_TASKS_MAX_LIMIT
         let url = $"https://api.todoist.com/sync/v9/completed/get_all?limit=($limit)&annotate_notes=($annotate_notes)&annotate_items=($annotate_items)&offset=($offset)"
    
         let result = http post --headers [ "Authorization" $"Bearer ($env.TODOIST_API_TOKEN)" ] --content-type "application/x-www-form-urlencoded" $url { sync_token: "*", resource_types: '["all"]' }
            
         $result
     }
    
     def get-completed-tasks [] {
         mut results = []
         mut offset = 0
    
         while true {
             let result = get-completed-tasks-with-offset $offset
             $results = $results | append $result
             $offset += $COMPLETED_TASKS_MAX_LIMIT
    
             if ($result | get items | is-empty) {
                 break
             }
         }
    
         $results
     }
    
     def get-stats [] {
         log info "Getting stats"
         let result = http get --headers [ "Authorization" $"Bearer ($env.TODOIST_API_TOKEN)" ] https://api.todoist.com/sync/v9/completed/get_stats
         $result
     }
    
  4. Copy this in as runner.nu:

     #! /usr/bin/env nu
    
     const RFC3339_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
    
     source ./sync.nu
    
    
     let sync_data = get-sync-data
     let completed_tasks = get-completed-tasks
     let completed_tasks_stats = get-stats
    
    
     let endpoints = {
         "sync": $sync_data,
         "completed/get_all": $completed_tasks,
         "completed/get_stats": $completed_tasks_stats
     }
    
     let metadata = {
     "created_at": (date now | format date $RFC3339_FORMAT),
     }
    
     let result =  {endpoints: $endpoints, metadata: $metadata}
    
    
     $result | save -f todoist-export.json
    
  5. Run nu runner.nu in your terminal.

    You should get a file called todoist-export.json in the same directory as the script.