Ownware
Home›Fleetora›API
Fleetora · API

Fleetora API, as shipped in the download

Fleetora REST API, Webhooks & MCP (1.0)

Fleetora ships a JSON REST API, signed webhooks and an MCP endpoint, so the register can answer to whatever else you run — a spreadsheet, a workflow tool, or an assistant.

Everything below reads the same engine the screens read. There is one definition of "overdue" in this product, and no surface computes a second one.

Authentication

Every request carries a bearer key:

Authorization: Bearer ask_xxxx

Mint keys in Settings → API & Webhooks. A key belongs to a user and can do exactly what that user can do in the browser — the same four-rung role ladder applies (viewer · driver · member · admin): adding a vehicle needs fleet.write (member or admin), logging a reading mileage.log and reporting a fault defect.report (driver and up), and a key whose holder lacks the permission is refused with 403 forbidden (from 1.0.3; before, the REST writes checked only the key's scope). Keys are stored as SHA-256 hashes and shown once.

Access: a key is created Read only or Read and write. A read-only key is refused on every non-GET request at the door, before any handler runs, with 403 forbidden. Give the read-only kind to anything that only needs to answer questions.

Endpoints

MethodPathWhat it does
GET/api/pingVerify the key; returns the user and the key's scope
GET/api/vehiclesList vehicles. `?status=active\disposed\all`
POST/api/vehiclesAdd a vehicle. reg required and unique
GET/api/vehicles/{id}One vehicle with its documents, services and open-defect count
GET/api/expiringThe headline. Document expiries and service dues in one ranked list. ?state=…, ?include_disposed=1
POST/api/vehicles/{id}/mileageRecord an odometer reading
POST/api/vehicles/{id}/defectsReport a fault
GET/api/openapi.jsonOpenAPI 3.0 spec (imports as a custom connector)
GET/healthzUnauthenticated liveness probe

The one that matters

curl -s https://fleet.example.com/api/expiring \
  -H "Authorization: Bearer ask_xxxx"
{
  "as_of": "2026-08-22",
  "expiring": [
    { "kind": "document", "id": 12, "vehicle_id": 2, "reg": "FL-2277",
      "item": "Road-use tax or licence", "detail": "RUT-9910-B",
      "state": "expired", "days": -6, "distance": null,
      "due_on": "2026-08-16", "due_by": "date" },
    { "kind": "service", "id": 3, "vehicle_id": 1, "reg": "FL-1042",
      "item": "Full service", "detail": "500 mi to go",
      "state": "soon", "days": 200, "distance": 500,
      "due_on": "2027-01-01", "due_by": "distance" }
  ]
}

state is one of expired · overdue · critical · soon · ok · unknown. unknown is a real answer, not a missing one — see Limits, honestly below.

Units

distance, odometer and every interval are whole numbers in the vehicle's own unit (mi or km, per vehicle). The API never converts between them, because converting would mean picking a unit the operator did not.

Webhooks

POSTed as JSON on each subscribed event, signed:

X-Fleetora-Event: defect.reported
X-Fleetora-Signature: sha256=<hmac_sha256(body, secret)>
EventFires when
vehicle.createda vehicle is added, from any door
vehicle.disposeda vehicle is taken off the road
service.completeda scheduled service is marked done
defect.reporteda fault is reported

One delivery attempt with a 5-second timeout, logged either way. Build idempotent receivers.

Power Automate (and Logic Apps)

Import /api/openapi.json as a custom connector, set the bearer key once, and the endpoints appear as actions. GET /api/expiring is the natural trigger source for "tell the office what is due".

Limits, honestly

  • The API acts at user level; scope is read-only or full, on top of the app's roles.
  • One delivery attempt per webhook event (log + idempotent receivers, not a retry queue).
  • GET /api/vehicles caps at 500 rows. This is a fleet register, not a telematics warehouse.
  • unknown is not an error. A service tracked by distance whose vehicle has no odometer reading on file cannot be given a date without inventing a usage rate. Fleetora returns "state": "unknown" and the honest nulls rather than a plausible guess. Record a reading and the row takes its place in the ranking.
  • Fleetora reads no telematics device and talks to no licensing authority. Every date in it is a date somebody entered.

MCP — the agent endpoint

Fleetora speaks the Model Context Protocol at POST /mcp, so Claude, ChatGPT agents, n8n's AI nodes or your own code can use the register instead of merely reading it. It is the same product underneath: the same bearer key, the same roles, the same engine. An agent cannot do anything its key's user could not do in the browser — and it cannot decide what is overdue; Fleetora's engine does.

Transport is streamable HTTP, stateless: one JSON-RPC 2.0 request in, one JSON response out.

curl -s -X POST https://fleet.example.com/mcp \
  -H "Authorization: Bearer ask_xxxx" -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize",
       "params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-agent","version":"1"}}}'

