OBDRestTRIPS
iPhone App · Web App · OpenAPI

Your logbook simply comes along.

OBDRest reads trips, error codes and measured values directly from your car via an OBD2 adapter. Trips are recorded automatically, classified as private or business and synchronized with your server – where you can view, manage and export everything.

Also works offlineYour data belongs to youStandard server or your own server
128OBD2 measured values decoded
3,074Mercedes error codes explained
4Trip types in the logbook
60documented API operations
How it works

From the plug to the evaluation

No cable clutter, no manual work: plug in the adapter, set up the app once – OBDRest takes care of the rest in the background.

🔌

Plug in the adapter

An ELM327 Bluetooth LE adapter (e.g. Vgate iCar Pro 2S) into the OBD2 socket. The app remembers the adapter.

📱

Start driving

Ignition on – iOS connects automatically, even in the background. Route, speed, consumption and engine values are recorded.

☁️

Synchronize

After the trip, the trip, vehicle data, errors and measured values go to your chosen server – the standard server or your own. When offline, a queue waits.

📊

Evaluate & export

In the browser: assign logbook entries, view statistics, track errors, export CSV/JSON/GPX.

Centerpiece

Your data on the server – view, manage, export

The app stores everything locally and works without a network. With a server, your data is additionally backed up, available on all devices and can be evaluated in the browser.

👀

View

  • Overview with key figures, consumption and eco-score
  • Every trip with map, speed, RPM and elevation profile
  • Vehicles with control units, error codes, measured values
  • Statistics: weekdays, time of day, driving time vs. parking time
  • Heatmap of your routes and annual calendar of driving days
🗂️

Manage

  • Assign trips as private / business / commute – individually or in bulk
  • Purpose and multi-line description per trip
  • Expenses with receipts, vehicle registration and photos
  • Delete trips (with permission), keep vehicles separate
  • Administrators manage users and permissions
📤

Export

  • PDF logbook print-ready (A4 landscape, monthly totals)
  • CSV logbook for Excel/Numbers with totals per type
  • JSON full export of all data, optionally with measurement points
  • GPX per trip for map apps
  • REST API for your own evaluations and scripts
PDF logbookCSV logbookJSON complete exportGPX routeOpenAPI 3.1 interfacecurl examples
📒 Logbook

Private or business? One tap is enough.

Every recorded trip gets a start and destination address, distance and duration. You assign them – in the app by swiping, in the browser by clicking or for many trips at once. The assignment is synchronized in both directions.

🏠 Private Leisure
💼 Business Client, appointment
🏢 Commute Commuting
❔ Unassigned Open
  • Totals per type and month as a chart
  • Filter by period, type, vehicle and full text
  • CSV export with date, time, addresses, km, purpose
  • "Logbook" widget on the iPhone home screen

ℹ️ OBDRest provides the data for your logbook. Whether an electronic logbook is recognized for tax purposes depends on further requirements (e.g. immutability) – please consult your tax advisor.

Trip list with assignment Private, Business and Commute
Expenses: fuel price, consumption from fuel receipts and costs per month
💶 Expenses & Receipts

Fuel, parking, repairs – all costs at a glance.

Record every expense in seconds – in the browser or in the app, optionally directly with a photo of the receipt. OBDRest calculates fuel price, actual consumption between two full tanks and your cost per kilometer from this.

⛽ Fuel Liters, €/l, consumption
🅿️ Parking Duration, locations
🔧 Repair & maintenance Inspection, tires, MOT
🧾 Other Toll, AdBlue, accessories
  • Receipts as photo or PDF – multiple per expense, directly with the camera in the app
  • PDF receipts are displayed in the browser with pdf.js – with zoom and download
  • Vehicle registration, photos, insurance stored with the vehicle
  • Expenses per month, category and vehicle – also in the statistics
  • Privacy: Each file is visible only to its owner – even with a manipulated URL
Features

Everything your car reveals

The iPhone app only reads – it changes nothing on the vehicle (only exception: clearing the error memory after confirmation).

🎛️

Cockpit & live data

All measured values supported by the vehicle from all control units in 10 groups – from RPM to DPF differential pressure.

🛣️

Automatic trips

Start and end are detected, even in the background. Map, consumption, CO₂, eco-score, driving events.

⚠️

Error memory

Current and old errors (OBD 03/07/0A and manufacturer diagnostics UDS), freeze frame, history.

📚

3,074 codes explained

Reference for Mercedes error codes, searchable and with highlighting of found codes.

🩺

Analysis

Rules for battery, coolant, thermostat, catalytic converter, particulate filter and readiness tests.

🅿️

Movement & parking

How long does the car drive, how long does it stand? Ratio, parking breaks and monthly trend.

🔐

Accounts & permissions

SSO or local account, everyone sees only their own data, administrators additionally see all.

🔥

Heatmap & annual calendar

Where are you often? Heatmap of all routes and parking locations, plus an annual calendar like GitHub with all driving days.

💶

Expenses

Fuel, parking, repair and other with charts, fuel price, consumption and cost per km.

📎

Receipts & documents

Photos and PDFs for expenses and vehicles – camera in the app, pdf.js view in the browser.

📝

Description & PDF

Multi-line description per trip, logbook as print-ready PDF, CSV or JSON.

🚗

Where is my car?

Parking spot at the end of the last trip with current address – one tap starts walking navigation, in the app and in the browser.

🧮

Odometer

Enter odometer reading per vehicle (app, web, MCP), optionally also for fuel, parking and workshop. Today's reading is extrapolated from the trips since then.

🤖

MCP Agent

Query trips, expenses and statistics in natural language – with Claude and other MCP clients. All commands →

📶

Offline first

Everything is stored locally; a queue sends data once a network is available. Fully usable without a server.

Screenshots

This is what it looks like

With test data: a Mercedes GLC 220 d and a VW Golf, trips in Berlin and to the Baltic Sea. Click to enlarge.

Cockpit
Cockpit
Live data
Live data
Active trip
Active trip
Trip with map
Trip with map
Error memory
Error memory
Server dialog
Server dialog
Supported adapters

The right plug for the OBD2 port

OBDRest communicates with ELM327-compatible adapters via Bluetooth Low Energy. The OBD2 port is usually located under the steering wheel; mandatory for gasoline vehicles from 2001 and diesel vehicles from 2004 (EU).

✅ My adapter · tested

Vgate iCar Pro 2S

Illustration of the Vgate iCar Pro 2S with light ring and OBD2 plug

Compact OBD2 adapter with Bluetooth 5.2, ELM327 command set v2.3, and light ring. It sleeps automatically (quiescent current approx. 3 mA) and wakes up on start – including hybrid and electric vehicles – so it can remain plugged in permanently. On the iPhone it appears as IOS-Vlink.

  • Connection directly in the app via BLE – do not pair in iOS settings
  • Automatic connection in the background as soon as the ignition is on
  • Tested with Mercedes-Benz GLC (X253, 2015), CAN 11 bit / 500 kbit/s

Compatibility

Adapter / interfaceBLE serviceStatus
Vgate iCar Pro 2S18F0✅ tested
Vgate iCar Pro (BLE 4.0)18F0🟢 same interface
ELM327 BLE adapter (many clones)FFF0🟢 supported
HM-10-based adaptersFFE0🟢 supported
Adapters with service E7810A71…E7810A71🟢 supported
Classic Bluetooth (SPP) on iPhone–❌ not allowed by iOS
Wi-Fi adapters–⏳ currently not

ℹ️ "Supported" means: The app recognizes the BLE service and speaks ELM327. Cheap clones often report a wrong firmware version and cannot handle multiple queries or manufacturer diagnostics (UDS) – the app then automatically falls back to individual queries.

Operation

Where does your data go? You decide.

The app works without a server. If you want to sync, you use either the default server – or your own server. Switch anytime in the app: connection button top right → "Adapter & Server" → Server.

Option A · default

☁️ Default server

Preconfigured, nothing to set up. Register an account, sign in to the app – done.

