Skip to main content

GraphQL API

The Apollon API provides a full GraphQL interface with query/mutation support via async-graphql.

Endpoints

EndpointMethodDescription
/v1/gqlPOSTGraphQL query/mutation endpoint
/v1/graphiqlGETGraphiQL IDE (disabled when docs.graphiql = false)
/v1/schemaGETGraphQL schema in SDL format (plain text)

Custom Scalars

ScalarFormatExample
DateTimeRFC 3339 string"2026-06-09T12:00:00Z"
UUIDStandard UUID string"550e8400-e29b-41d4-a716-446655440000"

Queries

gps

Current GPS position from the Peplink router. Returns null if the GPS provider is unreachable.

query {
gps {
id
timestamp
latitude
longitude
altitude
speedKmh
speedMps
speedMph
speedKnots
tripId
}
}

gpsSpeed

Current speed from the Peplink router. Returns null if unreachable.

query {
gpsSpeed {
speedKmh
}
}

gpsHistory

Historical GPS records in a time range. Both parameters are unix timestamps (seconds). Defaults to the last 24 hours.

query {
gpsHistory(start: 1717848000, end: 1717934400) {
start
end
count
records {
id
timestamp
latitude
longitude
altitude
speedKmh
tripId
}
}
}
ArgumentTypeRequiredDefaultDescription
startIntNo24h agoStart of time range (unix timestamp)
endIntNonowEnd of time range (unix timestamp)

trips

All trips, ordered by start time descending.

query {
trips {
id
startTime
endTime
cargo
weight
status
logGps
category {
id
name
}
sender {
id
name
}
receiver {
id
name
}
gpsLocations {
latitude
longitude
speedKmh
timestamp
}
}
}

trip

A single trip by ID.

query {
trip(id: "550e8400-e29b-41d4-a716-446655440000") {
id
cargo
status
startLatitude
startLongitude
endLatitude
endLongitude
category { name }
sender { name }
receiver { name }
gpsLocations { latitude longitude timestamp }
}
}

clients

All clients, ordered by name ascending.

query {
clients {
id
name
email
phone
city
country
contacts {
id
name
email
position
isPrimary
}
tripsAsSender { id cargo status }
tripsAsReceiver { id cargo status }
}
}

client

A single client by ID.

query {
client(id: "550e8400-e29b-41d4-a716-446655440000") {
id
name
email
street
houseNumber
postalCode
city
country
additionalInfo
contacts { id name isPrimary }
tripsAsSender { id cargo }
tripsAsReceiver { id cargo }
}
}

categories

All cargo categories, ordered by name ascending.

query {
categories {
id
name
description
createdAt
updatedAt
trips { id cargo status }
}
}

category

A single cargo category by ID.

query {
category(id: "550e8400-e29b-41d4-a716-446655440000") {
id
name
description
createdAt
updatedAt
trips { id cargo status weight }
}
}

watchlistEntries

All watchlist entries, ordered by name ascending.

query {
watchlistEntries {
id
mmsi
name
categoryId
alertSound
dangerSound
starColor
rangeThresholds
createdAt
updatedAt
}
}

watchlistEntry

A single watchlist entry by ID.

query {
watchlistEntry(id: "550e8400-e29b-41d4-a716-446655440000") {
id
mmsi
name
categoryId
starColor
rangeThresholds
}
}

watchlistCategories

All watchlist categories, ordered by name ascending.

query {
watchlistCategories {
id
name
color
displayType
soundEnabled
overlayEnabled
overlayIcon
alertSound
dangerSound
rangeThresholds
createdAt
updatedAt
}
}

watchlistCategory

A single watchlist category by ID.

query {
watchlistCategory(id: "550e8400-e29b-41d4-a716-446655440000") {
id
name
color
displayType
overlayIcon
}
}

watchlistSettings

Global watchlist settings (singleton). Returns null if not yet initialized.

query {
watchlistSettings {
id
rangeThresholds
defaultAlertSound
defaultDangerSound
defaultStarColor
updatedAt
}
}

watchlistSounds

All available watchlist sounds (built-in + custom).

query {
watchlistSounds {
id
key
name
volume
fileId
builtin
createdAt
}
}

health

System health check covering database, Peplink, forwarding, and WebSocket status.

query {
health {
status
uptime
database
peplink
forwarding
websocket
websocketClients
timestamp
}
}

