Cuttlefish is a Scala 3 library that provides a functional, type-safe client for the Octopus Energy API. It offers comprehensive access to meter consumption data, tariffs, and account information.
Built on http4s and Cats Effect, Cuttlefish provides a pure functional interface to the Octopus Energy REST API with automatic retry handling, authentication management, and typed request/response models.
- Type-Safe API - Strongly typed request and response models for all endpoints
- Functional Design - Built on Cats Effect with pure functional semantics
- Automatic Retries - Configurable exponential backoff retry policy
- Authentication Management - Handles API key authentication automatically
- Comprehensive Coverage - Supports consumption data, tariffs, products, and account endpoints
- Streaming Ready - Returns
F[_]effects compatible with fs2 streams
Add the following to your build.sbt:
libraryDependencies += "com.colofabrix.scala" %% "cuttlefish" % "1.0.0"For Mill:
ivy"com.colofabrix.scala::cuttlefish:1.0.0"| Category | Endpoints |
|---|---|
| Consumption | Gas and electricity meter consumption data |
| Account | Account information and details |
| Products | Product listings and details |
| Tariffs | Unit rates and standing charges for gas/electricity |
| Grid Supply Points | GSP lookup by postcode |
| Meter Points | Electricity meter point information |
Create a client and fetch meter consumption data:
import cats.effect.*
import com.colofabrix.scala.cuttlefish.*
import com.colofabrix.scala.cuttlefish.api.*
import com.colofabrix.scala.cuttlefish.model.*
object MyApp extends IOApp.Simple {
def run: IO[Unit] =
for
client <- CuttlefishClient[IO]()
_ <- client.login("your-api-key")
consumption <- client.meterConsumption(
MeterConsumptionRequest(
product = OctopusProduct.Electricity,
meterPointNumber = MeterPointNumber("1234567890"),
serial = SerialNumber("ABC123"),
from = Some(OffsetDateTime.now().minusDays(7)),
to = Some(OffsetDateTime.now()),
pageSize = Some(100),
),
)
_ <- IO.println(s"Consumption: $consumption")
yield ()
}val accountInfo =
for
client <- CuttlefishClient[IO]()
_ <- client.login("your-api-key")
account <- client.getAccount(AccountRequest(AccountNumber("A-1234ABCD")))
yield accountSome endpoints don't require authentication:
val products =
for
client <- CuttlefishClient[IO]()
products <- client.getProducts(ProductsRequest(isGreen = Some(true)))
yield productsval rates =
for
client <- CuttlefishClient[IO]()
rates <- client.getElectricityStandardUnitRates(
ElectricityUnitRatesRequest(
productCode = ProductCode("AGILE-FLEX-22-11-25"),
tariffCode = TariffCode("E-1R-AGILE-FLEX-22-11-25-C"),
periodFrom = Some(OffsetDateTime.now().minusDays(1)),
periodTo = Some(OffsetDateTime.now()),
),
)
yield ratesThe main entry point for interacting with the Octopus Energy API.
| Method | Description | Auth Required |
|---|---|---|
login(apiKey) |
Authenticate with API key | - |
logout() |
Clear authentication | - |
meterConsumption(request) |
Get meter consumption data | ✓ |
getAccount(request) |
Get account information | ✓ |
getProducts(request) |
List available products | ✗ |
getProductDetails(request) |
Get product details | ✗ |
getGridSupplyPoints(request) |
Lookup GSP by postcode | ✗ |
getElectricityMeterPoint(request) |
Get meter point info | ✗ |
getElectricityStandardUnitRates(request) |
Get standard unit rates | ✗ |
getElectricityDayUnitRates(request) |
Get day unit rates (Economy 7) | ✗ |
getElectricityNightUnitRates(request) |
Get night unit rates (Economy 7) | ✗ |
getElectricityStandingCharges(request) |
Get standing charges | ✗ |
getGasStandardUnitRates(request) |
Get gas unit rates | ✗ |
getGasStandingCharges(request) |
Get gas standing charges | ✗ |
Cuttlefish uses opaque types to prevent parameter mix-ups:
| Type | Description |
|---|---|
MeterPointNumber |
MPAN/MPRN identifier |
SerialNumber |
Meter serial number |
AccountNumber |
Octopus account number |
ProductCode |
Product identifier |
TariffCode |
Tariff identifier |
Postcode |
UK postcode |
Mpan |
Electricity meter point admin number |
Default client configuration via application.conf:
cuttlefish {
api-base = "https://api.octopus.energy/v1"
http-timeout = 30 seconds
max-retries = 3
max-retry-time = 10 seconds
}Or programmatically:
val config =
CuttlefishConfig(
apiBase = Uri.unsafeFromString("https://api.octopus.energy/v1"),
httpTimeout = 30.seconds,
maxRetries = 3,
maxRetryTime = 10.seconds,
)
val client = CuttlefishClient[IO](Some(config))Cuttlefish uses typed errors for API failures:
import com.colofabrix.scala.cuttlefish.model.*
client
.meterConsumption(request)
.handleErrorWith {
case CuttlefishError(message, Some(requestError)) =>
IO.println(s"API error: ${requestError.detail}")
case CuttlefishError(message, None) =>
IO.println(s"Client error: $message")
}To use the authenticated endpoints, you need an Octopus Energy API key:
- Log in to your Octopus Energy account
- Navigate to Developer Settings
- Generate an API key
Note: The API key provides read-only access to your account and consumption data.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Cuttlefish is released under the MIT license. See LICENSE for details.
- Octopus Energy API Documentation
- Guy Lipman's Octopus API Guide
- http4s - Typeful, functional HTTP for Scala
- Cats Effect - The pure asynchronous runtime for Scala