Adresse:  https://app.fahrten.fusenigk.de
Benutzer: dein Konto (SSO oder registriert)
Option B · your own server

🏠 Your own server

Run our web app yourself (Docker) or use your own implementation of the documented REST API. In the app, just change the address.

Adresse:  https://fahrten.meine-firma.de
Benutzer: Konto auf deinem Server

🔒 The app sends data exclusively to the address shown in the server dialog. Without a server, all data remains only on the iPhone. Switching is possible at any time – "Reset sync" then sends all trips to the new server.

Recommended

☁️ Hosted

Ready to go immediately at app.fahrten.fusenigk.de: TLS, daily maintenance, SSO login, registration in one minute.

Register now
On-premises

🏠 In your own network

The complete web app runs as a Docker Compose stack (Next.js + MariaDB) on your server or NAS. Login via Keycloak/SSO or local accounts.

# Webapp-Verzeichnis kopieren, .env anlegen
cp .env.example .env    # DB-Passwörter, SESSION_SECRET
docker compose up -d --build
curl http://localhost:3330/api/v1/health
For developers

🧩 Your own server

The app speaks an open REST interface documented as OpenAPI 3.1. Implement the sync endpoints yourself – e.g., for your fleet management – and enter the address in the app.

API documentation openapi.yaml 🤖 MCP agent
Questions

Frequently asked questions

Which adapter do I need?

See Supported adapters.

An ELM327-compatible adapter with Bluetooth Low Energy, tested with the Vgate iCar Pro 2S (identifies as "IOS-Vlink"). Do not pair in iOS Bluetooth settings – the app connects directly.

Do I have to use your server?

No. The default is app.fahrten.fusenigk.de, but you can enter your own server at any time – our web app via Docker Compose or your own implementation of the REST API. Or work entirely without a server.

Does the app work without a server?

Yes. Trips, errors, and measurements are always stored on the iPhone. The server is a supplement: backup, analysis in the browser, export, and multiple devices.

Who can see my data?

Only you. Every query is limited to your account. Administrators of your installation can view all data for management purposes – with on-prem, that's you yourself.

How do I export my logbook?

In the web app under "Trips" → "Logbook (CSV)" (filters are applied) or via GET /api/v1/export/fahrten.csv. All data is available as JSON, each route as GPX.

Can I try the demo?

Yes – select "View demo" on the login page (user demo, password demo). The demo contains test trips, error codes, and measurements, is read-only, and for security reasons can only be used in the browser – for the app and the REST API you need your own account.

Is the vehicle modified?

No. OBDRest only uses read-only diagnostic services. The only exception is clearing the error memory – only after explicit confirmation.

Ready for the first trip?

Create an account, enter the server in the app, start driving.

MCP agent mcp-fahrten v1.0.0

Query your trip data in natural language – in Claude Code, Claude Desktop, or any other client with Model Context Protocol (MCP). The agent uses the documented REST API: with the default server or your own server.

🔍 21 read-only tools

Trips, logbook, statistics, heatmap, vehicles, errors, measurements, expenses, parking location

✏️ 5 write tools

Assign and describe trips, record expenses, upload receipts – marked as "modifies data"

📤 Exports

Logbook as PDF or CSV, all data as JSON, routes as GPX, download receipts

💬 Example dialog

You: How many kilometers did I drive for business in October, what did the car cost me and where is it right now?
→ fahrtenbuch_auswertung(from 2026-10-01, to 2026-10-31) · ausgaben_statistik(…) · parkplatz()
Claude: In October you drove 246 km for business (14% of all kilometers). Expenses were around €1,180 – mainly the inspection (€489.60) and the DPF cleaning (€378). Your GLC has been parked since yesterday at 14:36 at Unter den Linden 10 – on foot: [Google Maps link]. Three trips have not yet been assigned – should I enter them as "commute"?

Writing tools (✏️) are only executed by the client after your confirmation.

General

READSfahrten_statusStatus and login

Checks the server and database and shows the logged-in user with their permissions (send, delete, API, administrator).

No parameters.

Example prompts
Is the trip server reachable and which account am I logged in with?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrten_status", "arguments": {}}}

Trips & logbook

READSfahrten_listeList trips

Lists trips with date, route, km, type (private/business/commute), consumption and eco-score. Filter by period, type, vehicle and full text.

Parameters (* required)
NameTypeDescription
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
artprivat | geschaeftlich | arbeitsweg | noneTrip type (none = unassigned)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
suchestringFull text in addresses, label and description
limitnumberCount (default 50, max. 1000)
allebooleanAdministrators only: data of all users
Example prompts
Show me all business trips in October 2026.Which trips went to Potsdam?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrten_liste", "arguments": {}}}
READSfahrt_detailTrip in detail

All metrics of a trip (route, duration, speed, consumption, CO₂, eco-score with factors, driving events, description). Optionally a thinned-out measurement point table.

Parameters (* required)
NameTypeDescription
id *stringTrip ID (UUID)
messpunktenumberNumber of measurement points in the output (0 = none, default 0)
allebooleanAdministrators only: data of all users
Example prompts
How economical was my last trip and what can I do better?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrt_detail", "arguments": {"id": "…"}}}
READSfahrtenbuch_auswertungEvaluate logbook

Kilometers per trip type and month, shares of private/business/commute and the list of trips not yet assigned.

Parameters (* required)
NameTypeDescription
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
How many kilometers did I drive for business in 2026, and which trips have not yet been assigned?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrtenbuch_auswertung", "arguments": {}}}
WRITESfahrt_zuordnenAssign trips

✏️ Modifies data: assigns one or more trips as private, business or commute.

Parameters (* required)
NameTypeDescription
ids *string[]Trip IDs
art *privat | geschaeftlich | arbeitsweg | noneTrip type (none = unassigned)
Example prompts
Assign trips 6f1b2c3d-… and 7a2c… as business.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrt_zuordnen", "arguments": {"ids": "…", "art": "…"}}}
WRITESfahrt_bearbeitenEdit trip

✏️ Modifies data: sets the type, label (short, e.g. customer) and/or the multi-line description of a trip.

Parameters (* required)
NameTypeDescription
id *stringTrip ID
artprivat | geschaeftlich | arbeitsweg | noneTrip type (none = unassigned)
etikettstringShort label / purpose
beschreibungstringMulti-line description (empty = remove)
Example prompts
Enter "Customer appointment Muster GmbH" as the purpose for my trip to Adlershof.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrt_bearbeiten", "arguments": {"id": "…"}}}

Statistics & analyses

READSstatistikStatistics

Metrics for a period: trips, km, hours, liters, Ø consumption, CO₂, eco-score, idling, driving events, km per month, weekdays, times and route lengths.

Parameters (* required)
NameTypeDescription
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
Give me statistics on my trips in the last quarter.On which weekday do I drive the most?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "statistik", "arguments": {}}}
READSbewegung_parkenMovement & parking

How long are the vehicles moved and how long are they parked? Driving time, idling, parking time, share of driving, ratio and parking breaks.

Parameters (* required)
NameTypeDescription
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
What percentage of the time is my car just sitting around?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "bewegung_parken", "arguments": {}}}
READSheatmap_orteMost frequent places (heatmap)

The most frequent start/destination locations (parking locations) and the extent of all trips – basis of the heatmap.

Parameters (* required)
NameTypeDescription
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
artprivat | geschaeftlich | arbeitsweg | noneTrip type (none = unassigned)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
Where do I park most often?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "heatmap_orte", "arguments": {}}}
READSjahreskarteYear map (trips per day)

Trips and km per calendar day of a year (like the GitHub activity display): active days, longest streak, day with the most trips.

Parameters (* required)
NameTypeDescription
jahrnumberYear (default: current year)
artprivat | geschaeftlich | arbeitsweg | noneTrip type (none = unassigned)
allebooleanAdministrators only: data of all users
Example prompts
On how many days did I drive in 2026 and what was my longest streak?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "jahreskarte", "arguments": {}}}
READSmonatsberichtMonthly report