pegel

Nearest water gauge station from Pegelonline WSV. Returns null if disabled or no station found.

With stations whitelist configured: returns the nearest whitelisted station (no radius limit). Without whitelist: searches by GPS proximity within radius / server config.

query($water: String, $radius: Float) {
pegel(water: $water, radius: $radius) {
stationName
waterName
km
latitude
longitude
value
unit
timestamp
state
}
}
ArgumentTypeDescription
waterStringFilter by water body name (e.g. RHEIN)
radiusFloatSearch radius in km (whitelist mode: ignored, radius mode: capped at server config)

activeVessels

AIS vessels seen within the look-back window, ordered by lastSeen descending (newest first). Records come from the persistent vessels registry, so this includes vessels no longer on the live map.

query {
activeVessels(withinSecs: 3600) {
id
mmsi
name
shipType
length
beam
callsign
firstSeen
lastSeen
updatedAt
source
}
}

`source` is the last effective tracking source (`"local"` | `"aisstream"`, null until the first activity flush)the same value carried live on the `vessels` WS payload. Local has position priority; aisstream takes over on handoff.
ArgumentTypeRequiredDescription
withinSecsInt!YesLook-back window in seconds — only vessels whose lastSeen falls within it are returned

vessels

All vessels in the persistent vessels registry, ordered by lastSeen descending (newest first).

query {
vessels {
id
mmsi
name
shipType
length
beam
callsign
firstSeen
lastSeen
updatedAt
}
}

vessel

A single registry vessel by MMSI. Returns null if the MMSI is not in the registry.

query {
vessel(mmsi: 211234567) {
id
mmsi
name
shipType
callsign
lastSeen
}
}
ArgumentTypeRequiredDescription
mmsiInt!YesMaritime Mobile Service Identity

vesselHistory

Static-field change audit log from vessels_history, ordered by changedAt descending (newest first). Each entry records one static field change (name, shipType, length, beam, or callsign).

query {
vesselHistory(mmsi: 211234567, limit: 50) {
id
mmsi
field
oldValue
newValue
changedAt
}
}
ArgumentTypeRequiredDescription
mmsiIntNoFilter to a single vessel; omit for all vessels
limitIntNoMax entries to return (default 200, max 1000)

Mutations

createTrip

Create a new trip.

mutation {
createTrip(input: {
startLatitude: 51.5074
startLongitude: -0.1278
cargo: "Electronics"
categoryId: "..."
weight: 250.5
senderId: "..."
receiverId: "..."
logGps: true
}) {
id
startTime
cargo
status
}
}

Input: CreateTripInput

FieldTypeRequiredDefault
startLatitudeFloat!Yes--
startLongitudeFloat!Yes--
cargoString!Yes--
categoryIdUUID!Yes--
weightFloat!Yes--
senderIdUUID!Yes--
receiverIdUUID!Yes--
logGpsBoolean!Nofalse

updateTrip

Update an existing trip. Only provided fields are changed.

mutation {
updateTrip(input: {
id: "550e8400-..."
cargo: "Updated Electronics"
weight: 300.0
status: CANCELLED
}) {
id
cargo
weight
status
}
}

Input: UpdateTripInput

FieldTypeRequired
idUUID!Yes
cargoStringNo
categoryIdUUIDNo
weightFloatNo
senderIdUUIDNo
receiverIdUUIDNo
statusGqlTripStatusNo
logGpsBooleanNo

deleteTrip

Delete a trip and its associated GPS locations. Returns true on success.

mutation {
deleteTrip(id: "550e8400-...")
}

completeTrip

Complete an active trip by setting end coordinates and status.

mutation {
completeTrip(input: {
id: "550e8400-..."
endLatitude: 52.5200
endLongitude: 13.4050
}) {
id
status
endTime
endLatitude
endLongitude
}
}

Input: CompleteTripInput

FieldTypeRequired
idUUID!Yes
endLatitudeFloat!Yes
endLongitudeFloat!Yes

createClient

Create a new client, optionally with contact persons.

mutation {
createClient(input: {
name: "ACME Logistics"
email: "info@acme.example.com"
phone: "+49 30 12345678"
street: "Hauptstrasse"
houseNumber: "42"
postalCode: "10115"
city: "Berlin"
country: "DE"
contacts: [{
name: "John Doe"
email: "john@acme.example.com"
phone: "+49 30 12345679"
position: "Logistics Manager"
isPrimary: true
}]
}) {
id
name
contacts { id name isPrimary }
}
}

