diff --git a/modules/common/src/main/scala/docspell/common/Duration.scala b/modules/common/src/main/scala/docspell/common/Duration.scala
index 9c5cdd20..1f837196 100644
--- a/modules/common/src/main/scala/docspell/common/Duration.scala
+++ b/modules/common/src/main/scala/docspell/common/Duration.scala
@@ -4,7 +4,7 @@ import cats.implicits._
 import scala.concurrent.duration.{FiniteDuration, Duration => SDur}
 import java.time.{Duration => JDur}
 import java.util.concurrent.TimeUnit
-
+import io.circe._
 import cats.effect.Sync
 
 case class Duration(nanos: Long) {
@@ -54,4 +54,11 @@ object Duration {
       now <- Timestamp.current[F]
       end = Timestamp.current[F]
     } yield end.map(e => Duration.millis(e.toMillis - now.toMillis))
+
+
+  implicit val jsonEncoder: Encoder[Duration] =
+    Encoder.encodeLong.contramap(_.millis)
+
+  implicit val jsonDecoder: Decoder[Duration] =
+    Decoder.decodeLong.map(Duration.millis)
 }
diff --git a/modules/common/src/main/scala/docspell/common/ScanMailboxArgs.scala b/modules/common/src/main/scala/docspell/common/ScanMailboxArgs.scala
new file mode 100644
index 00000000..f84e30ea
--- /dev/null
+++ b/modules/common/src/main/scala/docspell/common/ScanMailboxArgs.scala
@@ -0,0 +1,42 @@
+package docspell.common
+
+import io.circe._, io.circe.generic.semiauto._
+import docspell.common.syntax.all._
+
+/** Arguments to the poll-mailbox task.
+  *
+  * This tasks queries user mailboxes and pushes found mails into
+  * docspell for processing.
+  *
+  * If the structure changes, there must be some database migration to
+  * update or remove the json data of the corresponding task.
+  */
+case class ScanMailboxArgs(
+    // the docspell user account
+    account: AccountId,
+    // the configured imap connection
+    imapConnection: Ident,
+    // what folders to search
+    folders: List[String],
+    // only select mails received since then
+    receivedSince: Option[Duration],
+    // move submitted mails to another folder
+    targetFolder: Option[String],
+    // delete the after submitting (only if targetFolder is None)
+    deleteMail: Boolean,
+    // set the direction when submitting
+    direction: Option[Direction]
+)
+
+object ScanMailboxArgs {
+
+  val taskName = Ident.unsafe("scan-mailbox")
+
+  implicit val jsonEncoder: Encoder[ScanMailboxArgs] =
+    deriveEncoder[ScanMailboxArgs]
+  implicit val jsonDecoder: Decoder[ScanMailboxArgs] =
+    deriveDecoder[ScanMailboxArgs]
+
+  def parse(str: String): Either[Throwable, ScanMailboxArgs] =
+    str.parseJsonAs[ScanMailboxArgs]
+}