Skip to Content
DocumentationSDKs & OpenAPI

SDKs and the OpenAPI Contract

You can call the Public API over plain HTTP; the clients on this page take care of the repetitive work — token management, retries, and pagination.

Machine-readable contract

The OpenAPI 3.0 definition is always generated from the running code. There is no hand-maintained copy.

To generate a client for a language we do not ship, feed the schema to openapi-generator:

npx @openapitools/openapi-generator-cli generate \ -i https://api.frigolive.nl/api/public/schema.json \ -g go \ -o ./frigolive-go

Ready-made collections

One source of truth

The schema is produced from the code that serves the API, so this reference, the schema, and the real behaviour cannot drift apart.

Official clients

LanguagePackageInstall
Python 3.9+frigolivepip install frigolive
Node.js 18+@frigolive/api-clientnpm install @frigolive/api-client
.NET 8Frigolive.Apidotnet add package Frigolive.Api

All three behave identically:

Token handling is automatic

An access token is obtained, cached in memory, and refreshed 60 seconds before it expires. Concurrent requests share a single token call.

Retries are safe

429 and 5xx responses are retried with exponential backoff and jitter, honouring Retry-After. A POST without an idempotency key is never retried.

Idempotency is built in

An Idempotency-Key is added to POST requests automatically, so a retry after a network failure will not create a second record.

Errors are typed

The HTTP status maps to an exception type and request_id is preserved. Include that value in any support request.

Python

import os from frigolive import FrigoliveClient, NotFoundError client = FrigoliveClient( client_id=os.environ["FRIGOLIVE_CLIENT_ID"], client_secret=os.environ["FRIGOLIVE_CLIENT_SECRET"], scope="devices:read telemetry:read", ) client.account_id = client.accounts()[0]["id"] for device in client.iterate("/devices/"): print(device["display_serial"], device["battery_level"])

Node.js

import { FrigoliveClient } from "@frigolive/api-client"; const client = new FrigoliveClient({ clientId: process.env.FRIGOLIVE_CLIENT_ID!, clientSecret: process.env.FRIGOLIVE_CLIENT_SECRET!, scope: "devices:read telemetry:read", }); for await (const device of client.iterate("/devices/")) { console.log(device); }

.NET

await using var client = new FrigoliveClient(new FrigoliveClientOptions { ClientId = Environment.GetEnvironmentVariable("FRIGOLIVE_CLIENT_ID")!, ClientSecret = Environment.GetEnvironmentVariable("FRIGOLIVE_CLIENT_SECRET")!, Scope = "devices:read telemetry:read", }); await foreach (var device in client.IterateAsync("/devices/")) { Console.WriteLine(device.GetProperty("label").GetString()); }
The secret stays on your server

None of these clients is designed to run in a browser or a distributed mobile app. Your interface talks to your own backend; that backend calls Frigolive server-to-server.

Pagination

Each client ships a helper that walks list endpoints for you. The next page is read from links.next, so you never increment the page number yourself.

If you are not using a client, apply the same rule yourself: Errors & Resilience.