API
All fleet and event data is also available as an open, unauthenticated JSON API — no account, no API key needed. Meant for your own automations (Home Assistant, n8n, Node-RED, custom scripts). To prevent abuse, a rate limit of 60 requests/minute per IP address applies; the response includes the headers X-RateLimit-Limit and X-RateLimit-Remaining for this, and 429 with Retry-After when exceeded.
GET /api/v1/ships
Current status of all 8 fleet ships.
curl https://schiffstracker.example.de/api/v1/ships
[
{
"mmsi": "477116800",
"slug": "hefei",
"name": "BYD Hefei",
"latitude": 53.55,
"longitude": 8.58,
"sog": 15.2,
"cog": 41,
"destination_name": "Hamburg",
"destination_confidence": "gesichert",
"heading_to_germany": 1,
"eta": "2026-08-27T06:00:00.000Z",
"position_updated_at": "2026-08-25T20:04:00.000Z",
"...": "weitere Felder, siehe /api/v1/ships/{slug}"
}
]GET /api/v1/ships/{slug}
Status of a single ship. The slugs match the ship page URLs (e.g. hefei for /schiff/hefei). Unknown slug → 404.
curl https://schiffstracker.example.de/api/v1/ships/hefei
{
"mmsi": "477116800",
"slug": "hefei",
"name": "BYD Hefei",
"latitude": 53.55,
"longitude": 8.58,
"sog": 15.2,
"cog": 41,
"destination_name": "Hamburg",
"destination_confidence": "gesichert",
"heading_to_germany": 1,
"eta": "2026-08-27T06:00:00.000Z",
"position_updated_at": "2026-08-25T20:04:00.000Z",
"approach": {
"state": "approaching",
"closingKm": 180.4,
"windowHours": 22.5,
"nearestPort": { "locode": "DEHAM", "name": "Hamburg", "distanceKm": 210.1 }
}
}The eta field is the estimated time of arrival as reported by the crew via AIS (ISO timestamp in UTC, or null). It is not validated and often not reset after arrival.
The approach field is a movement-based direction estimate from the track (independent of the reported destination): state is approaching, receding, steady, or unknown; closingKm is the net approach to the nearest German port within the time window. It's also included per ship in GET /api/v1/ships.
The projection field is the projected route to the German destination port (or null): kind is to-port, points are [lat, lng] pairs from the current position to the port. A ship's current heading is available separately in the cog field (course over ground).
GET /api/v1/ships/{slug}/track
The recorded track of a ship (thinned-out position points, oldest first). Optional query parameter sinceHours (default 72, maximum 720 = 30 days retention).
curl "https://schiffstracker.example.de/api/v1/ships/hefei/track?sinceHours=48"
[
{
"id": 1024,
"mmsi": "477116800",
"latitude": 51.9,
"longitude": 4.1,
"sog": 12.4,
"cog": 88,
"recorded_at": "2026-08-25T18:02:00.000Z"
}
]GET /api/v1/events
Events for ships heading to Germany and arriving in German ports (the same ones as in the RSS feed; for a confirmed destination and on arrival also as a Discord notification), as JSON instead of XML.
Optional query parameters: limit (default 30, max 100), mmsi (filter to one ship) and type (filter to one event type).
Event types in the event_type field: heading_to_germany_possible (possible destination in Germany, unconfirmed), heading_to_germany (confirmed destination in Germany) and arrived (arrived at the German destination port, i.e. moored, at anchor or nearly stopped).
curl "https://schiffstracker.example.de/api/v1/events?limit=10&mmsi=477116800"
curl "https://schiffstracker.example.de/api/v1/events?type=arrived"
[
{
"id": 42,
"mmsi": "477116800",
"ship_name": "BYD Hefei",
"ship_slug": "hefei",
"event_type": "heading_to_germany",
"destination_name": "Hamburg",
"occurred_at": "2026-08-25T20:04:00.000Z"
}
]Example: Home Assistant
“Notify me on arrival”: a REST sensor polls the latest arrived event, its value is the event id. When it changes, a ship has arrived and the automation says so. The condition stops a notification when Home Assistant restarts. Use type=heading_to_germany instead of arrived for “heading to Germany”.
# configuration.yaml
rest:
- resource: https://schiffstracker.example.de/api/v1/events?type=arrived&limit=1
scan_interval: 300
sensor:
- name: "BYD letzte Ankunft"
value_template: "{{ value_json[0].id if value_json | length > 0 else 0 }}"
json_attributes_path: "$[0]"
json_attributes:
- ship_name
- destination_name
- occurred_at# automations.yaml
- alias: "BYD-Schiff angekommen"
trigger:
- platform: state
entity_id: sensor.byd_letzte_ankunft
condition:
- condition: template
value_template: "{{ trigger.from_state.state not in ['unknown', 'unavailable'] }}"
action:
- service: notify.notify
data:
message: >-
{{ state_attr('sensor.byd_letzte_ankunft', 'ship_name') }} ist in
{{ state_attr('sensor.byd_letzte_ankunft', 'destination_name') }} angekommen