todoist-sdk: Unofficial Haskell SDK for the Todoist REST API

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

TodoistSDK provides a type-safe, tagless-final interface to the Todoist REST API. It includes comprehensive coverage of Projects, Tasks, Comments, Sections, and Labels endpoints with both real HTTP and tracing interpreters for testing. The library uses mtl-style type classes for operation definitions and provides a clean builder pattern for request construction.


[Skip to Readme]

Properties

Versions 0.1.1.1, 0.1.2.1
Change log CHANGELOG.md
Dependencies aeson (>=2.2.3.0 && <2.3), base (>=4.7 && <5), bytestring (>=0.12.2.0 && <0.12.3), req (>=3.13.4 && <3.14), text (>=2.1.2 && <2.2), todoist-sdk, transformers (>=0.6.1.1 && <0.6.2.0) [details]
License MIT
Copyright 2025 Sam S. Almahri
Author Sam S. Almahri
Maintainer sam.salmahri@gmail.com
Category Web
Home page https://github.com/samahri/TodoistSDK
Bug tracker https://github.com/samahri/TodoistSDK/issues
Source repo head: git clone https://github.com/samahri/TodoistSDK
Uploaded by samahri at 2025-11-15T06:29:02Z

library todoist-sdk

Modules

  • Web
    • Web.Todoist
      • Domain
        • Web.Todoist.Domain.Comment
        • Web.Todoist.Domain.Label
        • Web.Todoist.Domain.Project
        • Web.Todoist.Domain.Section
        • Web.Todoist.Domain.Task
        • Web.Todoist.Domain.Types
      • Web.Todoist.Runner
        • Web.Todoist.Runner.IO
          • Web.Todoist.Runner.IO.Core
          • Web.Todoist.Runner.IO.Interpreters
        • Web.Todoist.Runner.Trace
      • Util
        • Web.Todoist.Util.Builder
        • Web.Todoist.Util.QueryParam

library todoist-sdk:todoist-sdk-internal

Modules

  • Web
    • Todoist
      • Internal
        • Web.Todoist.Internal.Config
        • Web.Todoist.Internal.Error
        • Web.Todoist.Internal.HTTP
        • Web.Todoist.Internal.Json
        • Web.Todoist.Internal.Request
        • Web.Todoist.Internal.Types

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for todoist-sdk-0.1.1.1

[back to package description]

TodoistSDK

Hackage

An unofficial Haskell SDK for the Todoist REST API. Manage projects, tasks, comments, sections, and labels with type-safe, ergonomic Haskell functions.

Features

Installation

Using Stack

Add to your stack.yaml:

extra-deps:
  - todoist-sdk-0.1.1.1

Add to your package.yaml or .cabal file:

dependencies:
  - todoist-sdk

Using Cabal

Add to your .cabal file's build-depends:

build-depends:
    base >=4.7 && <5
  , todoist-sdk

Then install:

cabal update
cabal install todoist-sdk

Quick Start

Get your API token from Todoist Settings → Integrations → Developer.

Try it in the REPL

$ stack repl
>>> import Web.Todoist
>>> let config = newTodoistConfig "your-api-token-here"
>>> result <- todoist config getAllProjects
>>> case result of
      Left err -> print err
      Right projects -> mapM_ print projects

Complete Example

Create a file example.hs:

#!/usr/bin/env stack
-- stack --resolver lts-24.7 script --package todoist-sdk --package text

{-# LANGUAGE OverloadedStrings #-}

import Web.Todoist

main :: IO ()
main = do
    -- Configure with your API token
    let config = newTodoistConfig "your-api-token-here"

    result <- todoist config $ do
        -- Create a new project
        let newProj = runBuilder (newProject "My Haskell Project")
                      (setDescription "Learning Haskell SDK" <> setViewStyle Board)
        project <- addProject newProj

        -- Create a task in the project
        let newTask = runBuilder (newTask "Read documentation")
                      (setProjectId (_id project) <> setPriority 2)
        task <- addTask newTask

        -- Get all tasks
        tasks <- getTasks emptyTaskParam

        pure (project, task, tasks)

    case result of
        Left err -> putStrLn $ "Error: " ++ show err
        Right (proj, task, tasks) -> do
            putStrLn $ "Created project: " ++ show (_name proj)
            putStrLn $ "Created task: " ++ show (_content task)
            putStrLn $ "Total tasks: " ++ show (length tasks)

Run it:

chmod +x example.hs
./example.hs

Common Usage Examples

Working with Projects

import Web.Todoist

let config = newTodoistConfig "your-api-token"

-- Get all projects
result <- todoist config getAllProjects

-- Create a project with optional fields
let newProject = runBuilder (newProject "Shopping List")
                 (setColor "blue" <> setViewStyle List <> setIsFavorite True)
project <- todoist config (addProject newProject)

-- Update a project
let update = runBuilder emptyProjectUpdate (setName "Updated Name")
updated <- todoist config (updateProject update projectId)

-- Delete a project
todoist config (deleteProject projectId)

Working with Tasks

-- Create a task with due date
let task = runBuilder (newTask "Buy milk")
           (setProjectId "project-123"
            <> setDueString "tomorrow"
            <> setPriority 3
            <> setLabelIds ["grocery", "urgent"])
result <- todoist config (addTask task)

-- Get tasks with filters
let params = TaskParam
    { project_id = Just "project-123"
    , filter = Nothing
    , label_id = Nothing
    , cursor = Nothing
    , limit = Nothing
    }
tasks <- todoist config (getTasks params)

-- Complete a task
todoist config (closeTask taskId)

-- Update a task
let update = runBuilder emptyTaskPatch (setContent "Buy 2% milk")
updated <- todoist config (updateTask update taskId)

Working with Comments

-- Add a comment to a task
let comment = runBuilder (newComment "Don't forget organic!")
              (setTaskId "task-456")
result <- todoist config (addComment comment)

-- Get all comments for a project
let params = CommentParam
    { project_id = Just "project-123"
    , task_id = Nothing
    , cursor = Nothing
    , limit = Nothing
    , public_key = Nothing
    }
comments <- todoist config (getComments params)

Working with Sections

-- Create a section
let section = runBuilder (newSection "In Progress" "project-123") mempty
result <- todoist config (addSection section)

-- Get sections for a project with builder pattern
let params = runBuilder newSectionParam (setProjectId "project-123" <> setLimit 50)
sections <- todoist config (getSections params)

Working with Labels

-- Create a label
let label = runBuilder (newLabel "urgent") mempty
result <- todoist config (addLabel label)

-- Get all labels
let params = runBuilder newLabelParam (setLimit 50)
labels <- todoist config (getLabels params)

Error Handling

All operations return Either TodoistError a. The TodoistError type includes:

Example:

result <- todoist config (getProject projectId)
case result of
    Left BadRequest -> putStrLn "Invalid project ID"
    Left Unauthorized -> putStrLn "Check your API token"
    Left NotFound -> putStrLn "Project not found"
    Left (HttpError msg) -> putStrLn $ "HTTP error: " ++ msg
    Right project -> print project

Documentation

Full API documentation is available on Hackage.

For details on the Todoist REST API, see the official documentation.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

This library is a labor of love to the Haskell community and to the Todoist app. It is an unofficial SDK and is not affiliated with or endorsed by Doist.