Compact report for a month: trips, km, logbook breakdown, consumption, eco-score, expenses per category, cost per km and active errors.

Parameters (* required)
NameTypeDescription
monat *stringMonth YYYY-MM
allebooleanAdministrators only: data of all users
Example prompts
Create a monthly report for October 2026 for me.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "monatsbericht", "arguments": {"monat": "…"}}}

Vehicles & diagnostics

READSfahrzeuge_listeVehicles

All vehicles with VIN, trips, km, fuel, active errors and last trip.

Parameters (* required)
NameTypeDescription
allebooleanAdministrators only: data of all users
Example prompts
Which vehicles do I have and how many km have they driven?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrzeuge_liste", "arguments": {}}}
READSfahrzeug_zustandVehicle condition

Condition of a vehicle: metrics, active and old error codes, control units and the latest measured values with findings from the analysis.

Parameters (* required)
NameTypeDescription
id *numberVehicle ID
allebooleanAdministrators only: data of all users
Example prompts
Is everything okay with my GLC?Which errors does vehicle 4 have?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fahrzeug_zustand", "arguments": {"id": 1}}}
READSfehler_listeError codes

Error codes (DTC) of all or one vehicle with description, system, status (active/old), first/last seen and count.

Parameters (* required)
NameTypeDescription
aktivbooleanonly active errors
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
Which error codes are currently active?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "fehler_liste", "arguments": {}}}
READSmesswert_verlaufMeasured value history

History of an OBD measured value across all snapshots (e.g. 42 = control unit voltage, 05 = coolant, 2F = fuel level) with minimum, maximum and mean.

Parameters (* required)
NameTypeDescription
pid *stringOBD PID hexadecimal
allebooleanAdministrators only: data of all users
Example prompts
How has the onboard voltage developed? Is the battery weak?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "messwert_verlauf", "arguments": {"pid": "…"}}}
READSparkplatzWhere is my car?

Parking location per vehicle (end of the last trip) with address, time and links for walking navigation (Google Maps, Apple Maps).

Parameters (* required)
NameTypeDescription
allebooleanAdministrators only: data of all users
Example prompts
Where have I parked my car?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "parkplatz", "arguments": {}}}
READSkilometerstandMileage

Last recorded mileage of a vehicle (manually or from fuel/workshop receipts), estimated mileage today (+ km driven since then) and history.

Parameters (* required)
NameTypeDescription
fahrzeug *numberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
What is the current mileage of my GLC?When is the next inspection due if it is scheduled every 25,000 km?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "kilometerstand", "arguments": {"fahrzeug": 1}}}
WRITESkilometerstand_erfassenRecord mileage

✏️ Modifies data: saves a read-off mileage for one of your own vehicles.

Parameters (* required)
NameTypeDescription
fahrzeug *numberVehicle ID (see fahrzeuge_liste)
km *numberMileage (whole km)
datumstringISO date (default: now)
notizstringNote
Example prompts
My GLC has 128,450 km on the odometer today – enter that.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "kilometerstand_erfassen", "arguments": {"fahrzeug": 1, "km": 1}}}

Expenses & receipts

READSausgaben_listeList expenses

Expenses (fuel, parking, repairs, other) with totals per category, provider, details and number of receipts.

Parameters (* required)
NameTypeDescription
categoryfuel | parking | repair | otherCategory
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
What did I spend on fuel in October?List all repairs with invoices.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "ausgaben_liste", "arguments": {}}}
READSexpense_statisticsEvaluate expenses

Cost per month and category, cost per kilometer, Ø fuel price, consumption from full tank fill-ups, most expensive parking locations, repairs by type, expenses per vehicle.

Parameters (* required)
NameTypeDescription
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
allebooleanAdministrators only: data of all users
Example prompts
What does my car cost me per kilometer?How has the fuel price developed?
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "ausgaben_statistik", "arguments": {}}}
WRITEScreate_expenseRecord expense

✏️ Modifies data: creates an expense (fuel with liters/price/full tank, parking with duration, repair with type/invoice number, other). Then upload receipts with receipt_upload.

Parameters (* required)
NameTypeDescription
category *fuel | parking | repair | otherCategory
amount *numberAmount in euros
datumstringTimestamp ISO 8601 (default: now)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
providerstringGas station, parking garage, workshop
locationstringLocation/address
odometernumberOdometer
notizstringNote
litersnumberFuel: liters
price_per_liternumberFuel: €/l
full_tankbooleanFuel: full tank
fuel_typestringFuel: e.g. diesel
duration_minnumberParking: minutes
repair_typestringRepair: inspection, oil change, tires, HU/AU, …
invoice_nostringRepair: invoice number
Example prompts
I just filled up 48.6 l of diesel at Aral for €82.45, odometer 129980.Record €6.50 parking in the Adlershof parking garage for 2 hours.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "ausgabe_anlegen", "arguments": {"kategorie": "…", "betrag": 1}}}
READSreceipts_listReceipts and vehicle documents

Receipts (photos/PDFs) of an expense or documents of a vehicle (registration certificate, photos, insurance) with ID, type and size.

Parameters (* required)
NameTypeDescription
expense_idstringExpense ID
vehicle_idnumberVehicle ID (instead of expense_id)
allebooleanAdministrators only: data of all users
Example prompts
Which receipts are attached to the inspection from October 5?Show me the documents of my GLC.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "belege_liste", "arguments": {}}}
READSdownload_receiptDownload receipt

Saves a receipt or a vehicle document (photo/PDF) locally. Only own files.

Parameters (* required)
NameTypeDescription
id *stringFile ID (see receipts_list)
target_pathstringLocal target path of the file (default: current directory)
allebooleanAdministrators only: data of all users
Example prompts
Download the invoice for the inspection.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "beleg_herunterladen", "arguments": {"id": "…"}}}
WRITESupload_receiptUpload receipt

✏️ Modifies data: uploads local photos/PDFs (JPEG, PNG, WebP, HEIC, PDF; max. 15 MB) to an expense or as a vehicle document.

Parameters (* required)
NameTypeDescription
paths *string[]Local file paths
expense_idstringExpense ID
vehicle_idnumberVehicle ID (instead of expense_id)
document_typeregistration_certificate | photo | insurance | otheronly with vehicle_id (default photo)
Example prompts
Upload ~/Downloads/invoice.pdf as a receipt for repair 3c1e….File ~/Scans/registration_certificate.pdf with vehicle 4 as registration certificate.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "beleg_hochladen", "arguments": {"pfade": "…"}}}

Export

READSexport_logbookExport logbook

Saves the logbook as PDF (A4 landscape, monthly totals), CSV (Excel, totals per type) or all data as JSON locally.

Parameters (* required)
NameTypeDescription
format *pdf | csv | jsonFormat
vonstringStart date YYYY-MM-DD (optional)
bisstringEnd date YYYY-MM-DD, inclusive (optional)
artprivat | geschaeftlich | arbeitsweg | noneTrip type (none = unassigned)
fahrzeugnumberVehicle ID (see fahrzeuge_liste)
target_pathstringLocal target path of the file (default: current directory)
allebooleanAdministrators only: data of all users
Example prompts
Export my business logbook 2026 as PDF.Save all my data as JSON.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "export_fahrtenbuch", "arguments": {"format": "…"}}}
READSexport_gpxRoute as GPX

Saves the GPS route of a trip as GPX 1.1 (elevation, time, speed) – e.g. for map apps.

Parameters (* required)
NameTypeDescription
id *stringTrip ID
target_pathstringLocal target path of the file (default: current directory)
allebooleanAdministrators only: data of all users
Example prompts
Save the route of my Baltic Sea trip as GPX.
Call (JSON-RPC)
{"method": "tools/call", "params": {"name": "export_gpx", "arguments": {"id": "…"}}}

📋 Prompts (Templates)

PromptDescriptionArguments
monthly_reportReport for one month (trips, logbook, expenses, errors) with assessment.month: month YYYY-MM
complete_logbookFind unassigned trips and make suggestions for assignment.from: start date YYYY-MM-DD
vehicle_checkCheck the condition of all vehicles (errors, battery, maintenance).–

Resource: fahrten://openapi.yaml – the OpenAPI specification of the REST API.

API documentation v1.4.0

REST interface for trips, vehicles, error codes and measurements of the iOS app OBDRest · OpenAPI 3.1.0 · download openapi.yaml

📘 Basics

The iOS app OBDRest reads vehicle data via OBD2 adapter (ELM327, Bluetooth LE), records trips and sends them to this server. The same interface can be used to read, manage and export all data – or to implement your own server to which the app sends its data (server dialog in the app: address, user, password).

Response format: All JSON responses have the envelope { "ok": true, "data": … } or { "ok": false, "error": "plain text", "details": … }. Times are ISO 8601 in UTC.

Authentication (read first):

  1. POST /auth/login with username and password (SSO account or local account) → data.token.
  2. Every further call with header Authorization: Bearer <token>. Tokens for client: "app" are valid for 90 days, for client: "web" for 12 hours (then additionally as httpOnly cookie fahrten_session).
  3. Alternatively for scripts: HTTP Basic (curl -u user:password).

Permissions: Normal users only see and change their own data. Administrators see the data of all users with ?all=1 or that of one user with ?user=<id> and manage users under /admin/users.

Uploads are idempotent: Trips, fault readings and snapshots carry a UUID from the app; vehicles are identified via user + vehicle identification number (VIN). Resending does not create duplicates.

Server
https://app.fahrten.fusenigk.de/api/v1 – Production (hosted)
https://fahrten.fusenigk.de/api/v1 – Redirect for older app installations
http://localhost:3330/api/v1 – On-premises / own installation (Docker Compose)

📦 Response format and errors

Every JSON response is an envelope: {"ok": true, "daten": …} on success, {"ok": false, "fehler": "Plain text", "details": …} on errors. Exports (CSV, JSON file, GPX) return the file directly.

StatusMeaning
200/201Success
400Invalid input (zod validation, details names the field)
401Not signed in or token expired → sign in again
403No permission (e.g. send, delete, administration)
404Not found – also if the record belongs to another user
409/429Conflict (name taken) / too many requests
500/503Server error / SSO or database unreachable

Authentication

Login, registration, logout, own user

POST/auth/login🌐 public

Sign in and obtain token

Checks the password via SSO (Keycloak, realm fusenigk) or – for local accounts – against the stored scrypt hash. Only users who are enabled in the app (table users) receive a token. The call writes nothing to the database. After 10 failed attempts per IP in 15 minutes, the server responds with 429.

API right: Accounts without the darfApi right (e.g. the demo account demo) receive the response 403 with client: "app" (grund: api_disabled) – only after the password has been verified. Such accounts can only sign in in the browser; bearer tokens and HTTP Basic are also rejected for them with 403.

Request (application/json) – schema LoginAnfrage
{
  "username": "max.mustermann",
  "password": "geheim-und-lang",
  "client": "app"
}
Responses
200Signed in
400Invalid input
401Username or password incorrect (also for unknown user – no enumeration)
403Password correct, but account not enabled, locked or without API right (grund: api_disabled, e.g. demo account)
429Too many failed attempts
503SSO server unreachable
Example response
{
  "ok": true,
  "daten": {
    "benutzer": {
      "id": 7,
      "username": "max.mustermann",
      "name": "Max Mustermann",
      "email": "max@example.org",
      "rolle": "user",
      "istAdmin": false,
      "darfSenden": true,
      "darfLoeschen": true,
      "darfApi": true,
      "aktiv": true,
      "anmeldung": "local"
    },
    "methode": "local",
    "token": "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiRGVtby1CZW51dHplciIsImFydCI6ImFwcCJ9.…",
    "ablauf": "2027-02-05T09:20:00.000Z"
  }
}
curl – set credentials (own account – the demo account has no API access)
export BENUTZER='max.mustermann'
export PASSWORT='geheim-und-lang'
curl – log in and store token in variable
TOKEN=$(curl -s https://app.fahrten.fusenigk.de/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d "{\"username\":\"$BENUTZER\",\"password\":\"$PASSWORT\",\"client\":\"app\"}" | jq -r .daten.token)
echo "$TOKEN"
curl – then every call with bearer token
curl -s https://app.fahrten.fusenigk.de/api/v1/auth/me -H "Authorization: Bearer $TOKEN"
curl – alternative without token – HTTP Basic
curl -s -u "$BENUTZER:$PASSWORT" https://app.fahrten.fusenigk.de/api/v1/auth/me
POST/auth/registrieren🌐 public

Create local account

Creates a local user (role user, may send and delete own trips) in the database and signs them in directly. Reserved names (admin, demo, …) and names already taken → 409. At most 5 registrations per IP in 15 minutes.

Request (application/json) – schema Registrierung
{
  "username": "max.mustermann",
  "name": "Max Mustermann",
  "email": "max@example.org",
  "passwort": "geheim-und-lang",
  "client": "app"
}
Responses
201Created and signed in (response like login)
400Invalid input
409Name reserved or taken
429Too many registrations
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/auth/registrieren \
  -H 'Content-Type: application/json' \
  -d '{"username":"max.mustermann","name":"Max Mustermann","email":"max@example.org","passwort":"geheim-und-lang","client":"app"}'
GET/auth/me🔒 Sign-in required

Signed-in user with rights

Responses
200Users
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/auth/me -H "Authorization: Bearer $TOKEN"
POST/auth/logout🌐 public

Delete session cookie

Bearer tokens are stateless (JWT) and expire; logging out only affects the browser cookie.

Responses
200Signed out
429Too many requests
curl
curl -s -X POST https://app.fahrten.fusenigk.de/api/v1/auth/logout

Synchronization

Uploads from the iOS app (also authoritative for custom server implementations)

POST/sync/fahrten🔒 Sign-in required

Send trips including measurement points

Accepts 1–50 trips in the app's Codable format (Trip). Existing trips with the same UUID are replaced (including all measurement points); a UUID of a different user is never overwritten (status: fremd). The vehicle is assigned or created via vin. Right darfSenden required.

Request (application/json)
Responses
200Result per trip
400Invalid input
401Not signed in
403No permission to send
Example response
{
  "ok": true,
  "daten": {
    "fahrten": [
      {
        "id": "6f1b2c3d-4e5f-4a1b-9c2d-0123456789ab",
        "status": "neu",
        "messpunkte": 1834
      }
    ]
  }
}
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/fahrten \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"fahrzeugName":"GLC 220 d","trips":[{"id":"6F1B2C3D-4E5F-4A1B-9C2D-0123456789AB",
       "startDate":"2026-11-07T07:00:00Z","endDate":"2026-11-07T07:24:00Z","kind":"geschaeftlich",
       "note":"Kundentermin","fuelType":"diesel","vin":"WDC2539051F123456","isDemo":false,
       "summary":{"distanceKm":18.4,"litersPer100km":6.1,"eco":{"score":81,"factors":[]}},
       "samples":[{"time":"2026-11-07T07:00:02Z","speed":12.5,"rpm":1100,"latitude":52.52,"longitude":13.405}]}]}'
POST/sync/fahrzeug🔒 Sign-in required

Send vehicle and control unit data (OBD mode 09)

Request (application/json) – schema FahrzeugUpload
Responses
200Vehicle created/updated
403No permission to send
Example response
{
  "ok": true,
  "daten": {
    "fahrzeugId": 4
  }
}
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/fahrzeug \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"vin":"WDC2539051F123456","name":"Mercedes-Benz GLC (2015)","fuelType":"diesel",
       "protocol":"ISO 15765-4 CAN (11 Bit, 500 kBaud)","adapter":"IOS-Vlink",
       "ecus":[{"ecu":"7E8","name":"ECM – EngineControl","calibrationIDs":["6519015400"],"calibrationVerificationNumbers":["1A2B3C4D"]}]}'
POST/sync/fehler🔒 Sign-in required

Send fault memory reading and fault history

