diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,24 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 0.8.3.0 - 2024-05-03
+
+### Fixed
+
+- Deduplicate OpenAPI3 security / jwt items
+- Replace bad generated OpenAPI3 identifier
+
+### Added
+- `O3.ToParamSchema JobType`
+- `instance HasField "get"` for `PagedJobs`
+- `getJobs`: Add `rev`, `handler`, `name` query params
+- `instance ToParamSchema JobType`
+- `Hercules.API.ShowRead` wrapper
+deea4 doc: API / Find jobs: refer to per project endpoint
+- `NotPlanned` derivation status
+- Document auth instructions in API description
+- Add `references` to `BuiltOutput`
+
 ## 0.8.2.0 - 2024-02-12
 
 ### Added
diff --git a/hercules-ci-api.cabal b/hercules-ci-api.cabal
--- a/hercules-ci-api.cabal
+++ b/hercules-ci-api.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               hercules-ci-api
-version:            0.8.2.0
+version:            0.8.3.0
 synopsis:           Hercules CI API definition with Servant
 homepage:           https://github.com/hercules-ci/hercules-ci-agent#readme
 bug-reports:        https://github.com/hercules-ci/hercules-ci-agent/issues
@@ -18,7 +18,6 @@
 common defaults
   default-language:   Haskell2010
   default-extensions:
-    NoImplicitPrelude
     DeriveGeneric
     DeriveTraversable
     DerivingStrategies
@@ -28,6 +27,7 @@
     InstanceSigs
     LambdaCase
     MultiParamTypeClasses
+    NoImplicitPrelude
     OverloadedStrings
     RankNTypes
     TupleSections
@@ -128,6 +128,7 @@
     Hercules.API.Repos.SimpleRepo
     Hercules.API.Result
     Hercules.API.Servant.Status
+    Hercules.API.ShowRead
     Hercules.API.SimpleAttribute
     Hercules.API.State
     Hercules.API.State.ProjectState
diff --git a/hercules-gen-swagger/Main.hs b/hercules-gen-swagger/Main.hs
--- a/hercules-gen-swagger/Main.hs
+++ b/hercules-gen-swagger/Main.hs
@@ -4,7 +4,9 @@
 where
 
 import Data.Aeson (encode)
+import Data.Function ((&))
 import Data.String.Conv (toS)
+import Data.Text qualified as T
 import Hercules.API (openapi3, swagger)
 import System.Environment (getArgs)
 import System.IO (hPutStrLn, stderr)
@@ -14,7 +16,13 @@
 main = do
   args <- getArgs
   case args of
-    ["--experimental-openapi3"] -> putStrLn $ toS $ encode openapi3
+    ["--experimental-openapi3"] ->
+      putStrLn $
+        openapi3
+          & encode
+          & toS
+          & T.replace "Attribute_(Result_AttributeError_Derivation)" "Attribute_Result_AttributeError_Derivation"
+          & toS
     [] -> putStrLn $ toS $ encode swagger
     _ -> do
       hPutStrLn stderr "Usage: hercules-gen-swagger [--experimental-openapi3] > swagger.json"
diff --git a/src/Hercules/API.hs b/src/Hercules/API.hs
--- a/src/Hercules/API.hs
+++ b/src/Hercules/API.hs
@@ -33,6 +33,7 @@
 
 import Control.Lens
 import Control.Monad
+import Data.List qualified as L
 import Data.OpenApi qualified as O3
 import Data.Proxy (Proxy (..))
 import Data.Swagger hiding (Header)
@@ -126,7 +127,7 @@
       .~ "v1"
     & info
       . description
-      ?~ "You have reached the Hercules Continuous Integration Application Programming Interface. This user interface provides human friendly access to the various endpoints. To get started with Hercules CI, see hercules-ci.com. Happy building! —the Hercules team"
+      ?~ "You have reached the Hercules Continuous Integration Application Programming Interface. This user interface provides human friendly access to the various endpoints. To get a personal access token, use the `hci login` command and inspect `~/.config/hercules-ci/credentials.json`. Unquote the token and put it in a header as `Authorization: Bearer eyJ...`. To get started with Hercules CI, see hercules-ci.com. Happy building! —the Hercules team"
     & withTags clientProjects "project" "Project and job operations"
     & withTags clientBuild "build" "Build related operations"
     & withTags clientEffects "effect" "Effect related operations"