Input: CreateClientInput

FieldTypeRequiredDefault
nameString!Yes--
emailString!Yes--
phoneString!Yes--
streetString!Yes--
houseNumberString!Yes--
postalCodeString!Yes--
cityString!Yes--
countryString!Yes--
additionalInfoStringNonull
contacts[CreateContactInput!]!No[]

updateClient

Update an existing client. Only provided fields are changed.

mutation {
updateClient(input: {
id: "550e8400-..."
name: "ACME Logistics GmbH"
city: "Hamburg"
}) {
id
name
city
}
}

Input: UpdateClientInput

FieldTypeRequired
idUUID!Yes
nameStringNo
emailStringNo
phoneStringNo
streetStringNo
houseNumberStringNo
postalCodeStringNo
cityStringNo
countryStringNo
additionalInfoStringNo

createContact

Add a contact person to an existing client.

mutation {
createContact(
clientId: "550e8400-..."
input: {
name: "Jane Smith"
email: "jane@acme.example.com"
phone: "+49 30 12345680"
position: "Fleet Manager"
isPrimary: false
}
) {
id
name
isPrimary
clientId
}
}

Input: CreateContactInput

FieldTypeRequiredDefault
nameString!Yes--
emailString!Yes--
phoneString!Yes--
positionString!Yes--
isPrimaryBoolean!Nofalse

updateContact

Update a contact person. Only provided fields are changed.

mutation {
updateContact(input: {
id: "660e8400-..."
clientId: "550e8400-..."
name: "Jane Doe"
isPrimary: true
}) {
id
name
isPrimary
}
}

Input: UpdateContactInput

FieldTypeRequired
idUUID!Yes
clientIdUUID!Yes
nameStringNo
emailStringNo
phoneStringNo
positionStringNo
isPrimaryBooleanNo

deleteContact

Delete a contact person. Returns true on success.

mutation {
deleteContact(contactId: "660e8400-...", clientId: "550e8400-...")
}

createCategory

Create a new cargo category.

mutation {
createCategory(input: {
name: "Fragile Goods"
description: "Items requiring careful handling"
}) {
id
name
description
createdAt
}
}

Input: CreateCategoryInput

FieldTypeRequired
nameString!Yes
descriptionStringNo

updateCategory

Update an existing cargo category. Only provided fields are changed.

mutation {
updateCategory(input: {
id: "550e8400-..."
name: "Fragile Items"
}) {
id
name
updatedAt
}
}

Input: UpdateCategoryInput

FieldTypeRequired
idUUID!Yes
nameStringNo
descriptionStringNo

deleteCategory

Delete a cargo category. Returns false if trips still reference it.

mutation {
deleteCategory(id: "550e8400-...")
}

createWatchlistEntry

Create a new watchlist entry.

mutation {
createWatchlistEntry(input: {
mmsi: "211234567"
name: "MS Harmonie"
categoryId: "..."
alertSound: "sonar"
dangerSound: "alarm"
starColor: "#EF4444"
rangeThresholds: [10.0, 7.0, 5.0, 2.0, 1.0]
}) {
id
mmsi
name
createdAt
}
}

Input: CreateWatchlistEntryInput

FieldTypeRequiredDefault
mmsiString!Yes--
nameString!Yes--
categoryIdUUIDNonull
alertSoundStringNonull
dangerSoundStringNonull
starColorStringNonull
rangeThresholdsJSONNonull

updateWatchlistEntry

Update an existing watchlist entry. Only provided fields are changed.

mutation {
updateWatchlistEntry(input: {
id: "550e8400-..."
name: "MS Harmonie II"
starColor: "#F59E0B"
}) {
id
name
starColor
updatedAt
}
}

Input: UpdateWatchlistEntryInput

FieldTypeRequired
idUUID!Yes
mmsiStringNo
nameStringNo
categoryIdUUIDNo
alertSoundStringNo
dangerSoundStringNo
starColorStringNo
rangeThresholdsJSONNo

deleteWatchlistEntry

Delete a watchlist entry by ID. Returns true on success.

mutation {
deleteWatchlistEntry(id: "550e8400-...")
}

createWatchlistCategory

Create a new watchlist category.