Stores the reading raw and consolidates the history per code (first/last seen, count, active).

Request (application/json) – schema FehlerUpload
Responses
200saved
401Not signed in
Example response
{
  "ok": true,
  "daten": {
    "id": "0d6e…",
    "neu": true,
    "codes": 2,
    "aktiv": 1
  }
}
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/fehler \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"id":"0D6E2A11-1C2B-4E7F-9A10-2B3C4D5E6F70","vin":"WDC2539051F123456","readAt":"2026-11-07T07:01:00Z",
       "entries":[{"code":"P2002","kind":"stored","ecu":"7E8","description":"Dieselpartikelfilter – Wirkungsgrad unter Schwellenwert","udsStatus":47}],
       "udsECUs":["7E8"],"history":[]}'
POST/sync/messwerte🔒 Sign-in required

Send snapshot of all live measurement values

Request (application/json) – schema Momentaufnahme
Responses
200saved
401Not signed in
Example response
{
  "ok": true,
  "daten": {
    "id": "9a…",
    "neu": true,
    "werte": 42
  }
}
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/messwerte \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"id":"9A1B2C3D-0000-4000-8000-000000000001","vin":"WDC2539051F123456","takenAt":"2026-11-07T07:10:00Z",
       "voltage":14.1,"protocol":"ISO 15765-4 CAN","readings":[{"pid":"0C","ecu":"7E8","name":"Drehzahl","value":1850,"unit":"U/min","group":"Motor"}],
       "findings":[{"title":"Ladespannung in Ordnung","detail":"14,1 V","severity":"ok"}]}'
GET/sync/index🔒 Sign-in required

Own trip IDs with modification timestamp

Basis for synchronization in the app – missing trips are loaded, assignments changed on the web are adopted.

Responses
200Index
401Not signed in
Example response
{
  "ok": true,
  "daten": {
    "fahrten": [
      {
        "id": "6F1B2C3D-4E5F-4A1B-9C2D-0123456789AB",
        "aktualisiert": "2026-11-07T08:00:00.000Z",
        "messpunkte": 1834
      }
    ]
  }
}
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/index -H "Authorization: Bearer $TOKEN" | jq '.daten.fahrten | length'
POST/sync/ausgaben🔒 Sign-in required

Send expenses from the app (1–500, idempotent via the UUID)

Request (application/json)
{
  "ausgaben": [
    {
      "kategorie": "tanken",
      "datum": "2026-11-07T08:15:00Z",
      "betrag": 82.45,
      "fahrzeugId": 4,
      "anbieter": "Aral Unter den Linden",
      "liter": 48.6,
      "preisJeLiter": 1.699,
      "kraftstoff": "Diesel",
      "vollgetankt": true,
      "kmStand": 129980,
      "id": "3c1e5a2b-7d4f-4e8a-9b1c-2d3e4f5a6b7c"
    }
  ]
}
Responses
200Status per expense (new/updated/fremd)
401Not signed in
403no permission
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/ausgaben -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d @ausgaben.json
POST/sync/kilometerstand🔒 Sign-in required

Send odometer readings from the app (1–500, idempotent via the UUID, vehicle via the VIN)

Request (application/json)
{
  "kilometerstaende": [
    {
      "id": "5b0e7d1c-2a4f-4c3e-8d9a-1f2e3d4c5b6a",
      "vin": "WDC2539091F000000",
      "km": 128450,
      "datum": "2026-11-07T09:00:00Z"
    }
  ]
}
Responses
200Status per entry (new/updated/fremd/kein-fahrzeug)
401Not signed in
403no permission
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/kilometerstand -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d @kilometerstaende.json
POST/sync/unknown🔒 Login required

Report unknown codes from the app (PIDs without decoder, error codes without description)

Aggregated per user + vehicle (VIN) + type + code + control unit; the last 20 raw data records are retained as samples. Administrators evaluate the entries under /admin/unknown.

Request (application/json)
{
  "vin": "WDC2539091F000000",
  "protokoll": "ISO 15765-4 CAN (11 bit, 500 kbaud)",
  "adapter": "Vgate iCar Pro",
  "codes": [
    {
      "art": "pid",
      "code": "8B",
      "ecu": "7E8",
      "modus": "01",
      "roh": "1F 00 2A 10",
      "gesehen": "2026-11-07T18:00:00Z"
    }
  ]
}
Responses
200Vehicle ID, number of codes, of which new
400invalid input (e.g. raw data not as hex)
401Not signed in
403no permission to send
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/unbekannt -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d @unbekannt.json
GET/sync/ausgaben-index🔒 Sign-in required

Own expense IDs with modification timestamp

Responses
200`daten.ausgaben[]`
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/sync/ausgaben-index -H "Authorization: Bearer $TOKEN"

Trips

Read trips, assign logbook category (Private/Business/Commute), delete

GET/fahrten🔒 Sign-in required

List trips

Parameters
NameLocationTypeDescription
allequerystring (1)

Administrators only: data of all users

benutzerqueryinteger

Administrators only: data of a specific user

fahrzeugqueryinteger

Vehicle ID

vonquerystring · dateExample: 2026-10-01
bisquerystring · dateExample: 2026-10-31
artqueryFahrtArt
suchequerystring

Full text in addresses and note

limitqueryinteger
offsetqueryinteger
Responses
200Page of the trip list
401Not signed in
curl – business trips in October
curl -s 'https://app.fahrten.fusenigk.de/api/v1/fahrten?art=geschaeftlich&von=2026-10-01&bis=2026-10-31' \
  -H "Authorization: Bearer $TOKEN" | jq '.daten.fahrten[] | {start, km, startAdresse, zielAdresse, notiz}'
PATCH/fahrten🔒 Sign-in required

Bulk assignment Private / Business / Commute

Request (application/json)
Responses
200Number of changed trips
401Not signed in
Example response
{
  "ok": true,
  "daten": {
    "geaendert": 2
  }
}
curl
curl -s -X PATCH https://app.fahrten.fusenigk.de/api/v1/fahrten \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"ids":["6f1b2c3d-4e5f-4a1b-9c2d-0123456789ab","7a2c…"],"kind":"geschaeftlich"}'
GET/fahrten/{id}🔒 Sign-in required

Trip with all measurement points

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
formatquerystring (app)

app returns the iOS app's Codable format (Trip)

allequerystring (1)

Administrators only: data of all users

Responses
200Trip incl. `punkte` (or `samples` with format=app)
404Not found (or not visible)
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fahrten/$ID -H "Authorization: Bearer $TOKEN" | jq '.daten | {km, art, punkte: (.punkte|length)}'
PATCH/fahrten/{id}🔒 Sign-in required

Change type, label and description of a trip

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Request (application/json)
{
  "kind": "geschaeftlich",
  "note": "Kundentermin Adlershof",
  "details": "Projektbesprechung mit Frau Muster.\nRückweg über Lager Schönefeld (Material abgeholt)."
}
Responses
200changed
404Not found (or not visible)
curl
curl -s -X PATCH https://app.fahrten.fusenigk.de/api/v1/fahrten/$ID \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"kind":"geschaeftlich","note":"Kundentermin Adlershof","details":"Projektbesprechung.\nRückweg über Lager Schönefeld."}'
DELETE/fahrten/{id}🔒 Sign-in required

Delete trip (right darfLoeschen)

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200deleted
403No permission
404Not found (or not visible)
curl
curl -s -X DELETE https://app.fahrten.fusenigk.de/api/v1/fahrten/$ID -H "Authorization: Bearer $TOKEN"

Vehicles

Vehicles per user (identified via the vehicle identification number)

GET/fahrzeuge🔒 Sign-in required

Vehicles with key figures

Parameters
NameLocationTypeDescription
allequerystring (1)

Administrators only: data of all users

Responses
200List (`daten.fahrzeuge`)
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fahrzeuge -H "Authorization: Bearer $TOKEN" | jq '.daten.fahrzeuge[] | {name, vin, fahrten, km, fehlerAktiv}'
GET/fahrzeuge/{id}🔒 Sign-in required