Then tools/list to discover, tools/call to act:

curl -s -X POST https://fleet.example.com/mcp \
  -H "Authorization: Bearer ask_xxxx" -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"expiring_next","arguments":{"limit":10}}}'

Connect it to an assistant

Mint the key in the app first: Settings → API keys. Choose Read only when the assistant should answer questions but never change anything — the endpoint then lists only the read tools and refuses the rest by name, so a careless prompt cannot write. Full access behaves as before.

Every client needs the same three facts, and nothing in the handshake is vendor-specific:

The addresshttps://fleet.example.com/mcp
The keyheader Authorization: Bearer ask_xxxx
The transportMCP over streamable HTTP, stateless

Claude — one command, or the same URL and header as a custom connector in the desktop and web apps:

claude mcp add --transport http fleetora https://fleet.example.com/mcp \
  --header "Authorization: Bearer ask_xxxx"

ChatGPT and the OpenAI API — one entry in the Responses API's tools array (in ChatGPT itself, the same URL and key go in as a connector):

{
  "type": "mcp",
  "server_label": "fleetora",
  "server_url": "https://fleet.example.com/mcp",
  "authorization": "ask_xxxx",
  "require_approval": "never"
}

Own Your AI reads a list of servers in this shape:

{
  "mcpServers": [
    { "id": "fleetora", "name": "Fleetora", "url": "https://fleet.example.com/mcp",
      "token": "ask_xxxx", "enabled": true }
  ]
}

**Every other client spells the same three facts differently — copy the shape from its own documentation, not from here.** VS Code is the clearest example of why: its configuration reference (read 6 September 2026) puts servers in .vscode/mcp.json under a "servers" object — *"an object that maps server names to their configurations"* — not an mcpServers array. Pasted as-is, the block above will not load there. The id, the URL and the token are what travel; the JSON around them belongs to whichever client you are configuring.

A local model, n8n, or your own code — n8n's MCP Client node takes the URL and the same Authorization: Bearer header; a model running on your own machine reaches it through any MCP client, so nothing leaves your network at all. Writing it yourself is one POST of JSON-RPC 2.0:

curl -X POST https://fleet.example.com/mcp \
  -H "Authorization: Bearer ask_xxxx" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Any client that speaks MCP's streamable-HTTP transport works, including ones that do not exist yet: Fleetora implements the protocol, not an integration with a particular vendor.

Tools

ToolWrites?What it does
expiring_nextnoWhat expires or falls due next across the whole fleet, ranked worst first
list_vehiclesnoVehicles with current odometer and who holds each one
vehicle_recordnoOne vehicle in full: documents, services with due dates and due readings, open defects, recent readings
document_typesnoThe document types this operator tracks — always list these before assuming one exists
log_mileageyesRecord an odometer reading; a reading lower than the last is refused
report_defectyesReport a fault, with severity

There is deliberately no dispose tool, no document-renewal tool and no send-mail tool. Taking a vehicle off the road, renewing compliance paperwork and emailing a driver stay human clicks in the app. An agent can tell you what is about to bite and log what a driver reports — it cannot retire a vehicle or claim a certificate was renewed.

What an agent must not assume

  • Document types are the operator's, not a standard. Vehicle compliance is named differently in every country. Call document_types first; never assume "MOT" or any other regime exists here.
  • Distance is not time. A service due in 500 miles has no date until somebody records a reading. If state is unknown, say so — do not estimate.
  • The register knows only what was entered. There is no telematics feed and no authority lookup behind any of these numbers.

← Back to Fleetora · Manual · Quickstart · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →