Skip to main content
API

Exporting reservations via the REST API

How to authenticate against the ZEMTU REST API and export reservation data — including filtering, pagination, and a ready-to-use export script.

Written By Zemtu

Last updated About 3 hours ago

Introduction

This article is aimed at developers who want to make use of the ZEMTU REST API. It explains authentication, pagination, filtering, and ordering — using the export of reservation data as a complete, working example. The same pattern applies to all other endpoints (vehicles, users, invoices, etc.).

General info

  • Base URL: We use https://carsharing.zemtu.com in this documentation. Always replace carsharing with your subdomain: https://YOUR_ORGANIZATION.zemtu.com

  • Serialization format: JSON is used for data exchange.

  • Versioning: /api/v2/ — new API versions are offered under a distinct version number to allow backward-incompatible API evolution.

  • Methods: HTTP GET is used for fetching data, POST for creating, PUT/PATCH for updating and DELETE for deleting data.

  • Documentation: The auto-generated, interactive API documentation with all available endpoints, fields, and filters can be accessed at https://YOUR_ORGANIZATION.zemtu.com/docs

Authentication

TokenAuthentication: for clients to authenticate, the token key should be included in the Authorization HTTP header. The key should be prefixed by the string literal Token, with whitespace separating the two strings:

Authorization: Token 9944b19199c62bgf9418td846dd0e4bzdfc6de9b

There are several possibilities to obtain the token:

  • Read token from admin interface (only for users with org admin role): https://YOUR_ORGANIZATION.zemtu.com/admin/authtoken/token/

  • Get direct access to the token, e.g. via secure email from your organization administrator.

  • Obtain the token with username & password by posting the credentials to /api-token-auth/:

curl --data "username=USERNAME&password=PASSWORD" https://YOUR_ORGANIZATION.zemtu.com/api-token-auth/

The JSON response looks like {"token": "9844b19129c62bhf9418td746cd0e4bzdfc6de9b"} — the token is then used for all API communication.

Setup recommendation

Best practice is to create a dedicated machine user at https://YOUR_ORGANIZATION.zemtu.com/admin/main/customuser/ and get a token for it via https://YOUR_ORGANIZATION.zemtu.com/admin/authtoken/token/?user=PRIMARY_KEY_OF_THE_USER.

The rule of thumb for permissions: the API user sees the same objects via the API as in the backend administration. To export all reservations of an organization, the machine user needs to be assigned to the organization with a suitable role, e.g. "Accountant" or "OrgAdmin".

Pagination

All list endpoints return a paginated envelope:

{"count": 1234, "next": "https://...&page=2", "previous": null, "results": [ ... ]}
  • /api/v2/reservation/ — default page size: 100, maximum: 500

  • /api/v2/reservationaccounting/ and /api/v2/reservationreporting/ — default page size: 50, maximum: 250

  • A custom page size can be set with ?page_size=250; a specific page with &page=2. The simplest export strategy is to follow the next URL until it is null.

Endpoints for exporting reservations

Endpoint

Description

Access

/api/v2/reservation/

Complete reservation objects as shown in the UI. Returns reservations the user is allowed to view.

Read & Write

/api/v2/reservationaccounting/

Reservation data for accounting: real start/end, booked end, distance, odometer, version history, fees. Best suited for exports for billing and statistics.

Read-only

/api/v2/reservationreporting/

The user's own reservations including a trip report (distance, overdrawn time, trip segments).

Read-only

/api/v2/vehicle/

Vehicle master data (id, type, location).

Read-only

/api/v2/user/

User data. Users with the "User" role can only retrieve themselves; org admins can retrieve all users of the organization.

Read-only

Hint: the trailing / is important for detail endpoints, e.g. /api/v2/reservation/{ID}/.

Filtering

The reservation and reservation accounting endpoints support these filters:

Filter

Description

created__gte, created__lte

Creation date range of the reservation

modified__gte, modified__lte

Last change to the reservation (also considers workflow transitions triggered by the OBU)

reservation_start__gte/__gt/__lte/__lt

Reservation start range

reservation_end__gte/__gt/__lte/__lt

Reservation end range

state

Exact workflow state: opened, protected, closed, deleted

state__in

Several states, e.g. state__in=closed,deleted

vehicle

Vehicle id

vehicle__in

Several vehicle ids, e.g. vehicle__in=201,202

owner

User id of the reservation owner

Hint: gte stands for "greater than or equal to", lte for "less than or equal to". Datetimes are given in ISO 8601 format, e.g. 2026-01-01T00:00:00Z.

/api/v2/reservationreporting/ additionally offers start__gte/__lte (reservation start) and billed_end__gte/__lte (the end relevant for billing).

Filtering examples

  • All reservations starting in January 2026: https://YOUR_ORGANIZATION.zemtu.com/api/v2/reservationaccounting/?reservation_start__gte=2026-01-01T00:00:00Z&reservation_start__lt=2026-02-01T00:00:00Z

  • Closed or deleted reservations: ?state__in=closed,deleted

  • Reservations of vehicle 201: ?vehicle=201

  • Reservations owned by user 1550: ?owner=1550

  • Reservations changed since the last export run: ?modified__gte=2026-10-01T00:00:00Z

Ordering

Results can be sorted with the ordering parameter, e.g. ?ordering=-reservation_start for descending order by reservation start. Available ordering fields are created, reservation_start, reservation_end, and vehicle (reservation API); reservation_start (accounting and reporting APIs).

