OData API
v1

Fish Data API

OData v4 feeds for buyer agreements and auction lot prices captured from fish auctions.

The Fish Data API exposes fish-auction data as OData v4 feeds, making it easy to query, filter, and integrate data into tools like Power BI, Excel, or any OData-compatible client. Two collections are available:

BuyerAgreements — buyer and hammer-price agreements streamed live from the auction as lots are sold. AuctionLots — the full daily lot catalogue scraped from the auction sheet, with species, gear, seller, weight and the realised price per kilogram.

Protocol

OData v4 over HTTPS

Format

JSON (application/json)

Auth

API key via header or query param

Max page size

1 000 rows per request

Authentication

Every request must include an API key. You can pass it either as an HTTP request header (recommended) or as a query parameter (useful for tools that cannot set custom headers, such as the Power BI Web connector).

Option 1 — HTTP header (recommended)

HTTP
X-Api-Key: your-api-key-here

Option 2 — Query parameter

URL
https://fish.metadata.is/odata/BuyerAgreements?api_key=your-api-key-here
Avoid embedding API keys in URLs that may be logged or shared. Prefer the header approach whenever possible.

Requests with a missing or invalid key receive a 401 Unauthorized response.

Base URL

URL
https://fish.metadata.is/odata

The OData service root is /odata. All entity sets are relative to this path.

Endpoints

Two read-only collections are available. Both support the OData query options listed below.

List buyer agreements

GET /odata/BuyerAgreements

Returns a collection of buyer agreements. Supports all OData query options listed below.

Get a single agreement

GET /odata/BuyerAgreements(id)

Returns a single buyer agreement by its integer Id.

List auction lots

GET /odata/AuctionLots

Returns a collection of auction lots — one row per lot from the daily auction sheet.

Get a single lot

GET /odata/AuctionLots(id)

Returns a single auction lot by its integer Id.

Fields

Buyer Agreements

Field Type Description
Id Integer Unique record identifier (auto-assigned).
LotNumber String The lot identifier from the auction (e.g. A-001).
Buyer String Name of the buyer as reported by the auction system.
Price Decimal Hammer price in ISK.
AuctionDate Date The auction trading day (YYYY-MM-DD).
ReceivedAt DateTimeOffset UTC timestamp when the agreement was captured.

Auction Lots

Field Type Description
IdIntegerUnique record identifier (auto-assigned).
AuctionDateDateThe auction trading day (YYYY-MM-DD).
SpeciesStringFish species (e.g. Þorskur — cod).
SpeciesConditionStringCondition the species group was sold under (e.g. Óslægt — ungutted).
GroupTotalKgIntegerTotal kilograms offered in the species/condition group this lot belongs to.
LotStringLot identifier within the auction (e.g. 1-1).
GearStringFishing gear used (e.g. Lína — longline).
SellerStringSeller / vessel as reported by the auction.
ConditionStringLot condition grading.
SizeStringSize grading of the fish.
AgeStringAge / freshness of the catch (e.g. 1-dags — one day).
LocationStringAuction market / landing location.
WeightKgIntegerWeight of this lot, in kilograms.
PriceKrPerKgInteger (nullable)Realised price in ISK per kg. null until the auction has run.
ScrapedAtDateTimeOffsetUTC timestamp when the lot was scraped.
PriceKrPerKg is only populated during and after the auction (around 17:00 Iceland time on weekdays). Lots fetched earlier in the day will have a null price.

Query Options

The following standard OData system query options are supported on both collections:

OptionDescriptionExample
$filter Filter rows by a boolean expression. $filter=Buyer eq 'Jón Jónsson'
$select Return only the specified fields. $select=LotNumber,Price
$orderby Sort results. Append desc for descending. $orderby=Price desc
$top Limit number of rows returned (max 1 000). $top=100
$skip Skip the first N rows — use with $top to page through results. $skip=1000
$count Include total row count in the response. $count=true

Filter operators

OperatorMeaningExample
eqEqualsBuyer eq 'Jón Jónsson'
neNot equalsBuyer ne 'Unknown'
gtGreater thanPrice gt 500000
geGreater than or equalPrice ge 1000000
ltLess thanPrice lt 200000
leLess than or equalPrice le 999999
andLogical ANDPrice gt 500000 and Buyer eq 'Jón'
orLogical ORLotNumber eq 'A-001' or LotNumber eq 'B-002'

Filtering

Filter by buyer name

HTTP
GET /odata/BuyerAgreements?$filter=Buyer eq 'Jón Jónsson'
X-Api-Key: your-api-key-here

Filter by lot number

HTTP
GET /odata/BuyerAgreements?$filter=LotNumber eq 'A-042'
X-Api-Key: your-api-key-here

Filter by date range

HTTP
GET /odata/BuyerAgreements?$filter=ReceivedAt ge 2025-01-01T00:00:00Z and ReceivedAt lt 2025-02-01T00:00:00Z
X-Api-Key: your-api-key-here

Filter by minimum price

HTTP
GET /odata/BuyerAgreements?$filter=Price ge 1000000
X-Api-Key: your-api-key-here

Example response

200 OK · application/json
JSON
{
  "@odata.context": "https://fish.metadata.is/odata/$metadata#BuyerAgreements",
  "value": [
    {
      "Id":         1,
      "LotNumber": "A-042",
      "Buyer":     "Jón Jónsson",
      "Price":     1250000.00,
      "ReceivedAt":"2025-01-15T13:04:27Z"
    }
  ]
}

