The RiverSat API provides programmatic access to river water level data, forecasts, and discharge information for major river systems. All data endpoints support both CSV (default) and JSON response formats.
Select your environment to integrate in minutes with AI
I want to integrate the RiverSat API into this codebase using the TypeScript client library provided below. RiverSat provides river water level data, forecasts, and discharge information via a REST API.
## API Overview
**Base URL:** https://api.insights.earthdaily.com
**Authentication:** Bearer API key in Authorization header
**Response Format:** CSV (default) or JSON. Add `?format=json` to any data endpoint for JSON array responses.
## Available Endpoints
| Endpoint | Description |
|----------|-------------|
| GET /v1/rivers | List available rivers |
| GET /v1/rivers/{river}/discharge | Get discharge data |
| GET /v1/rivers/{river}/daily-levels | Get daily water levels |
| GET /v1/rivers/{river}/daily-levels/{station} | Get levels for specific station |
| GET /v1/rivers/{river}/forecast | Get forecast data |
| GET /v1/rivers/{river}/historical-forecast | Get historical forecasts |
| GET /v1/rivers/{river}/historical-forecast/{station}/{year} | Get forecast by station and year |
## Supported Rivers and Stations
**Rhine River (rhine):**
- maxau, kaub, cologne, duisburg, emmerich
**Mississippi River (mississippi):**
- st_paul_mn, winona_mn, camanche_ia, grafton_il
## TypeScript Client Library
Add this client library to your project as `riversat-client.ts`:
```typescript
const API_BASE_URL = 'https://api.insights.earthdaily.com'
type River = 'rhine' | 'mississippi'
type Format = 'csv' | 'json'
interface RiverInfo {
id: string
display_name: string
is_mock: boolean
data_sources: string[]
}
// Configuration
let authToken: string | null = null
export function setToken(token: string) {
authToken = token
}
// Helper for authenticated requests
async function fetchWithAuth(url: string): Promise<Response> {
if (!authToken) {
throw new Error('No auth token set. Call setToken() first.')
}
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${authToken}` }
})
if (!response.ok) {
throw new Error(`API error: ${response.status} ${response.statusText}`)
}
return response
}
// Helper to append format parameter to URL
function withFormat(url: string, format: Format): string {
if (format === 'csv') return url
const sep = url.includes('?') ? '&' : '?'
return url + sep + 'format=' + format
}
// Helper to parse response based on format
async function parseResponse(response: Response, format: Format): Promise<string | object[]> {
if (format === 'json') return response.json()
return response.text()
}
// List all available rivers
async function listRivers(): Promise<RiverInfo[]> {
const response = await fetchWithAuth(`${API_BASE_URL}/v1/rivers`)
return response.json()
}
// Get river discharge data (CSV or JSON)
async function getDischarge(
river: River,
stationName: string,
startDate: string,
endDate?: string,
format: Format = 'csv'
): Promise<string | object[]> {
const params = new URLSearchParams({ station_name: stationName, start_date: startDate })
if (endDate) params.set('end_date', endDate)
if (format !== 'csv') params.set('format', format)
const response = await fetchWithAuth(`${API_BASE_URL}/v1/rivers/${river}/discharge?${params}`)
return parseResponse(response, format)
}
// Get daily river levels (CSV or JSON)
async function getDailyLevels(
river: River,
options?: { includeHistorical?: boolean; format?: Format }
): Promise<string | object[]> {
const fmt = options?.format ?? 'csv'
let url = `${API_BASE_URL}/v1/rivers/${river}/levels/daily`
if (options?.includeHistorical) url += '?include_historical=true'
url = withFormat(url, fmt)
const response = await fetchWithAuth(url)
return parseResponse(response, fmt)
}
// Get daily levels for a specific station and date range (CSV or JSON)
async function getDailyLevelsByStation(
river: River,
station: string,
startDate: string,
endDate: string,
format: Format = 'csv'
): Promise<string | object[]> {
const params = new URLSearchParams({ start_date: startDate, end_date: endDate })
const url = withFormat(
`${API_BASE_URL}/v1/rivers/${river}/levels/daily/${station}?${params}`,
format
)
const response = await fetchWithAuth(url)
return parseResponse(response, format)
}
// Get recent forecast data (CSV or JSON)
async function getForecast(river: River, format: Format = 'csv'): Promise<string | object[]> {
const url = withFormat(`${API_BASE_URL}/v1/rivers/${river}/forecast`, format)
const response = await fetchWithAuth(url)
return parseResponse(response, format)
}
// Get historical forecast for a specific station and year (CSV or JSON)
async function getForecastByStationYear(
river: River,
station: string,
year: number,
format: Format = 'csv'
): Promise<string | object[]> {
const url = withFormat(
`${API_BASE_URL}/v1/rivers/${river}/forecast/historical/${station}/${year}`,
format
)
const response = await fetchWithAuth(url)
return parseResponse(response, format)
}
export const riversat = {
setToken,
listRivers,
getDischarge,
getDailyLevels,
getDailyLevelsByStation,
getForecast,
getForecastByStationYear
}
```
## OpenAPI Specification
For complete API details, schemas, and additional endpoints, refer to the OpenAPI spec:
https://api.insights.earthdaily.com/openapi.json
## Your Task
1. **Analyze the codebase** to understand the architecture and identify where river data would be valuable
2. **Find relevant modules** that handle logistics, shipping, supply chain, weather, or environmental data
3. **Identify integration points** where water level data, forecasts, or discharge info would add value
4. **Create a mapping** between any existing location/port data and RiverSat station IDs
5. **Add the client library** to an appropriate location in the project
6. **Implement API calls** where the data should be fetched and displayed
7. **Handle authentication** by integrating with the project's existing auth/config patterns
Present your findings as a structured plan before implementing.All API requests require authentication using a Bearer API key in the Authorization header. Create an API key above or contact your EarthDaily representative for organization access.
Authorization: Bearer YOUR_API_KEYGET /v1/rivers HTTP/1.1 Host: api.insights.earthdaily.com Authorization: Bearer ak_abc123...
All API endpoints are relative to the following base URL:
https://api.insights.earthdaily.comThe API currently supports two river systems. Each river has multiple monitoring stations for which you can retrieve water level data and forecasts.
| Station ID | Name |
|---|---|
maxau | Maxau |
kaub | Kaub |
cologne | Cologne |
duisburg | Duisburg |
emmerich | Emmerich |
| Station ID | Name |
|---|---|
st_paul_mn | St. Paul, MN |
winona_mn | Winona, MN |
camanche_ia | Camanche, IA |
grafton_il | Grafton, IL |
/v1/riversReturns a list of all available river systems with metadata including display name, data sources, and whether mock data is being used.
Returns RiverInfo[] with Content-Type: JSON
interface RiverInfo {
id: string
display_name: string
is_mock: boolean
data_sources: string[]
}
const response = await fetch('https://api.insights.earthdaily.com/v1/rivers', {
headers: {
'Authorization': `Bearer ${token}`
}
})
const rivers: RiverInfo[] = await response.json()/v1/rivers/{river}/dischargeReturns river discharge data from S3 as CSV (default) or JSON format. Use format=json for JSON array output. Discharge measures the volume of water flowing through a river cross-section per unit of time.
| Parameter | Type | Required | Description |
|---|---|---|---|
river | string | Yes | River system identifier. One of: rhine, mississippi |
station_name | string | Yes | Station name to filter by (e.g., kaub, cologne, duisburg) |
start_date | string | Yes | Start datetime in ISO 8601 format with timezone (e.g., 2024-01-01T00:00:00Z) |
end_date | string | No | End datetime in ISO 8601 format with timezone. Defaults to now. Maximum 2 year range from start_date. |
format | string | No | Response format: 'csv' (default) or 'json'(default: csv) |
Returns CSV (default) or JSON array with Content-Type: text/csv (default) or application/json
const params = new URLSearchParams({
station_name: 'kaub',
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-06-01T00:00:00Z'
})
const response = await fetch(`https://api.insights.earthdaily.com/v1/rivers/rhine/discharge?${params}`, {
headers: {
'Authorization': `Bearer ${token}`
}
})
const csvData = await response.text()
// Parse CSV data
const rows = csvData.split('\n').map(row => row.split(','))
// Add format=json to params for JSON array response/v1/rivers/{river}/levels/dailyReturns daily river levels data (mean, max, min) from S3 as CSV (default) or JSON format. Use format=json for JSON array output. By default returns only current year data. Use include_historical=true to get all historical data.
| Parameter | Type | Required | Description |
|---|---|---|---|
river | string | Yes | River system identifier. One of: rhine, mississippi |
include_historical | boolean | No | If true, return all historical data. If false (default), only return current year data.(default: false) |
format | string | No | Response format: 'csv' (default) or 'json'(default: csv) |
Returns CSV (default) or JSON array with Content-Type: text/csv (default) or application/json
// Current year only
const response = await fetch('https://api.insights.earthdaily.com/v1/rivers/rhine/levels/daily', {
headers: {
'Authorization': `Bearer ${token}`
}
})
// Include historical data
const historicalResponse = await fetch(
'https://api.insights.earthdaily.com/v1/rivers/rhine/levels/daily?include_historical=true',
{
headers: {
'Authorization': `Bearer ${token}`
}
}
)
const csvData = await response.text()
// Add ?format=json to the URL for JSON array response/v1/rivers/{river}/levels/daily/{station}Returns daily river levels data (mean, max, min) for a specific station filtered by date range from S3 as CSV (default) or JSON format. Use format=json for JSON array output.
| Parameter | Type | Required | Description |
|---|---|---|---|
river | string | Yes | River system identifier. One of: rhine, mississippi |
station | string | Yes | Station ID (e.g., kaub, cologne, duisburg for Rhine; st_paul_mn, winona_mn for Mississippi) |
start_date | string | Yes | Start date in YYYY-MM-DD format |
end_date | string | Yes | End date in YYYY-MM-DD format |
format | string | No | Response format: 'csv' (default) or 'json'(default: csv) |
Returns CSV (default) or JSON array with Content-Type: text/csv (default) or application/json
const params = new URLSearchParams({
start_date: '2024-01-01',
end_date: '2024-12-31'
})
const response = await fetch(
`https://api.insights.earthdaily.com/v1/rivers/rhine/levels/daily/kaub?${params}`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
)
const csvData = await response.text()
// Add ?format=json to the URL for JSON array response/v1/rivers/{river}/forecastReturns recent river level forecast data from S3 parquet file as CSV (default) or JSON format. Use format=json for JSON array output. This is a smaller file containing only the most recent forecast runs.
| Parameter | Type | Required | Description |
|---|---|---|---|
river | string | Yes | River system identifier. One of: rhine, mississippi |
format | string | No | Response format: 'csv' (default) or 'json'(default: csv) |
Returns CSV (default) or JSON array with Content-Type: text/csv (default) or application/json
const response = await fetch('https://api.insights.earthdaily.com/v1/rivers/rhine/forecast', {
headers: {
'Authorization': `Bearer ${token}`
}
})
const csvData = await response.text()
// CSV contains forecast data with columns like:
// station, forecast_date, target_date, predicted_level, confidence_lower, confidence_upper
// Add ?format=json to the URL for JSON array response/v1/rivers/{river}/forecast/historical/{station}/{year}Returns historical river level forecast data for a specific station and year from S3 parquet file as CSV (default) or JSON format. Use format=json for JSON array output.
| Parameter | Type | Required | Description |
|---|---|---|---|
river | string | Yes | River system identifier. One of: rhine, mississippi |
station | string | Yes | Station ID (e.g., kaub, cologne, duisburg for Rhine) |
year | integer | Yes | Year (e.g., 2024) |
format | string | No | Response format: 'csv' (default) or 'json'(default: csv) |
Returns CSV (default) or JSON array with Content-Type: text/csv (default) or application/json
const response = await fetch(
'https://api.insights.earthdaily.com/v1/rivers/rhine/forecast/historical/kaub/2024',
{
headers: {
'Authorization': `Bearer ${token}`
}
}
)
const csvData = await response.text()
// Add ?format=json to the URL for JSON array responseThe API uses standard HTTP status codes to indicate the success or failure of requests.
| Status Code | Description |
|---|---|
| 200 | Success - Request completed successfully |
| 401 | Unauthorized - Invalid or missing authentication token |
| 404 | Not Found - The requested resource does not exist |
| 422 | Validation Error - Invalid parameters provided |
| 500 | Internal Server Error - An unexpected error occurred |
When a validation error occurs (422), the response body contains details about the invalid parameters:
{
"detail": [
{
"loc": ["path", "river"],
"msg": "Input should be 'rhine' or 'mississippi'",
"type": "enum"
}
]
}