mutation {
createWatchlistCategory(input: {
name: "Freighter"
color: "#EF4444"
displayType: "stars"
soundEnabled: true
overlayEnabled: true
}) {
id
name
color
createdAt
}
}

Input: CreateWatchlistCategoryInput

FieldTypeRequiredDefault
nameString!Yes--
colorString!Yes--
displayTypeStringNo"stars"
soundEnabledBooleanNotrue
overlayEnabledBooleanNotrue
overlayIconStringNonull
alertSoundStringNonull
dangerSoundStringNonull
rangeThresholdsJSONNonull

updateWatchlistCategory

Update an existing watchlist category. Only provided fields are changed.

mutation {
updateWatchlistCategory(input: {
id: "550e8400-..."
name: "Tanker"
color: "#F97316"
}) {
id
name
color
updatedAt
}
}

Input: UpdateWatchlistCategoryInput

FieldTypeRequired
idUUID!Yes
nameStringNo
colorStringNo
displayTypeStringNo
soundEnabledBooleanNo
overlayEnabledBooleanNo
overlayIconStringNo
alertSoundStringNo
dangerSoundStringNo
rangeThresholdsJSONNo

deleteWatchlistCategory

Delete a watchlist category by ID. Returns true on success.

mutation {
deleteWatchlistCategory(id: "550e8400-...")
}

updateWatchlistSettings

Update global watchlist settings (upserts). Only provided fields are changed.

mutation {
updateWatchlistSettings(input: {
rangeThresholds: [8.0, 6.0, 4.0, 2.0, 0.5]
defaultStarColor: "#F59E0B"
}) {
id
rangeThresholds
defaultStarColor
updatedAt
}
}

Input: UpdateWatchlistSettingsInput

FieldTypeRequired
rangeThresholdsJSONNo
defaultAlertSoundStringNo
defaultDangerSoundStringNo
defaultStarColorStringNo

deleteWatchlistSound

Delete a custom watchlist sound by ID. Built-in sounds cannot be deleted. Returns error if the sound is still referenced.

mutation {
deleteWatchlistSound(id: "550e8400-...")
}

updateWatchlistSoundVolume

Update the volume of a watchlist sound (0-100).

mutation {
updateWatchlistSoundVolume(id: "550e8400-...", volume: 80) {
id
key
name
volume
}
}

updateVessel

Manually overwrite a vessel's static fields. Full-representation update — the input always carries all 5 editable fields; an omitted field is written as null (no partial merge).

mutation {
updateVessel(input: {
mmsi: 211234567
name: "MS Harmonie"
shipType: 70
length: 110
beam: 11
callsign: "DA1234"
}) {
id
mmsi
name
shipType
length
beam
callsign
}
}

Input: UpdateVesselInput

FieldTypeRequired
mmsiInt!Yes
nameStringNo
shipTypeIntNo
lengthIntNo
beamIntNo
callsignStringNo

deleteVessel