Vehicle with monthly history, faults, recent trips and latest measurement values

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Responses
200Vehicle
404Not found (or not visible)
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fahrzeuge/4 -H "Authorization: Bearer $TOKEN"
GET/fahrzeuge/{id}/kilometerstand🔒 Sign-in required

Odometer – last and estimated reading, history (manual and from expenses)

current is the most recent known reading – manually recorded or as the kmStand of an entry (fueling, parking, repair, other). estimated = km + sum of trips recorded thereafter (seitherKm).

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Responses
200Odometer
401Not signed in
404Not found (or not visible)
Example response
{
  "ok": true,
  "daten": {
    "aktuell": {
      "km": 128450,
      "datum": "2026-11-01T09:00:00Z",
      "geschaetzt": 128712,
      "seitherKm": 262
    },
    "verlauf": [
      {
        "id": "3C1E5A2B-7D4F-4E8A-9B1C-2D3E4F5A6B7C",
        "km": 128450,
        "datum": "2026-11-01T09:00:00Z",
        "quelle": "manuell",
        "notiz": "Tacho abgelesen",
        "ausgabeId": null
      }
    ]
  }
}
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fahrzeuge/4/kilometerstand -H "Authorization: Bearer $TOKEN"
POST/fahrzeuge/{id}/kilometerstand🔒 Login required

Record mileage (idempotent via optional UUID)

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Request (application/json) – Schema Kilometerstand
{
  "km": 128450,
  "datum": "2026-11-07T09:00:00Z",
  "notiz": "Tacho abgelesen"
}
Responses
200updated
201newly created
400invalid input
401Not signed in
403no permission (e.g. demo access)
404Not found (or not visible)
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fahrzeuge/4/kilometerstand \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"km": 128450, "notiz": "Tacho abgelesen"}'
DELETE/kilometerstand/{id}🔒 Login required

Delete manually recorded mileage (change readings from entries via the entry)

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200deleted
401Not signed in
403no permission
404Not found (or not visible)
curl
curl -s -X DELETE https://app.fahrten.fusenigk.de/api/v1/kilometerstand/3c1e5a2b-7d4f-4e8a-9b1c-2d3e4f5a6b7c -H "Authorization: Bearer $TOKEN"

Errors

Fault codes (DTC) and readout operations

GET/fehler🔒 Login required

Fault codes (active and old)

Parameters
NameLocationTypeDescription
aktivquerystring (1)

only active codes

fahrzeugqueryinteger
allequerystring (1)

Administrators only: data of all users

Responses
200List (`daten.fehler`)
401Not signed in
curl
curl -s 'https://app.fahrten.fusenigk.de/api/v1/fehler?aktiv=1' -H "Authorization: Bearer $TOKEN" | jq '.daten.fehler[] | {code, beschreibung, fahrzeug}'
GET/fehler/{id}🔒 Login required

Fault code with all readouts in which it occurred

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Responses
200Errors
404Not found (or not visible)
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fehler/12 -H "Authorization: Bearer $TOKEN"
GET/fehler/auslesungen🔒 Login required

Readout operations of the fault memory

Responses
200List (`daten.auslesungen`)
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fehler/auslesungen -H "Authorization: Bearer $TOKEN"

Expenses

Fueling, parking, repair/maintenance, other – record, edit, evaluate

GET/ausgaben🔒 Login required

List expenses (with totals per category)

Parameters
NameLocationTypeDescription
categoryquerystring (tanken, parken, reparatur, sonstiges)
vonquerystring · date
bisquerystring · date
fahrzeugqueryinteger
limitqueryinteger
allequerystring (1)

Administrators only: data of all users

Responses
200`daten.ausgaben[]` (incl. number of receipts), `daten.summen`, `daten.gesamt`
401Not signed in
curl
curl -s 'https://app.fahrten.fusenigk.de/api/v1/ausgaben?kategorie=tanken&von=2026-01-01' -H "Authorization: Bearer $TOKEN" | jq '.daten | {gesamt, summen}'
POST/ausgaben🔒 Login required

Record expense (permission "senden")

Request (application/json) – Schema Ausgabe
{
  "kategorie": "tanken",
  "datum": "2026-11-07T08:15:00Z",
  "betrag": 82.45,
  "fahrzeugId": 4,
  "anbieter": "Aral Unter den Linden",
  "liter": 48.6,
  "preisJeLiter": 1.699,
  "kraftstoff": "Diesel",
  "vollgetankt": true,
  "kmStand": 129980
}
Responses
201created (detail with `belegListe`)
400Invalid input
401Not signed in
403no permission
curl – Record repair
curl -s https://app.fahrten.fusenigk.de/api/v1/ausgaben -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"kategorie":"reparatur","datum":"2026-11-05T09:00:00Z","betrag":489.60,"art":"Inspektion","anbieter":"Mercedes-Benz Niederlassung Berlin","kmStand":129310,"rechnungsNr":"R-2026-48311"}'
curl – Record parking
curl -s https://app.fahrten.fusenigk.de/api/v1/ausgaben -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"kategorie":"parken","datum":"2026-11-06T09:30:00Z","betrag":6.50,"dauerMin":120,"anbieter":"Parkhaus WISTA Adlershof"}'
GET/ausgaben/{id}🔒 Login required

Expense with receipt list

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200Expense
401Not signed in
404Not found (or not visible)
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/ausgaben/$AUSGABE -H "Authorization: Bearer $TOKEN"
PUT/ausgaben/{id}🔒 Login required

Edit expense

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Request (application/json) – Schema Ausgabe
{
  "kategorie": "tanken",
  "datum": "2026-11-07T08:15:00Z",
  "betrag": 82.45,
  "fahrzeugId": 4,
  "anbieter": "Aral Unter den Linden",
  "liter": 48.6,
  "preisJeLiter": 1.699,
  "kraftstoff": "Diesel",
  "vollgetankt": true,
  "kmStand": 129980
}
Responses
200changed
401Not signed in
404Not found (or not visible)
curl
curl -s -X PUT https://app.fahrten.fusenigk.de/api/v1/ausgaben/$AUSGABE -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"kategorie":"tanken","datum":"2026-11-07T08:15:00Z","betrag":82.45,"liter":48.6,"vollgetankt":true}'
DELETE/ausgaben/{id}🔒 Login required

Delete expense including receipts (also files)

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200deleted
401Not signed in
404Not found (or not visible)
curl
curl -s -X DELETE https://app.fahrten.fusenigk.de/api/v1/ausgaben/$AUSGABE -H "Authorization: Bearer $TOKEN"
GET/ausgaben/statistik🔒 Login required

Expenses per month and category, fuel price, consumption from fuel receipts, cost per km, parking locations, repair types

Parameters
NameLocationTypeDescription
vonquerystring · date
bisquerystring · date
fahrzeugqueryinteger
allequerystring (1)

Administrators only: data of all users

Responses
200Statistics
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/ausgaben/statistik -H "Authorization: Bearer $TOKEN" | jq '.daten | {gesamt, kostenJeKm, tanken: .tanken.schnittPreis}'

Receipts & documents

Photos and PDFs for expenses (receipts) and vehicles (vehicle registration, photos, insurance) – own files only

GET/ausgaben/{id}/belege🔒 Login required

Receipts of an expense

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200`daten.belege[]` (file)
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/ausgaben/$AUSGABE/belege -H "Authorization: Bearer $TOKEN" | jq '.daten.belege[] | {dateiname, mime, url}'
POST/ausgaben/{id}/belege🔒 Login required

Upload photos/PDFs for an expense

The file type is detected by content (JPEG, PNG, WebP, HEIC, PDF); SVG/HTML are rejected (415). Identical files (SHA-256) are not stored twice. Storage on the server under uploads/<gruppe>/<untergruppe>/u<benutzer>/<uuid>.

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Request (application/json)
Responses
201`daten.belege[]` stored, `daten.fehler[]` rejected files
400no valid file
401Not signed in
403no permission
404Not found (or not visible)
curl – Upload invoice and photo
curl -s https://app.fahrten.fusenigk.de/api/v1/ausgaben/$AUSGABE/belege -H "Authorization: Bearer $TOKEN" \
  -F datei=@rechnung.pdf -F datei=@foto-quittung.jpg