Selecting Fields

Use $select to return only the fields you need, reducing payload size.

HTTP
GET /odata/BuyerAgreements?$select=LotNumber,Buyer,Price
X-Api-Key: your-api-key-here
200 OK · application/json
JSON
{
  "@odata.context": ".../$metadata#BuyerAgreements(LotNumber,Buyer,Price)",
  "value": [
    { "LotNumber": "A-042", "Buyer": "Jón Jónsson", "Price": 1250000.00 }
  ]
}

Sorting & Paging

Top 10 most expensive lots

HTTP
GET /odata/BuyerAgreements?$orderby=Price desc&$top=10
X-Api-Key: your-api-key-here

Paging through large result sets

The API returns at most 1 000 rows per request. When more results exist the response includes an @odata.nextLink URL — follow it to fetch the next page. Use $count=true on the first request to know the total up front.

Always include $orderby when paging. Without it the database may return rows in a different order on each page, causing duplicates or gaps.

Page 1 — fetch first 1 000 rows and total count

HTTP
GET /odata/BuyerAgreements?$orderby=Id&$count=true
X-Api-Key: your-api-key-here
200 OK · application/json
JSON
{
  "@odata.context":  "https://fish.metadata.is/odata/$metadata#BuyerAgreements",
  "@odata.count":   3420,
  "@odata.nextLink": "https://fish.metadata.is/odata/BuyerAgreements?$orderby=Id&$skip=1000",
  "value": [ /* 1 000 records */ ]
}

Page 2 — follow nextLink or use $skip manually

HTTP
GET /odata/BuyerAgreements?$orderby=Id&$skip=1000
X-Api-Key: your-api-key-here

Continue incrementing $skip by 1 000 until the response contains no @odata.nextLink — that means you have reached the last page.

Combined Queries

Query options can be combined freely in a single request.

Agreements from a specific auction day, sorted by price

HTTP
GET /odata/BuyerAgreements
  ?$filter=ReceivedAt ge 2025-05-15T00:00:00Z and ReceivedAt lt 2025-05-16T00:00:00Z
  &$orderby=Price desc
  &$select=LotNumber,Buyer,Price
  &$count=true
X-Api-Key: your-api-key-here

High-value lots for a specific buyer

HTTP
GET /odata/BuyerAgreements
  ?$filter=Buyer eq 'Jón Jónsson' and Price ge 500000
  &$orderby=ReceivedAt desc
  &$top=100
X-Api-Key: your-api-key-here

Auction Lots

The AuctionLots collection works exactly like BuyerAgreements — the same query options apply. Note that AuctionDate is a pure date, so filter it without quotes or a time component (e.g. AuctionDate eq 2026-06-05).

All cod lots on a given auction day

HTTP
GET /odata/AuctionLots?$filter=Species eq 'Þorskur' and AuctionDate eq 2026-06-05
X-Api-Key: your-api-key-here

Highest price-per-kg lots (priced lots only)

HTTP
GET /odata/AuctionLots?$filter=PriceKrPerKg ne null&$orderby=PriceKrPerKg desc&$top=10
X-Api-Key: your-api-key-here

Select just the columns you need

HTTP
GET /odata/AuctionLots?$select=AuctionDate,Species,Lot,WeightKg,PriceKrPerKg&$orderby=AuctionDate desc
X-Api-Key: your-api-key-here

Example response

200 OK · application/json
JSON
{
  "@odata.context": "https://fish.metadata.is/odata/$metadata#AuctionLots",
  "value": [
    {
      "Id":               1,
      "AuctionDate":      "2026-06-05",
      "Species":          "Þorskur",
      "SpeciesCondition": "Óslægt",
      "GroupTotalKg":     6451,
      "Lot":              "1-1",
      "Gear":             "Lína",
      "Seller":           "2755 - Jón Ásbjörnsson RE-777",
      "Condition":        "Ó",
      "Size":             "Bl.Umál",
      "Age":              "1-dags",
      "Location":         "FMÍS / Þorl",
      "WeightKg":         12,
      "PriceKrPerKg":     null,
      "ScrapedAt":        "2026-06-07T14:36:33Z"
    }
  ]
}

Power BI Integration

Use the built-in OData feed connector for the best experience — Power BI understands OData natively and can push query folding back to the server.

The OData feed connector supports query folding, meaning filters and column selections you apply in Power Query are sent directly to the API rather than fetched and filtered locally.
  1. Open the OData feed connector

    In Power BI Desktop: Get Data → OData feed. Paste a collection URL:

    URL
    https://fish.metadata.is/odata/BuyerAgreements
    https://fish.metadata.is/odata/AuctionLots

    Or point Power BI at the service root https://fish.metadata.is/odata and pick either collection from the navigator.

  2. Add the API key header

    Click Advanced, then under HTTP request header parameters add:

    Header nameValue
    X-Api-Keyyour-api-key-here
  3. Connect & load

    Click OK → Connect. Power BI will load the schema and show a preview. Click Load or Transform Data to shape the data in Power Query.

  4. Schedule refresh (optional)

    After publishing to the Power BI Service, configure a gateway data source or use the cloud gateway. Re-add the X-Api-Key header in the data source credentials under Advanced → HTTP request header parameters.

If your Power BI environment cannot send custom headers, append ?api_key=your-key to the URL instead. See the Authentication section for details.