Rental endpoints support the customer-facing on-demand rental lifecycle: reservations, active trips, rental operations, end checks, additions, damages, files, feedback, parking reservations, vehicle cards, and driving logs.
| Related reference: User API | User API Guide | Discovery And Vehicle Guide | Payments And Invoices Guide | Error Codes |
Common rental states include:
| State | Meaning |
|---|---|
RESERVATION |
The vehicle is reserved for the user but the trip has not started. |
ACTIVE |
The rental is in progress. The vehicle may be driving or parked depending on rental phases and operations. |
EXPIRED |
A reservation expired before it was started. |
CANCELLED |
A reservation was canceled. |
ENDED |
The rental completed and billing/finalization has run. |
ENDED_NO_MOVEMENT |
The rental started but ended without meaningful movement. |
Use rental operations for state transitions and vehicle actions:
| Operation | Typical use |
|---|---|
START |
Start a reserved rental. |
PARK |
Pause driving while keeping the rental active. |
DRIVE |
Resume driving after parking. |
END |
End the rental and trigger final checks and billing. |
OPEN_TAILBOX |
Open a configured tailbox/helmet box. |
RENEW_RESERVATION |
Extend a reservation where supported. |
The public User API reference exposes POST /rentals/{rentalId}/operation for rental operations.
Rental start can be blocked by missing T&C, verification, payment method, rental authority, branch/category restrictions, minimum age/license rules, balance requirements, or business account constraints.
Rental end can be blocked by parking, station, geofence, vehicle-state, equipment, photo, or surcharge checks. Use POST /rentals/{rentalId}/check/end before ending when the app needs to explain unresolved end-rental requirements.
The normal customer-facing rental flow has four phases:
| Phase | Goal | Main endpoints |
|---|---|---|
| Prepare | Make sure the user can rent this vehicle. | GET /vehicles, GET /vehicles/{id}, GET /termsandconditions, POST /termsandconditions, GET /payment, GET /rentals/requirements |
| Create | Reserve or start the rental. | POST /rentals |
| Operate | Start, park, drive, renew, open tailbox, or cancel. | POST /rentals/{rentalId}/operation, DELETE /rentals/{rentalId} |
| End | Validate parking/end conditions, upload files, end, then show final state. | POST /rentals/{rentalId}/check/end, POST /files, POST /rentals/{rentalId}/operation, GET /rentals/{rentalId} |
When a rental ends, the appliedRebates array on the rental detail response lists every promotion, package, subscription, reward, or voucher that was applied to that trip. Each entry carries the monetary discount it contributed and — for certain types — a nested voucherable object that describes the configured benefit.
Rebate types and voucherable availability:
type |
voucherable present |
Free-minutes benefit |
|---|---|---|
PROMOTION |
Yes (@type: "Promotion") |
Via voucherable.benefits[] — look for type: "FreeMinutes" |
PACKAGE |
Yes (@type: "Package") |
Via voucherable.benefits[] |
SUBSCRIPTION |
Yes (@type: "Subscription") |
Via voucherable.benefits[] |
REWARD |
Yes (@type: "Reward") |
Via voucherable.benefits[] |
RIDE_PASS |
Yes (@type: "RidePass") |
Via voucherable.benefits[] |
VEHICLE_PROMOTION |
No | Only amountNet / amountGross available |
CASHBACK, CUSTOMER_CARE, SINGLE_USE_VOUCHER, SIGNUP_REFERRAL, GEOFENCE_PROMOTION, GEOFENCE_SURCHARGE, FREE_REWARD, EARLY_RETURN_DISCOUNT |
No | Only amountNet / amountGross available |
appliedRebates is only populated for ended rentals. It is empty for rentals in RESERVATION or ACTIVE state.
How to read free-minutes consumption on a rental:
consumed minutes = voucherable.benefits[FreeMinutes].freeMinutesCount
(for the portion actually applied to this rental)
monetary discount = appliedRebates[].amountGross
For types without a voucherable, the monetary discount in amountGross is the only signal available. To derive consumed minutes, divide amountGross by the applicable per-minute rate.
Example — promotion with 10 free minutes, full ride is 10 minutes on a bike (€0.15/min):
GET /rentals/98765
{
"id": 98765,
"state": "ENDED",
"totalDuration": 10,
"sumGross": 0.00,
"currency": "EUR",
"price": {
"priceForDrivingGross": 1.50,
"rebateGross": 1.50,
"finalPriceGross": 0.00
},
"appliedRebates": [
{
"type": "PROMOTION",
"name": "10 Free Minutes",
"amountNet": 1.26,
"amountGross": 1.50,
"voucherable": {
"@type": "Promotion",
"id": 77,
"name": "10 Free Minutes",
"benefits": [
{
"type": "FreeMinutes",
"freeMinutesCount": 10.0
}
]
}
}
]
}
amountGross: 1.50 is the €1.50 that was deducted from the trip cost because of the promotion. freeMinutesCount: 10 tells you the promotion covers 10 minutes — confirming that all 10 minutes of this trip were free.
Example — partial usage: 10 free-minute promotion, only 7 minutes ridden:
"appliedRebates": [
{
"type": "PROMOTION",
"name": "10 Free Minutes",
"amountNet": 0.88,
"amountGross": 1.05,
"voucherable": {
"@type": "Promotion",
"id": 77,
"name": "10 Free Minutes",
"benefits": [
{
"type": "FreeMinutes",
"freeMinutesCount": 10.0
}
]
}
}
]
7 minutes × €0.15/min = €1.05 gross was discounted. The remaining 3 free minutes stay on the promotion for future rentals.
Example — vehicle promotion (no voucherable), 10 free minutes equivalent:
"appliedRebates": [
{
"type": "VEHICLE_PROMOTION",
"name": "Bike Promo",
"amountNet": 1.26,
"amountGross": 1.50,
"voucherable": null
}
]
For VEHICLE_PROMOTION, only the monetary discount is available. Divide amountGross by the per-minute rate to calculate consumed minutes programmatically.
Migration note for v1 integrations: The v1 field bonusMetersUsed from GET /pricing/reservations/{reservationID} has no direct equivalent in v2. Use appliedRebates[].amountGross for the monetary value consumed, and appliedRebates[].voucherable.benefits[type=FreeMinutes].freeMinutesCount for the configured free-minute count when available.
| Task | Endpoint |
|---|---|
| List current user’s rentals | GET /rentals |
| Get rental detail | GET /rentals/{rentalId} |
| List group rentals | GET /rentals/user-group/{userGroupId} |
Use rental detail after any operation to display the current state, price, vehicle, invoice, and next available actions.
Use trip overview screens to help users understand the current trip, review past trips, and continue into receipt, invoice, feedback, damage, or support actions. In the app, this usually means two UI levels:
GET /rentals;GET /rentals/{rentalId}.GET /rentals is optimized for overview lists. It returns enough information for cards such as “Trip on 21 May”, “ended in Praterstrasse”, “12 min”, “€4.20”, and “Toyota Yaris / Scooter 123”. Use it for history, active-rental banners, and quick account views. The endpoint is paginated and defaults to newest rentals first.
For a compact in-app card, show only the information a user can scan quickly: state, vehicle, date/time, start/end address, duration or distance, final or estimated price, and a small follow-up indicator for invoice or feedback where relevant. Keep billing details, route map, photos, rebates, and support actions for the trip detail screen.
Recommended list-card fields:
| UI element | Rental fields |
|---|---|
| Status badge | state, phaseState where available, rideMode |
| Vehicle label | vehicle.name, vehicle.code, vehicle.licensePlate, vehicle.categoryId |
| Start/end time | startTime, driveStartTime, endTime |
| Start/end place | startAddress, endAddress, startPosition, endPosition |
| Duration and distance | totalDuration, distance |
| Price preview/final price | estimatedPrice, price, priceV3, priceV4, priceGross, sumGross, currency |
| Benefit indicators | appliedRebates, pricingOption |
| Business context | type, reason, group, userGroup, balanceName |
| Follow-up actions | feedback, invoiceId, bookingId, activeDeposit |
Use GET /rentals/{rentalId} when the user opens a specific trip. The detail response contains richer context and is the better source for a receipt-like screen:
| Detail section | Rental fields |
|---|---|
| Trip route | encodedPolylineOfRoute, imageOfRouteUrl, startPosition, endPosition |
| Vehicle | vehicle, startSoc, endSoc, startKilometers, endKilometers |
| Time and distance | startTime, driveStartTime, endTime, totalDuration, distance |
| Price breakdown | priceV4, priceV3, price, estimatedPrice, currency, appliedRebates |
| Invoice and payment | invoiceId, invoice, deposit |
| Add-ons and pricing | additions, pricingOption, pricingBundleVersion |
| Photos and reports | fileIds, station, parking details where present |
| Feedback | feedback.rating, feedback.ratingDescription |
For active rentals, show estimatedPrice as an estimate and keep refreshing the rental at a responsible interval. For ended rentals, show final price fields and invoice data when available. If invoiceId is present but the full invoice object is not enough for the UI, link to the invoice flow from the Payments And Invoices Guide.
The trip overview should not infer final billing from only the list row. Open the detail view and re-fetch GET /rentals/{rentalId} when the user wants receipt, invoice, feedback, damage, parking-photo, or support actions.
Use POST /rentals.
Common request context:
| Field/context | Purpose |
|---|---|
vehicleId or vehicleCode |
Vehicle selected from the map or scan flow. |
startRentalState |
RESERVATION or ACTIVE, depending on whether the user reserves or starts immediately. |
userGroupCode / type: "BUSINESS" |
Business account billing where configured. |
additions |
Optional paid or configured additions selected before start. |
| Pricing option | Selected on-demand pricing option where the branch/category supports choices. |
Before creating the rental, make sure the user has accepted required T&C and has fulfilled start rental requirements.
The rental start screen should let the user choose how this trip will be paid before calling POST /rentals.
For a personal rental, load the user’s active payment sources with GET /payment?state=ACTIVE&branchId={branchId} and show the current default source. If the user selects a different card, wallet, or PayPal source, call PUT /payment with the selected sourceId, then re-fetch GET /payment and start the rental without userGroupCode. The rental creation request does not accept a payment-source ID; personal rentals use the user’s current eligible default payment source.
For a business-account rental, load the user’s memberships with GET /groups and show the eligible group as a separate billing option. When the user selects that option, pass the group’s userGroupCode in POST /rentals and set type: "BUSINESS" when the app sends an explicit rental type. The rental is then billed through the configured business account instead of the user’s personal default payment source.
Re-run rental requirements whenever the user changes between personal payment and a business account. Use GET /rentals/requirements with the selected branch/category/vehicle context and include userGroupCode or userGroupId for business rentals. This lets the app explain account-specific blockers such as missing payment setup, missing driving license, unaccepted terms, unpaid invoices, missing business-account approval, or required business context before the user taps start.
If the user adds a new payment method from the start screen, complete the add-payment flow, re-fetch GET /payment, optionally make the new source the default with PUT /payment, and then continue with the rental start. If the user switches to a business account, do not try to pass the personal payment source to POST /rentals; use userGroupCode to select the business billing context.
Rental add-ons are optional extras attached to a rental. They can be physical extras, such as a helmet or child seat, or digital products, such as an additional insurance package that reduces the user’s deductible or adds another rental-specific charge.
Load available add-ons with GET /rentals/additions. Filter the request by the selected vehicleCategoryId and branchId; include userGroupCode when the user selected a business account. For booking-like flows or scheduled pickup windows, also pass bookingStartTime and bookingEndTime so the returned additions match the intended rental window.
Each returned RentalAddition contains:
| Field | How to use it |
|---|---|
code |
Stable value to pass in additions when creating or updating the rental. |
name / description |
Localized user-facing copy for the start screen. |
isInternal |
Do not display internal additions as selectable user options. |
entitled |
Indicates that the current user is entitled to this addition, for example through a voucher, benefit, subscription, or group setup. |
pricingInformation |
Price context to show next to the add-on before the user starts. |
The app can let the user select multiple add-ons. Keep the selected add-on codes as an array and pass them in POST /rentals:
{
"vehicleId": 12345,
"startRentalState": "ACTIVE",
"additions": ["INSURANCE", "HELMET"]
}
If the rental is still in RESERVATION and has not entered ACTIVE, the app can update the selected add-ons with PATCH /rentals/{rentalId} and the new additions array. Once the rental is active, treat add-ons as locked unless the API explicitly allows the update for that tenant and rental type.
Show add-ons as part of the final start confirmation, together with vehicle, payment/business billing context, vouchers, rental requirements, and estimated price. For priced add-ons, include them in the estimate by calling GET /pricing-bundles/pricing-calculator with the same branchId, vehicleCategoryId or pricing bundle context, time window, business context, and selected additions codes. The price response can include additionsPriceGross, which lets the app show the add-on cost separately from driving, parking, unlock, distance, or reservation charges.
For an insurance-style add-on, do not hard-code the legal or deductible text in the app. Display the localized name, description, and price returned by the API/configuration, and make the selected code part of the rental creation request. If the add-on is included because the user has an entitlement, show it as included or discounted according to the returned addition and pricing/voucher information instead of charging it again in the UI.
When an add-on cannot be used, surface the API error as a recoverable start-screen state. Common examples are RA100 when an addition code is unknown and R245 when additions are not supported for the chosen rental type.
Recommended pre-rental sequence:
GET /vehicles.GET /vehicles/{id} or GET /vehicles/code/{code} for scan flows.GET /vehicles/categories/{id}, GET /rentals/additions, and GET /on-demand-pricing-options where relevant.GET /payment and business memberships with GET /groups when the app supports business rentals.GET /termsandconditions or branch-specific acceptance state. If needed, accept with POST /termsandconditions.userGroupCode, reason, and cost-center context where configured.POST /rentals with vehicleId or vehicleCode, startRentalState, selected additions, optional paid reservation minutes, optional group context, and optional pricing option.rentalId and immediately render the returned rental state.| Task | Endpoint |
|---|---|
| Perform rental operation | POST /rentals/{rentalId}/operation |
| Cancel a reservation | DELETE /rentals/{rentalId} |
| Buy reservation minutes | POST /rentals/{rentalId}/buy-reservation |
| Execute pre-end actions | POST /rentals/{rentalId}/execute-pre-end-actions |
| Check end-rental requirements and surcharges | POST /rentals/{rentalId}/check/end |
| Reserve parking station | PUT /rentals/{rentalId}/parking-reservation |
If a rental operation returns a concurrent-processing conflict, wait and re-fetch the rental before retrying. End-rental operations can involve vehicle commands, requirement evaluation, pricing, payment capture, invoices, and events.
Users can purchase additional reservation time while a rental is still in RESERVATION. This lets an app sell predefined extension options such as “add 5 minutes”, “add 10 minutes”, or “add 15 minutes” before the user starts the vehicle.
Call POST /rentals/{rentalId}/buy-reservation?minutes={minutes} with the selected number of minutes. The API returns the updated rental. The backend verifies that the rental still belongs to the user and is still reserved, extends the rental endTime, creates a paid reservation phase, and then opens a new free reservation phase after the paid block.
Recommended app flow:
endTime.POST /rentals/{rentalId}/buy-reservation?minutes={minutes}.endTime.RESERVATION, re-fetch GET /rentals/{rentalId} and switch the UI to the current state.The API accepts the number of minutes, not a package ID. If the operator wants to sell fixed reservation-time packages, model those as app choices backed by the configured reservation pricing. For example, the app can show three buttons for 5, 10, and 15 minutes, call the same endpoint with the selected value, and display the price calculated from the active pricing configuration.
For pricing previews, use the pricing calculator or simulator with the same branch, vehicle category or pricing bundle context, and a reservation-only time window. In the resulting rental or price breakdown, reservation charges appear as reservation pricing, paid reservation phases, or priceForReservationGross/reservation-related fields depending on the price response version.
This feature is configured on the operator side:
| Configuration area | Operations API guide |
|---|---|
| Free reservation window, max free reservation minutes, reset buffer, same-vehicle block | Operations API Guide - Settings and Operations API Rental Guide |
| Paid reservation pricing in on-demand pricing bundles | Operations API Pricing Guide |
| Branch/category assignment of the relevant on-demand pricing option | Operations API Pricing Guide |
For an active rental screen:
GET /rentals/{rentalId}.START to start a reserved rental.PARK and DRIVE for pause/resume flows where supported.OPEN_TAILBOX only if the vehicle supports it.RENEW_RESERVATION only for reservations where extension is allowed.For the end-rental flow:
POST /rentals/{rentalId}/check/end to surface blockers, required photos, parking restrictions, or surcharges before submitting the final end operation.POST /files.POST /rentals/{rentalId}/operation with operationType: "END", plus fileId, parkingReport, vehicleCode, reason, or communicationChannel where relevant.GET /rentals/{rentalId} if the UI needs invoice/payment finalization details.| Task | Endpoint |
|---|---|
| Update rental metadata or feedback | PATCH /rentals/{rentalId} |
| Submit feedback | POST /rentals/{rentalId}/feedback |
| Link condition files during rental | POST /rentals/{rentalId}/files |
| Upload file | POST /files |
| Get file download information | GET /files/{fileId} |
Use file uploads for rental photos, vehicle-condition images, damage images, parking photos, or other tenant-configured attachment workflows.
Images are uploaded first, then linked to the relevant object.
Use POST /files to upload the image as multipart form data. The response contains the file id.
Example upload:
POST /files?public=false&mediaType=image/jpeg&fileName=parking-photo.jpg
Content-Type: multipart/form-data
multipart=<binary image data>
Use public=false for normal user-uploaded rental photos unless the tenant explicitly wants public file access. After upload, use the returned file ID in one of these flows:
| Use case | Link/upload flow |
|---|---|
| Vehicle condition image before starting or during a rental | POST /rentals/{rentalId}/files with an array of file IDs. |
| Damage report image | Include uploaded file objects in POST /vehicles/{id}/damages. |
| Parking/end-rental photo while ending | Pass fileId in POST /rentals/{rentalId}/operation with operationType: "END". |
| Additional image after the rental is already ended | PATCH /rentals/{rentalId} with fileIds. |
For vehicle condition images, link the uploaded files to the rental while it is still in RESERVATION or ACTIVE:
POST /rentals/12345/files
Content-Type: application/json
[98765, 98766]
Use this for pre-trip inspection photos, during-rental vehicle condition photos, or other rental-context images that should be stored with the rental but are not a structured damage report.
After the trip is finished, show the feedback screen and submit the user’s rating with POST /rentals/{rentalId}/feedback.
Use this flow:
POST /rentals/{rentalId}/operation using operationType: "END".ENDED, ENDED_NO_MOVEMENT, or CANCELLED.POST /rentals/{rentalId}/feedback.Example request:
POST /rentals/12345/feedback
Content-Type: application/json
{
"rating": 5,
"ratingDescription": "Vehicle was clean and easy to unlock."
}
rating is the numeric trip rating, usually rendered as a 1-to-5 star control. ratingDescription is the free-text comment from the feedback screen. The comment can be empty or omitted if the user only wants to rate the trip.
The API returns 201 Created with the updated rental. The returned rental includes feedback.rating and feedback.ratingDescription, so the app can show the submitted rating on the receipt or trip-detail screen.
Feedback is owner-only and one-time. If another user submits feedback, the API returns an authorization error. If the rental is still active or already has feedback, the API returns a conflict. In those cases, re-fetch GET /rentals/{rentalId} and update the UI rather than retrying blindly.
| Task | Endpoint |
|---|---|
| List rental damages | GET /rentals/{rentalId}/damages |
| List vehicle damages | GET /vehicles/{id}/damages |
| Submit vehicle damage | POST /vehicles/{id}/damages |
| List vehicle cards/details for active rentals | GET /vehicle-cards |
Damage submission can be part of pre-rental inspection, active-rental inspection, post-rental feedback, or support flows. Re-fetch the rental or vehicle after submission if the UI depends on updated status.
Use this decision rule:
| User action | Recommended API |
|---|---|
| “I want to document the vehicle condition with photos.” | Upload images with POST /files, then link them to the rental with POST /rentals/{rentalId}/files while the rental is active/reserved. |
| “I found a new scratch, broken part, or other damage.” | Submit a structured damage report with POST /vehicles/{id}/damages. |
| “I need to prove where/how I parked at the end.” | Upload the image with POST /files, then pass the file ID in the end-rental operation. |
To report a damage:
POST /files.POST /vehicles/{id}/damages.branchId, part, optional description, optional severity, optional vehiclePosition and userPosition, and optional currentRentalId.GET /vehicles/{id}/damages or GET /rentals/{rentalId}/damages if the UI needs to show the updated list.Example:
POST /vehicles/345/damages
Content-Type: application/json
{
"branchId": 3,
"part": "front_bumper",
"description": "Scratch on the front bumper before trip start.",
"severity": "MINOR",
"currentRentalId": 12345,
"files": [
{
"id": 98765
}
]
}
Use currentRentalId when the damage is being reported in the context of a specific rental. For pre-trip reporting, this is normally the just-created reservation or active rental. For post-trip reporting, use the rental that just ended if the app still has that context.
Existing damage lists are available through:
GET /vehicles/{id}/damages for all reported damages visible on a vehicle.GET /rentals/{rentalId}/damages for damages associated with the rental’s vehicle, including file download details for approved, ignored, or under-repair damages.If the product requires a parking photo or the user wants to document the final parking state, upload the photo before ending the rental and pass the returned file ID in the end operation.
Example:
POST /files?public=false&mediaType=image/jpeg&fileName=end-parking.jpg
Content-Type: multipart/form-data
multipart=<binary image data>
Then end the rental:
POST /rentals/12345/operation
Content-Type: application/json
{
"operationType": "END",
"fileId": 98765,
"parkingReport": {
"description": "Parked in bay 14 near the north entrance."
}
}
If the rental is already ended and the app needs to attach an additional image later, use PATCH /rentals/{rentalId} with fileIds:
PATCH /rentals/12345
Content-Type: application/json
{
"fileIds": [98765]
}
Do not use damage reporting for generic parking proof. Use damage reporting only when the user is reporting a concrete vehicle damage.
Driving-log endpoints support branches or vehicle categories where users must record trip log details.
| Task | Endpoint |
|---|---|
| Get rental driving log | GET /rentals/{rentalId}/driving-log |
| Submit driving log | POST /rentals/{rentalId}/driving-log/submit |
| Validate driving log | GET /rentals/{rentalId}/driving-log/validation |
| List driving-log entries | GET /rentals/{rentalId}/driving-log/entries |
| Create driving-log entries | POST /rentals/{rentalId}/driving-log/entries |
| Get one driving-log entry | GET /rentals/{rentalId}/driving-log/entries/{drivingLogEntryId} |
| Update one driving-log entry | PUT /rentals/{rentalId}/driving-log/entries/{drivingLogEntryId} |
| Delete one driving-log entry | DELETE /rentals/{rentalId}/driving-log/entries/{drivingLogEntryId} |
| Area | Endpoints |
|---|---|
| Rentals | GET /rentals, POST /rentals, GET /rentals/{rentalId}, PATCH /rentals/{rentalId}, DELETE /rentals/{rentalId} |
| Operations and checks | POST /rentals/{rentalId}/operation, POST /rentals/{rentalId}/buy-reservation, POST /rentals/{rentalId}/execute-pre-end-actions, POST /rentals/{rentalId}/check/end, PUT /rentals/{rentalId}/parking-reservation |
| Requirements and additions | GET /rentals/requirements, GET /rentals/additions |
| Damage and files | GET /rentals/{rentalId}/damages, GET /vehicles/{id}/damages, POST /vehicles/{id}/damages, POST /rentals/{rentalId}/files, POST /files, GET /files/{fileId} |
| Feedback and vehicle cards | POST /rentals/{rentalId}/feedback, GET /vehicle-cards |
| Driving log | GET /rentals/{rentalId}/driving-log, POST /rentals/{rentalId}/driving-log/submit, GET /rentals/{rentalId}/driving-log/validation, GET/POST /rentals/{rentalId}/driving-log/entries, GET/PUT/DELETE /rentals/{rentalId}/driving-log/entries/{drivingLogEntryId} |