GET/belege/{id}🔒 Login required

Serve file (own files only)

Serves the file inline (?download=1 as attachment). Foreign IDs result in 404 – even with a manually modified URL.

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
downloadquerystring (1)
Responses
200File
401Not signed in
404Not found (or not visible)
curl
curl -s -OJ 'https://app.fahrten.fusenigk.de/api/v1/belege/$BELEG?download=1' -H "Authorization: Bearer $TOKEN"
DELETE/belege/{id}🔒 Login required

Delete file

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200deleted
401Not signed in
404Not found (or not visible)
curl
curl -s -X DELETE https://app.fahrten.fusenigk.de/api/v1/belege/$BELEG -H "Authorization: Bearer $TOKEN"
GET/fahrzeuge/{id}/dateien🔒 Login required

Vehicle registration, photos and documents of a vehicle

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Responses
200`daten.dateien[]`
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/fahrzeuge/4/dateien -H "Authorization: Bearer $TOKEN"
POST/fahrzeuge/{id}/dateien🔒 Login required

Upload vehicle registration/photo/document

The file type is detected by content (JPEG, PNG, WebP, HEIC, PDF); SVG/HTML are rejected (415). Identical files (SHA-256) are not stored twice. Storage on the server under uploads/<gruppe>/<untergruppe>/u<benutzer>/<uuid>.

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Request (application/json)
Responses
201`daten.dateien[]`, `daten.fehler[]`
401Not signed in
403no permission
404Not found (or not visible)
curl – Upload vehicle registration
curl -s https://app.fahrten.fusenigk.de/api/v1/fahrzeuge/4/dateien -H "Authorization: Bearer $TOKEN" \
  -F dokumentart=fahrzeugschein -F datei=@fahrzeugschein.pdf

Measurements

Snapshots of all live data

GET/messwerte🔒 Login required

Snapshots of live data

Responses
200List (`daten.momentaufnahmen`)
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/messwerte -H "Authorization: Bearer $TOKEN"
GET/messwerte/{id}🔒 Login required

All values and findings of a snapshot

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200Snapshot
404Not found (or not visible)
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/messwerte/$SNAP -H "Authorization: Bearer $TOKEN" | jq '.daten.werte[] | "\(.name): \(.value) \(.unit)"'
GET/messwerte/verlauf🔒 Login required

History of a measured value across all snapshots

Parameters
NameLocationTypeDescription
pidquerystring

OBD PID hexadecimal, e.g. 42 = control unit voltage, 05 = coolant

Responses
200History
401Not signed in
Example response
{
  "ok": true,
  "daten": {
    "pid": "42",
    "verlauf": [
      {
        "zeit": "2026-10-01T08:12:00.000Z",
        "wert": 14.12,
        "einheit": "V"
      }
    ]
  }
}
curl
curl -s 'https://app.fahrten.fusenigk.de/api/v1/messwerte/verlauf?pid=42' -H "Authorization: Bearer $TOKEN"

Statistics

Key figures and chart data

GET/statistik🔒 Login required

Key figures and chart data

Totals, months, logbook by type, weekdays, times, eco score, trip lengths, consumption, faults by system and "Movement & Parking" (driving time, parking time, ratio, parking breaks).

Parameters
NameLocationTypeDescription
vonquerystring · date
bisquerystring · date
fahrzeugqueryinteger
allequerystring (1)

Administrators only: data of all users

Responses
200Statistics
401Not signed in
curl
curl -s 'https://app.fahrten.fusenigk.de/api/v1/statistik?von=2026-01-01' -H "Authorization: Bearer $TOKEN" | jq '.daten | {summe, bewegung: (.bewegung | {anteilFahren, verhaeltnis})}'
GET/karte/heatmap🔒 Login required

Heatmap: dwell density of all trips (grid cells ≈ 110 m, parking locations weighted more heavily)

Parameters
NameLocationTypeDescription
vonquerystring · date
bisquerystring · date
artquerystring (privat, geschaeftlich, arbeitsweg, none)
fahrzeugqueryinteger
allequerystring (1)

Administrators only: data of all users

Responses
200`punkte[[lat, lon, gewicht]]`, `grenzen`, `haeufigsteOrte[]`
401Not signed in
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/karte/heatmap -H "Authorization: Bearer $TOKEN" | jq '.daten | {zellen, haeufigsteOrte}'
GET/karte/tage🔒 Login required

Year map: trips and km per day (like the GitHub activity display)

Parameters
NameLocationTypeDescription
jahrqueryinteger
artquerystring (privat, geschaeftlich, arbeitsweg, none)
fahrzeugqueryinteger
allequerystring (1)

Administrators only: data of all users

Responses
200`tage[]`, `aktiveTage`, `laengsteSerie`, `meisteFahrten`
401Not signed in
curl
curl -s 'https://app.fahrten.fusenigk.de/api/v1/karte/tage?jahr=2026' -H "Authorization: Bearer $TOKEN" | jq '.daten | {aktiveTage, laengsteSerie}'

Export

Logbook as CSV or PDF, all data as JSON, route as GPX

GET/fahrten/{id}/gpx🔒 Login required

Route of a trip as GPX 1.1

Parameters
NameLocationTypeDescription
idpath · requiredstring · uuid
Responses
200GPX file
404Not found (or not visible)
curl
curl -s -OJ https://app.fahrten.fusenigk.de/api/v1/fahrten/$ID/gpx -H "Authorization: Bearer $TOKEN"
GET/export/fahrten.csv🔒 Login required

Logbook as CSV

Semicolon-separated, UTF-8 with BOM (opens directly in Excel/Numbers), with totals per type. Filters like /fahrten.

Parameters
NameLocationTypeDescription
vonquerystring · date
bisquerystring · date
artqueryFahrtArt
fahrzeugqueryinteger
allequerystring (1)

Administrators only: data of all users

Responses
200CSV file
401Not signed in
Example response
Datum;Beginn;Ende;Dauer (min);Start;Ziel;km;Art;Notiz;…
06.11.2026;09:43;10:01;18;Unter den Linden 10, 10117 Berlin;Rudower Chaussee 17, 12489 Berlin;17,4;Geschäftlich;Projektbesprechung;…
curl – Business trips 2026 for tax purposes
curl -s -o fahrtenbuch-2026.csv \
  'https://app.fahrten.fusenigk.de/api/v1/export/fahrten.csv?art=geschaeftlich&von=2026-01-01&bis=2026-12-31' \
  -H "Authorization: Bearer $TOKEN"
GET/export/fahrten.pdf🔒 Login required

Logbook as PDF (A4 landscape)

Print-ready logbook: header with user, period and filter, totals per trip type (private, business, commute, open), table chronologically by months with subtotals, grand total and page numbers. Unicode font (DejaVu Sans), therefore Polish addresses are also correct. Filters like /fahrten.

Parameters
NameLocationTypeDescription
vonquerystring · date
bisquerystring · date
artqueryFahrtArt
fahrzeugqueryinteger
suchequerystring
allequerystring (1)

Administrators only: data of all users

Responses
200PDF file
401Not signed in
curl – Business trips October as PDF
curl -s -o fahrtenbuch-oktober.pdf \
  'https://app.fahrten.fusenigk.de/api/v1/export/fahrten.pdf?art=geschaeftlich&von=2026-10-01&bis=2026-10-31' \
  -H "Authorization: Bearer $TOKEN"
GET/export/daten.json🔒 Login required

All own data as JSON

Vehicles, trips, fault codes, readouts and snapshots. With messpunkte=1 additionally all measurement points of each trip.

Parameters
NameLocationTypeDescription
messpunktequerystring (1)
allequerystring (1)

Administrators only: data of all users

