Developers

    Introducing the AQUA-SMART Public API, Black Sea Data for Your App

    AQUA-SMART Product Team, e-AQUAF Project (BSB01009)

    June 2026 10 min read 0 views
    AQUA-SMART Black Sea observatory dashboard

    Why a Public API?

    AQUA-SMART has spent two years building a live observatory of the Black Sea: in-situ buoys in Romania, Bulgaria and Georgia streaming dissolved oxygen, pH, salinity and temperature; satellite layers from Copernicus Marine and NASA PACE for sea surface temperature, chlorophyll-a, salinity and currents; FAO FishStat production baselines for seven Black Sea countries; AIS vessel tracks; eddy and bloom event histories.

    We get the same question every week from researchers, app developers and aquaculture operators: "Can I pull this into my own dashboard / model / mobile app?"

    The answer is now yes. The AQUA-SMART Public REST API (v1) exposes the platform's live and historical data as plain JSON, behind a simple API key. This guide is everything you need to start.

    Get access: at the bottom of this article (and on every page of the docs) is a Request API access button. Fill in the short form, we review by hand, and you get a personal key by email, usually within 2 business days. No credit card, no plan to pick, no surprise bills. The API is free for non-commercial and commercial use under CC BY 4.0 attribution.

    What's in the API

    The v1 surface covers everything the dashboard reads:

    EndpointWhat it returns
    GET /v1/stationsList of monitoring stations with coordinates and metadata
    GET /v1/stations/:idFull station record + most-recent observation
    GET /v1/stations/:id/observationsTime-series of in-situ readings (DO, pH, salinity, SST) with optional from/to and limit
    GET /v1/stations/:id/indicatorsDaily indicators: WQI, thermal anomaly, bloom risk, DO mg/L, DO saturation %, SSH, eddy flag, health score (1–5)
    GET /v1/stations/snapshotNEW, One-shot latest snapshot for every station (WQI, mortality risk, bloom %, DO sat, eddy/bloom watch, health 1–5)
    GET /v1/stations/:id/feeding-guideNEW, Ration %, timing and rules based on DO supersaturation, NH₃ pH threshold, and SST envelopes
    GET /v1/stations/:id/diver-safetyNEW, Safe/caution/unsafe rating from waves, currents, Kd490 visibility, temperature, jellyfish risk
    GET /v1/stations/:id/bloom-eventsNEW, Detected chl-a bloom events (≥3 µg/L for ≥3 days) with eddy lag and WQI drop
    GET /v1/stations/daily-storyNEW, Today's AI-written Black Sea ocean narrative with WQI snapshot
    POST /v1/push-tokens · GET/PUT /v1/push-tokens/preferences · DELETE /v1/push-tokensNEW, Mobile push notification registration & preferences (user JWT, not API key)
    POST /v1/citizen-science · GET /v1/citizen-science/myNEW, Submit and list field observations with optional photo upload (user JWT)
    GET /v1/organizationsAquaculture organizations in the network
    GET /v1/projectsActive and completed projects
    GET /v1/openapi.jsonMachine-readable OpenAPI 3.0 schema

    Two auth modes. Public/read endpoints use X-API-Key. The four push-token routes and the two citizen-science routes use a Supabase user JWT in Authorization: Bearer <token> so each request is bound to the logged-in mobile-app user.

    Every response is JSON. Pagination is cursor-based via limit + cursor query parameters where applicable. Timestamps are ISO-8601 UTC. Coordinates are WGS84 (longitude, latitude in decimal degrees).

    Quick Start

    Once you have a key, a complete first call is one line:

    curl -H "X-API-Key: aqf_YOUR_KEY_HERE" \
      "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations"
    

    Response (abridged):

    {
      "data": [
        {
          "id": "ro-mangalia-01",
          "name": "Mangalia Bay",
          "country": "Romania",
          "latitude": 43.811,
          "longitude": 28.583,
          "active": true
        },
        { "id": "bg-burgas-01", "name": "Burgas Bay", "country": "Bulgaria", ... },
        { "id": "ge-batumi-01", "name": "Batumi", "country": "Georgia", ... }
      ],
      "meta": { "count": 3 }
    }
    

    That's it. You're talking to the same data source that powers the live dashboard.

    Authentication

    Every request must include your API key in the X-API-Key HTTP header:

    X-API-Key: aqf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    • Never put your key in client-side code (browser JS, mobile app binaries, GitHub repos). Anyone who sees it can use your quota. Always call our API from your own backend or a proxy you control.
    • Keys can be rotated. Email us if you want a fresh key, old ones are revoked instantly.
    • Keys are personal. Don't share them across teams; request one per integration.
    • The API is read-only. You cannot modify data through it.

    If your key is missing, malformed, expired or revoked you get a 401 Unauthorized with a JSON error body explaining what's wrong.

    Base URL & Versioning

    https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api
    

    The version is part of the path (/v1/...). Breaking changes ship as a new major version (/v2/...) with at least 6 months of overlap. Additive, non-breaking changes (new fields, new endpoints) ship to /v1/ continuously. Subscribe to release notes by emailing info@eaquaf.eu.

    Endpoint Reference

    Stations

    GET /v1/stations
    GET /v1/stations/:id
    

    Returns the list of monitoring buoys with location, country, and metadata. Valid station_id values today are ro (Danube Delta), bg (Varna) and ge (Batumi).

    Observations (time-series)

    GET /v1/stations/:id/observations?from=2026-05-01&to=2026-05-31&limit=500
    

    Returns raw readings as { observed_at, parameter, value, unit, source, depth_m }, parameters include sst, oxygen, ph, salinity, chlorophyll, ssh, waves, currents_u/v, nitrate, kd490. Filter with ?parameter=sst. Default limit is 500, max 1000. Records are sorted newest-first.

    Indicators (derived metrics)

    GET /v1/stations/:id/indicators?from=2026-05-01&to=2026-05-31
    

    Daily computed rows: observed_on, wqi (0–100), thermal_anomaly, bloom_risk, do_mgl, do_saturation_pct (García & Gordon 1992), ssh_cm, eddy_active and a 1–5 health_score.

    Organizations & projects

    GET /v1/organizations
    GET /v1/projects
    

    Reference data for the Black Sea aquaculture network, useful if you're building tools for matchmaking, supply-chain mapping or reporting.

    OpenAPI

    GET /v1/openapi.json
    

    The full machine-readable spec. Use it with Postman, Insomnia, or generators like openapi-generator / swagger-codegen to scaffold typed clients in TypeScript, Python, Go, Java, Swift, Kotlin, etc.

    v1.1, Mobile-ready endpoints

    The latest release adds eight endpoints designed for mobile apps and decision-support widgets, plus six user-scoped routes (push tokens + citizen science) authenticated with a Cloud JWT instead of an API key.

    # One-shot snapshot for every station, WQI, mortality risk, eddy/bloom flags, health 1–5
    curl -H "X-API-Key: $KEY" "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations/snapshot"
    
    # Today's AI-written Black Sea narrative (cached daily)
    curl -H "X-API-Key: $KEY" "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations/daily-story"
    
    # Aquaculture decision-support
    curl -H "X-API-Key: $KEY" "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations/ro/feeding-guide"
    curl -H "X-API-Key: $KEY" "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations/bg/diver-safety"
    curl -H "X-API-Key: $KEY" "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations/bg/bloom-events?year=2026"
    

    User-scoped routes (Authorization: Bearer JWT):

    # Register a mobile push token
    curl -X POST "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/push-tokens" \
      -H "Authorization: Bearer $USER_JWT" \
      -H "Content-Type: application/json" \
      -d '{ "fcm_token": "abc...", "platform": "android" }'
    
    # Submit a citizen-science field observation (optional photo as base64)
    curl -X POST "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/citizen-science" \
      -H "Authorization: Bearer $USER_JWT" \
      -H "Content-Type: application/json" \
      -d '{ "station_id": "ge", "water_colour": "brown-green", "foam": true, "visibility_cm": 35 }'
    

    The /v1/stations/:id/indicators payload was extended in the same release: every daily row now also carries do_mgl, do_saturation_pct (García & Gordon 1992), ssh_cm, eddy_active and health_score (1–5) so a mobile sparkline has everything it needs in one call.

    Changelog

    DateVersionWhat changed
    June 2026v1.18 new endpoints, snapshot, feeding-guide, diver-safety, bloom-events, daily-story, push-tokens (POST/GET/PUT/DELETE), citizen-science (POST/GET). Added do_mgl, do_saturation_pct, eddy_active, health_score to indicators. Introduced mobile-app JWT auth for user-scoped routes.
    May 2026v1.0Initial release, stations, observations, indicators, organizations, projects, OpenAPI spec. API-key auth only.

    Code Samples

    JavaScript / Node

    const res = await fetch(
      "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations/ro/observations?parameter=oxygen&limit=24",
      { headers: { "X-API-Key": process.env.AQUASMART_API_KEY } }
    );
    if (!res.ok) throw new Error(`API error ${res.status}`);
    const { data } = await res.json();
    console.log("Latest DO:", data[0].value, data[0].unit);
    

    Python (requests)

    import os, requests
    
    BASE = "https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api"
    HEADERS = {"X-API-Key": os.environ["AQUASMART_API_KEY"]}
    
    r = requests.get(f"{BASE}/v1/stations/ro/observations",
                     headers=HEADERS, params={"parameter": "oxygen", "limit": 24})
    r.raise_for_status()
    for row in r.json()["data"]:
        print(row["observed_at"], row["value"], row["unit"])
    

    R (httr)

    library(httr); library(jsonlite)
    res <- GET(
      paste0("https://nohfpjovcatvjbzebwus.supabase.co/functions/v1/public-api/v1/stations/ro/indicators"),
      query = list(from = "2026-05-01", to = "2026-05-31"),
      add_headers(`X-API-Key` = Sys.getenv("AQUASMART_API_KEY"))
    )
    stop_for_status(res)
    content(res, "parsed")
    

    Rate Limits

    To keep the platform healthy we apply two rolling-window limits, per API key:

    WindowDefault limit
    Short burst60 requests / minute
    Sustained5,000 requests / day

    Every response carries the standard headers X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. When you exceed the limit you get 429 Too Many Requests with a Retry-After header indicating how many seconds to wait.

    If your project genuinely needs more throughput (e.g. an academic backfill, a public-facing app), just say so in the access request, we lift caps case-by-case for free.

    Error Codes

    StatusMeaningWhat to do
    200Success,
    400Bad request, malformed parametersCheck the JSON details field
    401Missing / invalid API keyVerify the X-API-Key header
    403Revoked or scope-denied keyRequest a new key
    404Resource not foundDouble-check the station/project ID
    429Rate limit exceededHonor Retry-After and back off
    500Internal errorRetry with exponential backoff; report if persistent

    All error responses share the shape:

    { "error": "rate_limited", "message": "Try again in 42 seconds.", "details": {} }
    

    Data Licensing & Citation

    All data exposed through the API is published under Creative Commons Attribution 4.0 (CC BY 4.0). You're free to use it commercially, derivative works are encouraged, redistribution is allowed, provided you attribute correctly:

    Source: AQUA-SMART Black Sea Observatory, e-AQUAF Project (BSB01009), co-funded by the Interreg NEXT Black Sea Basin Programme.

    For scientific papers, please add the platform URL: https://eaquaf.eu.

    Reliability & Status

    The API runs on the same managed infrastructure as the dashboard, with continuous health monitoring (in-situ ingest, cron jobs, alerting). Planned maintenance is communicated by email to all key holders at least 48 hours in advance. There is no public status page yet, if you depend on the API in production, write to info@eaquaf.eu and we'll add you to the operational notifications list.

    What's Next

    A few things on the near-term roadmap:

    • WebSocket / SSE streams for live observation push (today you poll)
    • Per-user JWT auth so mobile apps can authenticate end-users directly (today only server-to-server keys)
    • Forecast endpoints exposing the same 48-hour mortality risk and harvest-window models the dashboard uses
    • GraphQL gateway for richer, single-round-trip queries

    If any of these are blockers for your project, tell us in the access request, that's how we prioritise.

    Get Started

    Click Request API access below. We'll review and email your key. You can also download this whole guide as a branded PDF to share with your team.

    Request API access

    Tell us about your project and we'll review your request and email your personal API key, usually within 2 business days. Free for academic and commercial use under CC BY 4.0.

    Full reference
    Interreg NEXT Black Sea Basin Programme – Co-funded by the European Union

    Interreg NEXT Black Sea Basin Programme — Co-funded by the European Union

    Download the AQUA-SMART app

    Android
    Coming soon
    iOS
    Coming soon