Hard-delete a vessel from the registry. ignore: true also adds the MMSI to the persistent ignore list (union'd with [ais] ignore_mmsi config). Returns true on success.

mutation {
deleteVessel(mmsi: 211234567, ignore: false)
}
ArgumentTypeRequiredDescription
mmsiInt!YesMaritime Mobile Service Identity
ignoreBoolean!YesAlso blacklist the MMSI persistently

Output Types

GqlGpsLocation

FieldTypeDescription
idUUID!Location record ID
timestampDateTime!When the location was recorded
latitudeFloat!Latitude in degrees
longitudeFloat!Longitude in degrees
altitudeFloatAltitude in meters (nullable)
speedKmhFloat!Speed in km/h
speedMpsFloat!Speed in m/s
speedMphFloat!Speed in mph
speedKnotsFloat!Speed in knots
tripIdUUIDAssociated trip ID (nullable)

GqlTrip

FieldTypeDescription
idUUID!Trip ID
startTimeDateTime!Trip start time
endTimeDateTimeTrip end time (null if active)
startLatitudeFloat!Start latitude
startLongitudeFloat!Start longitude
endLatitudeFloatEnd latitude (null if active)
endLongitudeFloatEnd longitude (null if active)
cargoString!Cargo description
weightFloat!Cargo weight
statusGqlTripStatus!ACTIVE, COMPLETED, or CANCELLED
logGpsBoolean!Whether GPS logging is enabled
categoryGqlCargoCategory!Resolved category relation
senderGqlClient!Resolved sender client relation
receiverGqlClient!Resolved receiver client relation
gpsLocations[GqlGpsLocation!]!GPS locations for this trip

GqlClient

FieldTypeDescription
idUUID!Client ID
nameString!Client name
emailString!Email address
phoneString!Phone number
streetString!Street name
houseNumberString!House number
postalCodeString!Postal code
cityString!City
countryString!Country
additionalInfoStringAdditional info (nullable)
contacts[GqlContactPerson!]!Contact persons
tripsAsSender[GqlTrip!]!Trips where client is sender
tripsAsReceiver[GqlTrip!]!Trips where client is receiver

GqlContactPerson

FieldTypeDescription
idUUID!Contact ID
nameString!Contact name
emailString!Email
phoneString!Phone number
positionString!Job position/title
isPrimaryBoolean!Whether this is the primary contact
clientIdUUID!Parent client ID

GqlCargoCategory

FieldTypeDescription
idUUID!Category ID
nameString!Category name
descriptionStringDescription (nullable)
createdAtDateTime!Creation timestamp
updatedAtDateTime!Last update timestamp
trips[GqlTrip!]!Trips in this category

GqlTripStatus (Enum)

ValueDescription
ACTIVETrip is in progress
COMPLETEDTrip has been completed
CANCELLEDTrip has been cancelled

GqlWatchlistEntry

FieldTypeDescription
idUUID!Entry ID
mmsiString!MMSI number
nameString!Display name
categoryIdUUIDCategory ID (nullable)
alertSoundStringAlert sound key (nullable)
dangerSoundStringDanger sound key (nullable)
starColorStringHex star color (nullable, inherits from category/settings)
rangeThresholdsJSONDistance thresholds array (nullable)
createdAtDateTime!Creation timestamp
updatedAtDateTime!Last update timestamp

GqlWatchlistCategory

FieldTypeDescription
idUUID!Category ID
nameString!Category name
colorString!Hex color
displayTypeString!Display mode (stars or custom)
soundEnabledBoolean!Whether sound alerts are enabled
overlayEnabledBoolean!Whether overlay display is enabled
overlayIconStringLucide icon name (nullable, for custom display)
alertSoundStringAlert sound key (nullable)
dangerSoundStringDanger sound key (nullable)
rangeThresholdsJSONDistance thresholds array (nullable)
createdAtDateTime!Creation timestamp
updatedAtDateTime!Last update timestamp

GqlWatchlistSettings

FieldTypeDescription
idUUID!Settings ID
rangeThresholdsJSON!Default 5-element distance thresholds in km
defaultAlertSoundStringDefault alert sound key (nullable)
defaultDangerSoundStringDefault danger sound key (nullable)
defaultStarColorString!Default hex star color
updatedAtDateTime!Last update timestamp

GqlWatchlistSound

FieldTypeDescription
idUUID!Sound ID
keyString!Unique sound key
nameString!Display name
fileIdUUID!Associated storage file ID
volumeInt!Volume level (0-100)
builtinBoolean!Whether this is a built-in sound
createdAtDateTime!Creation timestamp

VesselRecordGql

FieldTypeDescription
idUUID!Vessel registry record ID
mmsiInt!Maritime Mobile Service Identity
nameStringVessel name (nullable)
shipTypeIntRaw AIS ship type code (nullable)
lengthIntLength in meters (nullable)
beamIntBeam in meters (nullable)
callsignStringRadio call sign (nullable)
firstSeenDateTime!First AIS contact
lastSeenDateTime!Most recent AIS contact
updatedAtDateTime!Last registry write

VesselHistoryGql

FieldTypeDescription
idUUID!History entry ID
mmsiInt!Maritime Mobile Service Identity
fieldString!Changed static field (name, shipType, length, beam, callsign)
oldValueStringPrevious value (nullable)
newValueStringNew value (nullable)
changedAtDateTime!Change timestamp

HealthStatus

FieldTypeDescription
statusString!Overall status (ok or degraded)
uptimeInt!Server uptime in seconds
databaseString!Database status
peplinkString!Peplink provider status
forwardingString!Forwarding service status
websocketString!WebSocket status (running or closing)
websocketClientsInt!Number of connected WebSocket clients
timestampDateTime!Check timestamp