Responses
200JSON file
401Not signed in
Example response
{
  "benutzer": "max.mustermann",
  "format": "obdrest-fahrten-export",
  "version": 1,
  "fahrzeuge": [],
  "fahrten": [],
  "fehler": [],
  "auslesungen": [],
  "momentaufnahmen": []
}
curl
curl -s -o meine-daten.json 'https://app.fahrten.fusenigk.de/api/v1/export/daten.json?messpunkte=1' -H "Authorization: Bearer $TOKEN"

Administration

User management (administrators only)

GET/admin/benutzer🔒 Login required

All users with statistics (admin only)

Responses
200List
403For administrators only
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/admin/benutzer -H "Authorization: Bearer $ADMIN_TOKEN"
POST/admin/benutzer🔒 Login required

Create user (SSO or local)

Request (application/json) – Schema BenutzerEingabe
{
  "username": "kasia",
  "name": "Katarzyna",
  "rolle": "user",
  "darfSenden": true,
  "darfLoeschen": false,
  "aktiv": true,
  "anmeldung": "sso"
}
Responses
201created
409already exists
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/admin/benutzer -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' -d '{"username":"kasia","rolle":"user","anmeldung":"sso"}'
GET/admin/system🔒 Login required

System status (administrators only)

App and MariaDB version, runtime, memory, rows and size per table, receipt storage and demo data inventory.

Responses
200OK
401Not signed in
403administrators only
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/admin/system -H "Authorization: Bearer $TOKEN"
GET/admin/vehicles🔒 Login required

All vehicles with adapter and metrics (administrators only)

Vehicles of all users with log, OBD adapter, number of control units, trips, km, active errors and unknown codes, plus an overview per adapter.

Responses
200OK
401Not signed in
403administrators only
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/admin/fahrzeuge -H "Authorization: Bearer $TOKEN"
GET/admin/activity🔒 Login required

Recent activity (administrators only)

Most recently uploaded trips, error readings, measurements, outputs and unknown codes, trips today/7 days and last synchronization per user.

Parameters
NameLocationTypeDescription
limitqueryinteger
Responses
200OK
401Not signed in
403administrators only
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/admin/aktivitaet -H "Authorization: Bearer $TOKEN"
GET/admin/unknown🔒 Login required

Unknown codes of all users with vehicle cross-reference (administrators only)

Parameters
NameLocationTypeDescription
artquerystring (pid, dtc)
statusquerystring (new, in-analysis, resolved, ignored)
fahrzeugqueryinteger
suchequerystring

code, VIN or vehicle name

Responses
200List (new first) with raw data samples, vehicle (VIN, model, control units, mileage) and user
401Not signed in
403administrators only
curl
curl -s 'https://app.fahrten.fusenigk.de/api/v1/admin/unbekannt?status=neu' -H "Authorization: Bearer $TOKEN"
PUT/admin/unknown/{id}🔒 Login required

Set analysis status and note (administrators only)

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Request (application/json)
{
  "status": "geklaert",
  "notiz": "PID 8B = SCR-Dosierung, A = Bitmaske"
}
Responses
200changed
404Entry not found
403administrators only
curl
curl -s -X PUT https://app.fahrten.fusenigk.de/api/v1/admin/unbekannt/1 -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"status":"in-analyse"}'
DELETE/admin/unknown/{id}🔒 Login required

Delete entry (administrators only)

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Responses
200deleted
404Entry not found
403administrators only
curl
curl -s -X DELETE https://app.fahrten.fusenigk.de/api/v1/admin/unbekannt/1 -H "Authorization: Bearer $TOKEN"
GET/admin/benutzer/{id}🔒 Login required

Read individual user

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Responses
200Users
404Not found (or not visible)
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/admin/benutzer/2 -H "Authorization: Bearer $ADMIN_TOKEN"
PUT/admin/benutzer/{id}🔒 Login required

Change role, permissions, login type, password

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Request (application/json) – Schema BenutzerEingabe
{
  "darfLoeschen": true,
  "aktiv": true
}
Responses
200changed
400Invalid input
curl
curl -s -X PUT https://app.fahrten.fusenigk.de/api/v1/admin/benutzer/2 -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' -d '{"darfLoeschen":true}'
DELETE/admin/benutzer/{id}🔒 Login required

Delete user with all data

Parameters
NameLocationTypeDescription
idpath · requiredinteger
Responses
200deleted
400Main administrator or own account cannot be deleted
curl
curl -s -X DELETE https://app.fahrten.fusenigk.de/api/v1/admin/benutzer/7 -H "Authorization: Bearer $ADMIN_TOKEN"

System

Operating status

GET/health🌐 public

Health check incl. database

Responses
200ok
503Database unreachable
429Too many requests
Example response
{
  "ok": true,
  "daten": {
    "status": "ok",
    "datenbank": "ok",
    "zeit": "2026-11-07T09:00:00.000Z"
  }
}
curl
curl -s https://app.fahrten.fusenigk.de/api/v1/health

🧱 Data models

The upload formats correspond to the Codable types of the iOS app – anyone building their own server must accept exactly these fields.

Trip

Trip in the Codable format of the iOS app

Field (* required)TypeDescription
id *string · uuid
startDate *string · date-time
endDate *string · date-time
samplesarray of TripSample
summaryobject | null

TripSummary of the app, incl. distanceKm, maxSpeed, avgSpeed, fuelLiters, litersPer100km, co2Kg, idleSeconds, events[], eco{score}

startAddressstring | null
endAddressstring | null
kindFahrtArt

Logbook assignment; none = not yet assigned

notestring
detailsstring | null

Multi-line, optional description of the trip

fuelTypestring (diesel, petrol)
vinstring | null
isDemoboolean
TripSample

Measurement point (approx. 1 per second)

Field (* required)TypeDescription
time *string · date-time
speednumber | null

km/h

rpmnumber | null
loadnumber | null

Engine load %

coolantnumber | null

°C

voltagenumber | null

V

ambientnumber | null

Outside temperature °C

pedalnumber | null

Accelerator pedal %

fuelRatenumber | null

l/h

latitudenumber | null
longitudenumber | null
altitudenumber | null

m above sea level

VehicleUpload
Field (* required)TypeDescription
vinstring | null
namestring | null
manufacturerstring | null
seriesstring | null
modelYearinteger | null
fuelTypestring | null
protocolstring | null
adapterstring | null
ecusarray of object
ErrorUpload
Field (* required)TypeDescription
id *string · uuid
vinstring | null
readAt *string · date-time
entriesarray of object
udsECUsarray of string
historyarray of object
Snapshot
Field (* required)TypeDescription
id *string · uuid
vinstring | null
takenAt *string · date-time
voltagenumber | null
protocolstring | null
readings *array of object
findingsarray of object
Trip

Trip in the list view of the web app

Field (* required)TypeDescription
idstring · uuid
benutzerstring
fahrzeugstring | null
startstring · date-time
endstring · date-time
durationSecondsinteger
kmnumber
maxKmhnumber | null
avgKmhnumber | null
litersPer100number | null
ecointeger | null
startAddressstring | null
destinationAddressstring | null
artFahrtArt

Logbook assignment; none = not yet assigned

notizstring | null
beschreibungstring | null

Multi-line description (Trip.details)

User
Field (* required)TypeDescription
idinteger
usernamestring
namestring | null
emailstring | null
rolestring (admin, user)
isAdminboolean
maySubmitboolean
mayDeleteboolean
aktivboolean
loginstring (sso, local)
mayApiboolean

REST API allowed (app login, Bearer, Basic); otherwise browser session only

UserInput
Field (* required)TypeDescription
usernamestring
namestring | null
emailstring | null
rolestring (admin, user)
maySubmitboolean
mayDeleteboolean
aktivboolean
loginstring (sso, local)
passwordstring | null

only for login=local

notizstring | null
mayApiboolean
LoginRequest
Field (* required)TypeDescription
username *string
password *string · password
clientstring (app, web)

app = Bearer token 90 days, web = cookie 12 h

Registration
Field (* required)TypeDescription
username *string
name *string
email *string · email
password *string
clientstring (app, web)