diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,15 @@
 
 `fedora-releases` uses [PVP Versioning](https://pvp.haskell.org).
 
-## 0.1.0
+## 0.2.0 (2024-12-04)
+- newerBranch now returns Maybe Branch
+- custom Ord Branch instance to correct the order of EPELNext
+- export extended Distribution.Fedora.BodhiReleases
+- getActiveReleases replaces getReleases (no longer reversed)
+- getActiveBranches (reverse sorted) replaces getFedoraBranches
+- similarly getActiveBranched replaces getFedoraBranched
+
+## 0.1.0 (2024-08-16)
 - project renamed from [fedora-dists](https://hackage.haskell.org/package/fedora-dists) to fedora-releases
 - uses Bodhi releases API endpoint instead of obsolete PDC Product versions
 - Distribution.Fedora and the Dist type in particular are gone
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -9,8 +9,17 @@
 A Haskell library for Fedora release versions
 (formerly [fedora-dists](https://hackage.haskell.org/package/fedora-dists))
 
+There are 3 modules:
+
+- Distribution.Fedora.Branch : top level (Branch type)
+- Distribution.Fedora.Release : mid level (Release type)
+- Distribution.Fedora.BodhiReleases : low level (aeson Object)
+
+It uses the Releases endpoint data from the Fedora Bodhi API
+(via [bodhi-hs](https://github.com/juhp/bodhi-hs)).
+
 See <https://hackage.haskell.org/package/fedora-releases> for documentation.
 
-fedora-releases is distributed under GPL version 3 or later.
+fedora-releases is released and distributed under GPL version 3 or later.
 
 Repository: <https://github.com/juhp/fedora-releases>
diff --git a/fedora-releases.cabal b/fedora-releases.cabal
--- a/fedora-releases.cabal
+++ b/fedora-releases.cabal
@@ -1,9 +1,9 @@
 cabal-version:       1.18
 name:                fedora-releases
-version:             0.1.0
+version:             0.2.0
 synopsis:            Library for Fedora release versions
 description:
-            This library provides the Branch and Release datatypes
+            This library provides the Branch and Release data types
             and various associated metadata functions for
             Fedora releases (Fedora and EPEL) needed for
             packaging development and building.
@@ -30,14 +30,15 @@
 library
   exposed-modules:     Distribution.Fedora.Branch
                        Distribution.Fedora.Release
-  other-modules:       Distribution.Fedora.BodhiReleases
+                       Distribution.Fedora.BodhiReleases
   hs-source-dirs:      src
 
   build-depends:       base >= 4.9 && < 5
                      , aeson
                      , bodhi
-                     , extra
                      , cached-json-file
+                     , extra
+                     , safe
 
   ghc-options:         -Wall
   if impl(ghc >= 8.0)
diff --git a/src/Distribution/Fedora/BodhiReleases.hs b/src/Distribution/Fedora/BodhiReleases.hs
--- a/src/Distribution/Fedora/BodhiReleases.hs
+++ b/src/Distribution/Fedora/BodhiReleases.hs
@@ -1,8 +1,18 @@
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE CPP                 #-}
 
-module Distribution.Fedora.BodhiReleases
-  (getBodhiReleases)
+{-|
+Low level library with aeson Object's for releases fetched from Bodhi API.
+-}
+
+module Distribution.Fedora.BodhiReleases (
+  getBodhiReleases,
+  getBodhiProductReleases,
+  getBodhiFedoraReleases,
+  getBodhiEPELReleases,
+  getBodhiBranchReleases,
+  lookupKey
+  )
 where
 
 import Control.Exception.Extra (retry)
@@ -11,8 +21,29 @@
 import System.Cached.JSON
 
 -- FIXME softer/warning on failure?
+-- | Get Releases from Fedora Bodhi API (excluding archived)
 getBodhiReleases :: IO [Object]
 getBodhiReleases =
   retry 2 $
   getCachedJSONQuery "fedora" "bodhi-releases.json"
   (bodhiReleases (makeKey "exclude_archived" "True")) 450
+
+-- | Get Releases from Bodhi API filtered by id_prefix
+getBodhiProductReleases :: String -> IO [Object]
+getBodhiProductReleases name =
+  reverse . filter (\r -> lookupKey "id_prefix" r == Just name) <$> getBodhiReleases
+
+-- | Get FEDORA Releases from Bodhi API
+getBodhiFedoraReleases :: IO [Object]
+getBodhiFedoraReleases =
+  getBodhiProductReleases "FEDORA"
+
+-- | Get FEDORA-EPEL Releases from Bodhi API
+getBodhiEPELReleases :: IO [Object]
+getBodhiEPELReleases =
+  getBodhiProductReleases "FEDORA-EPEL"
+
+-- | Get releases for branch name
+getBodhiBranchReleases :: String -> IO [Object]
+getBodhiBranchReleases br =
+  filter (\r -> lookupKey "branch" r == Just br) <$> getBodhiReleases
diff --git a/src/Distribution/Fedora/Branch.hs b/src/Distribution/Fedora/Branch.hs
--- a/src/Distribution/Fedora/Branch.hs
+++ b/src/Distribution/Fedora/Branch.hs
@@ -1,10 +1,6 @@
--- |
--- Module      :  Distribution.Fedora.Branch
--- Copyright   :  (C) 2020-2022,2024  Jens Petersen
---
--- Maintainer  :  Jens Petersen <petersen@fedoraproject.org>
---
--- Explanation: Fedora Branch type and functions
+{-|
+The module provides a Branch type for Fedora and EPEL for active Release's.
+-}
 
 -- This program is free software: you can redistribute it and/or modify
 -- it under the terms of the GNU General Public License as published by
@@ -14,26 +10,28 @@
 module Distribution.Fedora.Branch
   ( Branch(..)
   , readBranch
+  , showBranch
   , eitherBranch
   , readActiveBranch
   , eitherActiveBranch
   , newerBranch
-  , getFedoraBranches
-  , getFedoraBranched
+  , getActiveBranches
+  , getActiveBranched
   , getLatestFedoraBranch
   , branchDestTag
   , branchDistTag
   , branchRelease
-  , branchTarget
   , partitionBranches
   )
 where
 
 import Data.Char (isDigit)
 import Data.Either (partitionEithers)
-import Data.List (delete)
+import Data.List.Extra (delete, elemIndex, replace, sortBy)
 import Data.Maybe (mapMaybe)
+import Data.Ord (comparing, Down(Down))
 import Data.Tuple (swap)
+import Safe (headDef)
 
 import Distribution.Fedora.Release
 
@@ -41,8 +39,21 @@
 --
 -- Branch can be rawhide, or a fedora or epel branch
 data Branch = EPEL !Int | EPELNext !Int | Fedora !Int | Rawhide
-  deriving (Eq, Ord)
+  deriving (Eq)
 
+-- | defined such that: EPELNext 9 < EPEL 10 < Fedora 41 < Rawhide
+instance Ord Branch where
+  compare Rawhide Rawhide = EQ
+  compare (Fedora m) (Fedora n) = compare m n
+  compare (EPELNext m) (EPELNext n) = compare m n
+  compare (EPEL m) (EPEL n) = compare m n
+  compare Rawhide _ = GT
+  compare _ Rawhide = LT
+  compare (Fedora _) _ = GT
+  compare _ (Fedora _) = LT
+  compare (EPEL m) (EPELNext n) = if m == n then LT else compare m n
+  compare (EPELNext m) (EPEL n) = if m == n then GT else compare m n
+
 -- | Read a Fedora Branch name, otherwise return branch string
 eitherBranch :: String -> Either String Branch
 eitherBranch "rawhide" = Right Rawhide
@@ -67,13 +78,6 @@
     Left _ -> Nothing
     Right br -> Just br
 
--- Unsafely read a Fedora Branch name: errors for unknown branches
-readBranch' :: String -> Branch
-readBranch' bs =
-  case eitherBranch bs of
-    Left e -> error' $! "unknown Fedora branch: " ++ e
-    Right br -> br
-
 -- | Read a Branch name (one of the list of active branches)
 --
 -- Provides error strings for inactive or unknown branches.
@@ -94,84 +98,61 @@
     Left _ -> Nothing
     Right br -> Just br
 
-instance Show Branch where
-  show Rawhide = "rawhide"
-  show (Fedora n) = "f" ++ show n
-  show (EPEL n) = (if n <= 6 then "el" else "epel") ++ show n
-  show (EPELNext n) = "epel" ++ show n ++ "-next"
+-- | render Branch to String
+showBranch :: Branch -> String
+showBranch Rawhide = "rawhide"
+showBranch (Fedora n) = "f" ++ show n
+showBranch (EPEL n) = (if n <= 6 then "el" else "epel") ++ show n
+showBranch (EPELNext n) = "epel" ++ show n ++ "-next"
 
 -- | Get Release associated with release Branch
+--
+-- Fails if given an inactive branch
 branchRelease :: Branch -> IO Release
-branchRelease br = do
-  rels <- getReleases
-  case releaseFilter releaseBranch (== show br) rels of
-    [] -> error' $ "release not found for branch " ++ show br
-    [rel] -> return rel
-    rs -> error' $ "impossible happened: multiple releases for " ++ show br ++ ":\n" ++ unwords (map releaseBranch rs)
+branchRelease = getBranchRelease . showBranch
 
--- | Map Branch to Koji destination tag
-branchDestTag :: Branch -> String
-branchDestTag Rawhide = "rawhide"
-branchDestTag (Fedora n) = show (Fedora n) ++ "-updates-candidate"
-branchDestTag (EPEL n) = show (EPEL n) ++ "-testing-candidate"
-branchDestTag (EPELNext n) = show (EPELNext n) ++ "-testing-candidate"
+-- | Map Branch to Koji destination tag (candidate tag)
+branchDestTag :: Branch -> IO String
+branchDestTag br = releaseCandidateTag <$> branchRelease br
 
--- | Get %dist tag for branch
+-- | Converts koji dist tag  to rpm %dist tag for branch
+--
+-- f41 -> .fc41
+--
+-- epel10.0 -> .el10_0
 branchDistTag :: Branch -> IO String
-branchDistTag Rawhide = do
-  n <- releaseVersion <$> branchRelease Rawhide
-  branchDistTag (Fedora (read n))
-branchDistTag (Fedora n) = return $ ".fc" ++ show n
-branchDistTag (EPEL n) = return $ ".el" ++ show n
-branchDistTag (EPELNext n) = return $ ".el" ++ show n ++ ".next"
-
--- | Default build target associated with a branch
-branchTarget :: Branch -> String
-branchTarget (Fedora n) = show (Fedora n)
-branchTarget (EPEL n) = show (EPEL n)
-branchTarget (EPELNext n) = show (EPELNext n)
-branchTarget Rawhide = "rawhide"
+branchDistTag br = do
+  dist <- releaseDistTag <$> branchRelease br
+  -- f41 -> .fc41
+  -- epel10.0 -> .el10_0
+  return $ '.' : (distroFix br . replace "." "_") dist
+  where
+    distroFix (EPEL _) = replace "epel" "el"
+    distroFix _ = replace "f" "fc"
 
 -- | Returns newer branch than given one from supplied active branches.
 --
 -- Branches should be in descending order, eg from getFedoraBranches
-newerBranch :: Branch -> [Branch] -> Branch
-newerBranch Rawhide _ = Rawhide
-newerBranch (Fedora n) branches =
-  if Fedora n `elem` branches
-  then if Fedora (n+1) `elem` branches
-       then Fedora (n+1)
-       else Rawhide
-  else error' $ "Unsupported branch: " ++ show (Fedora n)
-newerBranch (EPEL n) branches =
-  if EPEL n `elem` branches
-  then if EPEL (n+1) `elem` branches
-       then EPEL (n+1)
-       else EPEL n
-  else error' $ "Unsupported branch: " ++ show (EPEL n)
-newerBranch (EPELNext n) branches =
-  if EPELNext n `elem` branches
-  then if EPELNext (n+1) `elem` branches
-       then EPELNext (n+1)
-       else EPELNext n
-  else error' $ "Unsupported branch: " ++ show (EPELNext n)
+newerBranch :: Branch -> [Branch] -> Maybe Branch
+newerBranch Rawhide _ = Nothing
+newerBranch br branches =
+  case elemIndex br branches of
+    Just i | i > 0 -> Just $ branches !! (i - 1)
+    _ -> Nothing
 
+
 --olderBranch :: Branch -> Branch
 --olderBranch Rawhide = latestBranch
 --olderBranch (Fedora n) = Fedora (n-1)
 
--- | Returns list of active Fedora branches, including rawhide and EPEL
-getFedoraBranches :: IO [Branch]
-getFedoraBranches =
-  mapMaybe (readBranch . releaseBranch) <$> getReleases
-
--- | Maps Release to Branch
-releaseToBranch :: Release -> Branch
-releaseToBranch = readBranch' . releaseBranch
+-- | Returns descending list of active Fedora branches, including rawhide and EPEL
+getActiveBranches :: IO [Branch]
+getActiveBranches =
+  reverseSort . mapMaybe (readBranch . releaseBranch) <$> getActiveReleases
 
 -- | Returns list of active Fedora branches, excluding rawhide
-getFedoraBranched :: IO [Branch]
-getFedoraBranched = delete Rawhide <$> getFedoraBranches
+getActiveBranched :: IO [Branch]
+getActiveBranched = delete Rawhide <$> getActiveBranches
 
 -- from simple-cmd
 error' :: String -> a
@@ -185,8 +166,7 @@
 -- | get newest Fedora branched Release
 getLatestFedoraBranch :: IO Branch
 getLatestFedoraBranch =
-  releaseToBranch . maximum . releaseFilter releaseBranch (/= "rawhide")
-  <$> getFedoraReleases
+  headDef (error' "no active branched!") <$> getActiveBranched
 
-releaseFilter :: (Release -> a) -> (a -> Bool) -> [Release] -> [Release]
-releaseFilter f p = filter (p . f)
+reverseSort :: Ord a => [a] -> [a]
+reverseSort = sortBy (comparing Down)
diff --git a/src/Distribution/Fedora/Release.hs b/src/Distribution/Fedora/Release.hs
--- a/src/Distribution/Fedora/Release.hs
+++ b/src/Distribution/Fedora/Release.hs
@@ -1,24 +1,22 @@
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE CPP                 #-}
 
--- |
--- Module      :  Distribution.Fedora.Release
--- Copyright   :  (C) 2020-2022,2024  Jens Petersen
---
--- Maintainer  :  Jens Petersen <petersen@fedoraproject.org>
---
--- Explanation: Fedora Release type and functions
-
 -- This program is free software: you can redistribute it and/or modify
 -- it under the terms of the GNU General Public License as published by
 -- the Free Software Foundation, either version 3 of the License, or
 -- (at your option) any later version.
 
+{-|
+The module provides a higher level API over BodhiReleases
+with a Release record type.
+-}
+
 module Distribution.Fedora.Release
   ( Release(..),
-    getReleases,
+    getActiveReleases,
     getFedoraReleases,
-    getEPELReleases
+    getEPELReleases,
+    getBranchRelease
   )
 where
 
@@ -26,20 +24,23 @@
 import Data.Aeson(Object)
 import Data.Maybe (mapMaybe)
 import Distribution.Fedora.BodhiReleases
-import Fedora.Bodhi (lookupKey)
 
 -- | Fedora Release data
 data Release = Release {
     releaseName :: String,
     releaseVersion :: String,
     releaseIdPrefix :: String,
-    releaseBranch :: String
+    releaseBranch :: String,
+    releaseComposed :: Bool,
+    releaseCandidateTag :: String,
+    releaseDistTag :: String,
+    releaseSettingStatus :: Maybe String,
+    releaseState :: String,
+    releaseAutomaticUpdates :: Bool,
+    releaseTestingRepo :: Maybe String,
+    releaseTestingTag :: String
   } deriving (Show,Eq)
 
-instance Ord Release where
-  compare r1 r2 =
-    compare (releaseName r1) (releaseName r2)
-
 readRelease :: Object -> Maybe Release
 readRelease obj = do
   name <- lookupKey "name" obj
@@ -47,24 +48,51 @@
   idPref <- lookupKey "id_prefix" obj
   guard (idPref `notElem` ["FEDORA-CONTAINER","FEDORA-FLATPAK"])
   br <- lookupKey "branch" obj
-  return $ Release name ver idPref br
+  composed <- lookupKey "composed_by_bodhi" obj
+  candidate <- lookupKey "candidate_tag" obj
+  disttag <- lookupKey "dist_tag" obj
+  let setting = lookupKey "setting_status" obj
+  state <- lookupKey "state" obj
+  automatic <- lookupKey "create_automatic_updates" obj
+  let testrepo = lookupKey "testing_repository" obj
+  testtag <- lookupKey "testing_tag" obj
+  return $ Release name ver idPref br composed candidate disttag setting state automatic testrepo testtag
 
+-- | ordered by releaseName
+instance Ord Release where
+  compare r1 r2 =
+    compare (releaseName r1) (releaseName r2)
+
 -- FIXME remove containers and flatpaks
 -- | Get list of all current Fedora Project releases (from Bodhi)
-getReleases :: IO [Release]
-getReleases =
-  reverse . mapMaybe readRelease <$> getBodhiReleases
+getActiveReleases :: IO [Release]
+getActiveReleases =
+  mapMaybe readRelease <$> getBodhiReleases
 
-getProductReleases :: String -> IO [Release]
-getProductReleases name =
-  filter (\p -> releaseIdPrefix p == name) <$> getReleases
+-- getProductReleases :: String -> IO [Release]
+-- getProductReleases name =
+--   mapMaybe readRelease <$> getBodhiProductReleases name
 
 -- | Get list of current Fedora Linux releases
 getFedoraReleases :: IO [Release]
 getFedoraReleases =
-  getProductReleases "FEDORA"
+  mapMaybe readRelease <$> getBodhiFedoraReleases
 
 -- | Get list of current Fedora EPEL releases
 getEPELReleases :: IO [Release]
 getEPELReleases =
-  getProductReleases "FEDORA-EPEL"
+  mapMaybe readRelease <$> getBodhiEPELReleases
+
+-- releaseFilter :: (Release -> a) -> (a -> Bool) -> [Release] -> [Release]
+-- releaseFilter f p = filter (p . f)
+
+-- | Get the Release for an active Branch
+--
+-- Errors for an inactive Branch
+getBranchRelease :: String -> IO Release
+getBranchRelease br = do
+  rels <- mapMaybe readRelease <$> getBodhiBranchReleases br
+  case rels of
+    [] -> error $ "release not found for branch " ++ br
+    [rel] -> return rel
+    _ -> error $ "multiple releases for " ++ br ++ ":\n" ++ unwords (map releaseName rels)
