Skip to main content

dlt-source-aquabyte

An installable dlt source package that loads aquaculture data from the Aquabyte API v3 into any dlt destination: sites, biomass, lice counts, welfare scores, behaviour and environmental readings.

Records land as the API returns them — nothing renamed, nothing dropped, no invented child tables. What is added is named up front rather than discovered later: _dlt_valid_from and _dlt_valid_to on the versioned sites table. Column names are the API's own field names, in dlt's usual snake_case.

Everything else is mechanics: auth, pagination, envelope unwrapping, incremental cursors, and overridable key and write-disposition defaults. Reshaping belongs in your transform layer, where you can change it without waiting for a release. Its only dependency is dlt itself — destination, orchestrator, secrets manager and log routing stay your choices.

Install

uv add dlt-source-aquabyte "dlt[duckdb]"   # any dlt destination works; DuckDB is the one below

Quick start

Put the API base URL and your key in a .dlt/ directory beside the script you are about to run.

.dlt/config.toml:

[sources.aquabyte]
base_url = "https://api.aquabyte.ai/v3/"
initial_date = "2020-01-01"             # first-run start for the date-based cursors
initial_time = "2020-01-01T00:00:00Z"   # first-run start for the time-based cursors

.dlt/secrets.toml:

[sources.aquabyte]
api_key = "your-api-key-here"

Then load every resource:

import dlt
from dlt_source_aquabyte import aquabyte_source

pipeline = dlt.pipeline(
    pipeline_name="aquabyte",
    destination="duckdb",     # any dlt destination
    dataset_name="aquabyte_data",
)
print(pipeline.run(aquabyte_source()))

The two initial_* values are the first-run start for the resources that keep an incremental cursor; a run of only sites or environmental_latest needs neither, and a cursor resource missing one fails with an error naming it. How far back your data goes differs per endpoint and per account, and setting a start earlier than that costs empty requests, not errors.

What it loads

Resource Endpoint Load strategy Key
sites GET /sites, GET /sites/{siteId} merge, scd2 id (merge key)
environmental GET /environmental merge penId, fromTime, toTime
environmental_latest GET /environmental/latest replace
biomass GET /biomass merge penId, date
harvest_report GET /biomass/harvestReport merge penId, slaughterStartDate, mainReport, asOfDate
lice_count GET /liceCount merge penId, date
behaviour_swim_speed GET /behaviour/swimSpeed merge penId, fromTime, toTime
behaviour_breathing_index GET /behaviour/breathingIndex merge penId, fromTime
welfare_scores GET /welfareScores merge penId, date

sites reads every site, and each site record carries its pens the way the API nests them — every pen, active or not. There is no separate pens table, because the API serves no pens endpoint; where pen history lives, and what the source does and does not promise about a pen or site that stops being reported. sites is versioned rather than replaced: a row is retired, never deleted, because a pen leaves /sites as soon as it is emptied (what that means for your queries). Nested objects land as one JSON column each, and welfare_scores is not unpivoted (why, and how to override it).

Configuring a resource

Each resource takes its endpoint's params in snake_case, except the window ones, which the incremental cursor drives:

source = aquabyte_source()
source.sites.bind(site_id="site-001")     # switches to GET /sites/{siteId}
source.biomass.bind(pen_id="pen-abc", bucket_size=250)
pipeline.run(source)
  • pen_id defaults to "all" — the API's own value for "every pen", in one request. Pass one id to read a single pen.
  • site_id is the one path param, not a query param: binding it moves sites to the per-site endpoint, and both write the same table.
  • The window is the incremental cursor's, not a parameter of its own: a daily run resumes where it left off, and a backfill binds the window on the resource's incremental_* argument — see the reference.
  • params is on every resource and merged into the query string last: the escape hatch for a query param the API grows later, no release needed. It wins over every named param, penId included.

Params can also be set in config, per resource:

[sources.aquabyte.environmental]
period = "15min"

Two params decide the grain of the data itself

period and bucket_size change what the API computes for you, not which rows you ask for. Both are worth deciding before the first load: a coarse setting is not wrong, but the detail under it never lands, and getting it later means re-loading that history the backfill way.

Param Resource Values API default What it decides
period environmental h, D, 15min D Row grain: h is 24× the rows of D, 15min is 96×
period behaviour_swim_speed h, D D As above. 15min here is a 422 — only environmental takes it
bucket_size biomass integer grams 1000 Bucket width of the nested weightDist histogram — no extra rows

⚠️ Changing period later leaves both grains in the table. The key is penId + fromTime + toTime, so hourly rows do not merge over the daily ones they cover — both sit there. Pick a period per resource and keep it, or re-load the history behind the change.

bucket_size adds no rows. weightDist covers only the weights observed, so a pen of smolt returns a couple of buckets and a harvest-size pen at 250 g a few dozen — one JSON column either way (what the arrays hold).

The package emits no log records of its own. dlt logs the window each run asked for and every request it made, on its own dlt logger, and routing them is dlt's [runtime] settings rather than anything here: what to set, and dlt's own logging documentation.

Examples

One concept each, readable on GitHub. From a checkout, run one with python examples/<name>.py.

Example The one concept
quickstart.py Load every resource into DuckDB
daily_load.py Re-running resumes from the stored cursor
backfill.py Re-load a window, stored cursor untouched

Compatibility

dlt-source-aquabyte Aquabyte API
0.1.x v3.1

The two numbers are unrelated — the package version is ordinary SemVer and never mirrors the API's. Built against that version's specs/openapi.json and run against the live API (last on 2026-08-17). A later backwards-compatible version is expected to work and is not verified here; run the suite first.

Read next

  • Reference — the versioned site registry, nesting, backfilling, column types, and what the source deliberately does not expose.
  • API quirks worth knowing — where the live API departs from its own OpenAPI document, including which identifiers to join on. Some of them change what a correct query looks like, so read it before your first one.
  • Changelog and contributing.

License

Apache-2.0. specs/openapi.json is Aquabyte's own OpenAPI document, included as the spec this package is built against; it is their material, and the licence does not extend to it.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dlt_source_aquabyte-0.1.0.tar.gz (32.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dlt_source_aquabyte-0.1.0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

File details

Details for the file dlt_source_aquabyte-0.1.0.tar.gz.

File metadata

  • Download URL: dlt_source_aquabyte-0.1.0.tar.gz
  • Upload date:
  • Size: 32.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dlt_source_aquabyte-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f4447b8e8e9aef09339f0c4675c8b1b768e574e6eafe1bb8c57854b0e7161bcd
MD5 2c3be3944cace243f51ca8609335e29c
BLAKE2b-256 5b48f8f7e9e977d9b66fb9ce257e34f4f8cc79e8b64d568ee923d7756615fbd4

See more details on using hashes here.

Provenance

The following attestation bundles were made for dlt_source_aquabyte-0.1.0.tar.gz:

Publisher: release.yml on Havbruksdataforeningen/dlt-sources

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dlt_source_aquabyte-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for dlt_source_aquabyte-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8ab0f567f800f45796c2ad17af2a6295012c156eb1ed2688db348d7c0dce48de
MD5 280244e35206abc5918ccb635400b0ea
BLAKE2b-256 5fc7997e082fde651376b8435d9d7b7926e17847e362388e08d9e61db7c56582

See more details on using hashes here.

Provenance

The following attestation bundles were made for dlt_source_aquabyte-0.1.0-py3-none-any.whl:

Publisher: release.yml on Havbruksdataforeningen/dlt-sources

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page