Result structure (reservation accounting)

Field

Type

Description

id

integer

Unique identifier of the reservation

created, modified

datetime

Creation / last change of the reservation

reservation_start, reservation_end

datetime

Start/end displayed in the UI (snapped to the booking slot)

start_booked, end_booked

datetime

Booked start/end relevant for billing

start_real, end_real

datetime

Real start (e.g. early access) / actual return time

start_first_tripsegment, end_last_tripsegment

datetime

Start of first / end of last recorded trip segment

purpose

integer

0 personal, 10 business

note, note_billing

text

Reservation note / billing note

lift_offer

boolean

Offering a lift?

state

text

Workflow state (see below)

owner

object

id, external_user_id, additional_data of the reservation owner

vehicle

object

id, type, label, brand, model, address1, city, zip, timezone

distance

float

Distance driven in km

odometer_start, odometer_end

float

Odometer readings at start/end

fees_data

object

Calculated fee data for the reservation

tags

list

Tags assigned to the reservation

versions

list

All versions of the reservation in descending order, including the current version — the complete history (fields: lift_offer, modified, note, reservation_start, reservation_end, purpose, state)

Example result

"note": "",
"reservation_start": "2014-09-04T05:30:00Z",
"start_real": null,
"reservation_end": "2014-09-05T12:30:00Z",
"end_real": null,
"note_billing": null,
"purpose": 0,
"owner": {
    "id": 2275,
    "external_user_id": ""
},
"vehicle": {
    "id": 201,
    "type": "ZEMTU Renault Twizy",
    "address1": "Färbergasse 17b",
    "city": "Dornbirn",
    "zip": "6850"
},
"created": "2014-09-02T18:02:48.740223Z",
"modified": "2014-09-02T18:03:00.274824Z",
"distance": null,
"lift_offer": false,
"state": "deleted",
"versions": [
    {
        "lift_offer": false,
        "state": "deleted",
        "modified": "2014-09-02T18:03:00.274Z",
        "note": "",
        "reservation_start": "2014-09-04T05:30:00Z",
        "purpose": 0,
        "reservation_end": "2014-09-05T12:30:00Z"
    },
    {
        "lift_offer": false,
        "state": "opened",
        "modified": "2014-09-02T18:02:56.804Z",
        "note": "",
        "reservation_start": "2014-09-04T05:30:00Z",
        "purpose": 0,
        "reservation_end": "2014-09-05T12:30:00Z"
    },
    {
        "lift_offer": false,
        "state": "opened",
        "modified": "2014-09-02T18:02:48.740Z",
        "note": "",
        "reservation_start": "2014-09-04T05:30:00Z",
        "purpose": 0,
        "reservation_end": "2014-09-05T09:30:00Z"
    }
],
"odometer_start": null,
"odometer_end": null

Example: exporting reservations

cURL

curl -H "Authorization: Token XXXX" \  "https://YOUR_ORGANIZATION.zemtu.com/api/v2/reservationaccounting/?format=json&page_size=250"

Python 3 — export all reservations of a month to CSV

#!/usr/bin/env python3
import os
import sys
import urllib.request
import urllib.error


# Use the provided demo token; in real use, prefer: TOKEN = os.environ.get("DRF_TOKEN")
TOKEN = "XXXX"


def main():
   url = "https://carsharing.zemtu.com/api/v2/reservationaccounting/?format=json"
   # url = "https://carsharing.zemtu.com/api/billing/v2/invoice/?format=json"
   data = None
   method = "GET"


   headers = {
       "Authorization": f"Token {TOKEN}",
       "Accept": "application/json",
   }
   if data:
       headers["Content-Type"] = "application/json"


   req = urllib.request.Request(url, data=data, method=method, headers=headers)


   try:
       with urllib.request.urlopen(req) as resp:
           body = resp.read().decode("utf-8", errors="replace")
           print(body)
           sys.exit(0)
   except urllib.error.HTTPError as e:
       err = e.read().decode("utf-8", errors="replace")
       print(f"HTTP {e.code}: {err}", file=sys.stderr)
       sys.exit(e.code)
   except urllib.error.URLError as e:
       print(f"Request error: {e}", file=sys.stderr)
       sys.exit(1)


if __name__ == "__main__":
   main()

Usage hints

  • The field reservation_end is the end displayed in the user interface only. The fields end_booked and end_real are the ones to consider for clearing.

  • When end_real > end_booked the reservation was overdrawn — extra fees might apply.

  • The field versions contains the whole history of a reservation. Loop over it to detect whether it was deleted or changed in a time span where extra fees might apply.

  • Deleted reservations stay in the result set — use state=deleted or state__in=... to handle them explicitly.

  • For recurring exports, filter on modified__gte with the timestamp of the last run instead of re-fetching everything.

Reservation states

State

Description

opened

Initial state when a new reservation is created. It is allowed to modify and delete the reservation. Allowed transitions: → protected, → deleted

protected

Reservation has been started — triggered when the OBU confirmed the start. No more changes to the reservation start allowed. Allowed transitions: → closed

closed

Reservation has ended — triggered when the OBU sends the final trip data. No more changes to start and end allowed.

deleted

Reservation has been deleted.

Further reading

Was this helpful?

Still need help? Share an idea