@@ -146,7 +147,14 @@
 
 -- | NOTE: this has not been tested yet.
 openapi3 :: O3.OpenApi
-openapi3 = SO3.toOpenApi apiWithJWT
+openapi3 =
+  SO3.toOpenApi apiWithJWT
+    -- It's generating a lot of duplicate security requirements, so let's deduplicate them.
+    & O3.security %~ (uniq . L.sortOn show)
+  where
+    -- Remove duplicates from a sorted list. (No custom prelude in this package for ordNub)
+    uniq (a1 : a2 : as) = if a1 == a2 then uniq (a2 : as) else a1 : uniq (a2 : as)
+    uniq as = as
 
 clientApiProxy :: (ClientAPI (Auth '[JWT] ()) AsApi -> a) -> Proxy ("api" :> "v1" :> a)
 clientApiProxy _ = Proxy
diff --git a/src/Hercules/API/Build/DerivationEvent/BuiltOutput.hs b/src/Hercules/API/Build/DerivationEvent/BuiltOutput.hs
--- a/src/Hercules/API/Build/DerivationEvent/BuiltOutput.hs
+++ b/src/Hercules/API/Build/DerivationEvent/BuiltOutput.hs
@@ -10,7 +10,9 @@
   { outputName :: Text,
     outputPath :: Text,
     hash :: Text,
-    size :: Int64
+    size :: Int64,
+    -- | Always 'Just' when agent >=0.10.1.
+    references :: Maybe [Text]
   }
   deriving (Generic, Show, Eq)
   deriving anyclass (NFData, ToJSON, FromJSON, ToSchema, O3.ToSchema)
diff --git a/src/Hercules/API/Derivation.hs b/src/Hercules/API/Derivation.hs
--- a/src/Hercules/API/Derivation.hs
+++ b/src/Hercules/API/Derivation.hs
@@ -20,7 +20,8 @@
   deriving anyclass (NFData, ToJSON, FromJSON, ToSchema, O3.ToSchema)
 
 data DerivationStatus
-  = Waiting
+  = NotPlanned
+  | Waiting
   | Building
   | BuildFailure
   | DependencyFailure
diff --git a/src/Hercules/API/Projects.hs b/src/Hercules/API/Projects.hs
--- a/src/Hercules/API/Projects.hs
+++ b/src/Hercules/API/Projects.hs
@@ -5,6 +5,7 @@
 module Hercules.API.Projects where
 
 import Data.OpenApi qualified as O3
+import GHC.Records (HasField (getField))
 import Hercules.API.Accounts.Account (Account)
 import Hercules.API.Build.EvaluationDetail
   ( EvaluationDetail,
@@ -22,6 +23,7 @@
 import Hercules.API.Projects.CreateUserEffectTokenResponse (CreateUserEffectTokenResponse)
 import Hercules.API.Projects.Job
   ( Job,
+    JobType,
     ProjectAndJobs,
   )
 import Hercules.API.Projects.JobHandlers (JobHandlers)
@@ -58,6 +60,9 @@
         :- Summary "Retrieve information about jobs"
           :> "jobs"
           :> QueryParam' '[Optional, Description "Constrain the results by git ref, such as refs/heads/my-branch or HEAD"] "ref" Text
+          :> QueryParam' '[Optional, Description "Git commit hash (from which to load the job handler definition)"] "rev" (Name "Rev")
+          :> QueryParam' '[Optional, Description "Job handler type, such as onPush or onSchedule"] "handler" JobType
+          :> QueryParam' '[Optional, Description "Job handler name, such as <name> in onPush.<name>"] "name" (Name "JobName")
           :> QueryParam' '[Optional, Description "Only return successful jobs, or only failed ones"] "success" Bool
           :> QueryParam' '[Optional, Description "Return jobs that come \"after\" the provided id in the response order."] "offsetId" (Id Job)
           :> QueryParam' '[Optional, Description "Return jobs that come \"after\" the provided index in the response order."] "offsetIndex" Int64
@@ -139,7 +144,8 @@
           :> Post '[JSON] CreateUserEffectTokenResponse,
     findJobs ::
       f
-        :- Summary "Find jobs"
+        :- Summary "Find jobs in multiple projects at once"
+          :> Description "For a more powerful single project endpoint, see /api/v1/site/{site}/account/{account}/project/{project}/jobs"
           :> "jobs"
           :> QueryParam' '[Optional, Description "Currently only \"github\" or omit entirely"] "site" (Name Forge)
           :> QueryParam' '[Optional, Description "Account name filter"] "account" (Name Account)
@@ -248,3 +254,5 @@
 newtype PagedJobs = PagedJobs (PagedResponse Job)
   deriving (Generic, Show, Eq)
   deriving anyclass (NFData, ToJSON, FromJSON, ToSchema, O3.ToSchema)
+
+instance HasField "get" PagedJobs (PagedResponse Job) where getField (PagedJobs a) = a
diff --git a/src/Hercules/API/Projects/Job.hs b/src/Hercules/API/Projects/Job.hs
--- a/src/Hercules/API/Projects/Job.hs
+++ b/src/Hercules/API/Projects/Job.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE DerivingVia #-}
 
 module Hercules.API.Projects.Job
   ( module Hercules.API.Projects.Job,
@@ -9,6 +10,7 @@
 where
 
 import Data.OpenApi qualified as O3
+import Data.Swagger (ToParamSchema)
 import Hercules.API.Accounts.Account (Account)
 import Hercules.API.Evaluation.Evaluation
   ( Evaluation,
@@ -19,6 +21,8 @@
 import Hercules.API.Projects.Project (Project)
 import Hercules.API.Projects.SimpleJob (JobPhase (..), JobStatus (..))
 import Hercules.API.Repos.Repo (Repo)
+import Hercules.API.ShowRead (ShowRead (ShowRead))
+import Web.HttpApiData (FromHttpApiData, ToHttpApiData)
 
 data Job = Job
   { id :: Id Job,
@@ -57,8 +61,9 @@
   | Legacy
   | OnPush
   | OnSchedule
-  deriving (Generic, Show, Eq)
-  deriving anyclass (NFData, ToJSON, FromJSON, ToSchema, O3.ToSchema)
+  deriving (Generic, Eq, Enum, Bounded, Show, Read)
+  deriving anyclass (NFData, ToJSON, FromJSON, ToSchema, ToParamSchema, O3.ToSchema, O3.ToParamSchema)
+  deriving (ToHttpApiData, FromHttpApiData) via (ShowRead JobType)
 
 data GitCommitSource = GitCommitSource
   { revision :: Text,
diff --git a/src/Hercules/API/ShowRead.hs b/src/Hercules/API/ShowRead.hs
new file mode 100644
--- /dev/null
+++ b/src/Hercules/API/ShowRead.hs
@@ -0,0 +1,22 @@
+module Hercules.API.ShowRead
+  ( ShowRead (ShowRead),
+  )
+where
+
+import Data.Either (Either (Right))
+import Data.Text qualified as T
+import Web.HttpApiData (FromHttpApiData (parseQueryParam), ToHttpApiData)
+import Web.Internal.HttpApiData (ToHttpApiData (toUrlPiece))
+import Prelude (Either (Left), Read, Show (show), reads)
+
+-- | A newtype wrapper for using 'Show' and 'Read' instances with @DerivingVia@.
+newtype ShowRead a = ShowRead a
+
+instance (Show a) => ToHttpApiData (ShowRead a) where
+  toUrlPiece (ShowRead a) = toUrlPiece (T.pack (show a))
+
+instance (Read a) => FromHttpApiData (ShowRead a) where
+  parseQueryParam t =
+    case reads (T.unpack t) of
+      [(a, "")] -> Right (ShowRead a)
+      _ -> Left "Could not parse"
