πŸš— Rental

Car rental management with bookings, returns, insurance, invoicing, and add-ons.

Overview

The Rental API simulates a car rental service with a full lifecycle: browse the fleet, make bookings, get approved, return cars, and pay invoices. It includes manager-only operations (approve, return, fleet management), insurance options, optional add-ons, and a payment method vault.

Base Path
/api/rental
Auth Header
x-api-key: <your-key>
App URL
/rental.html
Swagger
/rental/docs
Monetary values are stored in cents. The API also returns a formatted string for display. 15000 = $150.00.

Quick Start

Step 1
Browse Fleet
GET /cars with date filter
β†’
Step 2
Book Car
POST /bookings with car_id and dates
β†’
Step 3
Approve
PATCH /bookings/:id/approve (Manager)
β†’
Step 4
Return Car
POST /bookings/:id/return (Manager)
β†’
Step 5
Pay Invoice
PATCH /invoices/:id/pay
curl "https://qacloud.dev/api/rental/cars?start_date=2026-05-01&end_date=2026-05-05" \
  -H "x-api-key: YOUR_KEY"
curl -X POST https://qacloud.dev/api/rental/bookings \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "car_id": "CAR_UUID",
    "start_date": "2026-05-01",
    "end_date": "2026-05-05",
    "insurance_type": "BASIC"
  }'

Car & Booking Statuses

Car Statuses

AVAILABLE
Ready to be booked.
RENTED
Set automatically on booking approval. Cannot be manually set.
RETURNED
After a return is processed.
DAMAGED
Flagged by manager after inspection.
IN_SHOP
Undergoing maintenance.
State machine guard: A car with status RENTED cannot have its status changed manually β€” a return must be processed first. Returns 409.

Booking Statuses

PENDING
Created, awaiting manager approval.
APPROVED
Approved by manager; car set to RENTED.
ACTIVE
Car is out with the customer.
CANCELLED
Cancelled by customer or manager.
COMPLETED
Return processed. Invoice generated.

Insurance Options

BASIC
$15.00 / day
Basic liability coverage.
FULL
$35.00 / day
Comprehensive coverage including damage.
OWN
$0.00 / day
Customer provides own insurance.

Fleet Management

Each API key manages its own fleet. A car record contains: make, model, year, daily_rate (cents), status, image_url, and deletion state.

Soft delete (DELETE /cars/:id) sets a deleted_at timestamp rather than physically removing the record. Use ?show_deleted=true on GET /cars to see deleted cars.

Date Availability Filter

Pass ?start_date= and ?end_date= to GET /cars to receive only cars that are AVAILABLE and have no conflicting PENDING/APPROVED/ACTIVE bookings during that period.

Booking Lifecycle

Rental day calculation is inclusive on both ends: a booking from May 1 to May 5 is 4 days. The total cost = daily_rate Γ— days + insurance_rate Γ— days + add-on costs.

Availability Conflict Detection

Creating a booking checks for overlapping PENDING/APPROVED/ACTIVE bookings. A conflict returns 409 Conflict.

Manager Operations

Invoices

An invoice is automatically generated when a return is processed. It includes rental cost, insurance cost, add-on costs, and any damage fees. Invoices start as UNPAID.

Use PATCH /invoices/:id/pay to mark an invoice as paid. Payment is linked to the user's default payment method if one is set.

Payment Methods

Users can store multiple payment methods (e.g. credit cards). One card can be set as default. The default is used automatically when paying an invoice.

Payment method data is stored as-is β€” no Luhn validation or live charging. Useful for testing form handling and payment flows in isolation.

Add-ons

Add-ons are optional extras (GPS, child seat, roadside assistance, etc.) that can be added to a booking at creation time via addon_ids. Each add-on has a flat rate in cents.

Managers create and update add-ons via POST/PUT /addons. Regular users can only list available add-ons.

Cars API

GET /api/rental/cars List fleet; optionally filter by date availability
Query ParamDescription
start_dateISO date β€” with end_date, filters to available cars only
end_dateISO date β€” must be after start_date
statusAVAILABLE | RENTED | RETURNED | DAMAGED | IN_SHOP
show_deletedtrue to include soft-deleted cars
image_urltrue to filter cars with images; false to strip image_url from response
POST /api/rental/cars Add a car to your fleet
FieldRequiredDescription
makerequirede.g. Toyota
modelrequirede.g. Camry
yearrequiredInteger year
daily_raterequiredInteger in cents (e.g. 8500 = $85/day)
image_urloptionalURL to car photo
GET /api/rental/cars/:id Get a single car by ID

Returns the full car record including current status.

PUT /api/rental/cars/:id Update car details

Update make, model, year, daily_rate, or image_url. Cannot change status via this endpoint β€” use /status instead.

PUT /api/rental/cars/:id/status Update car operational status (Manager)
FieldRequiredDescription
statusrequiredAVAILABLE | RETURNED | DAMAGED | IN_SHOP (RENTED is auto-set via booking approval)

Returns 409 if car is currently RENTED β€” process a return first.

DELETE /api/rental/cars/:id Soft-delete a car

Sets deleted_at on the car. The car no longer appears in availability results but booking history is preserved.

Bookings API

GET /api/rental/bookings List your own bookings

Returns all bookings created by the current API key user.

GET /api/rental/bookings/all List all bookings (Manager)

Returns all bookings across all users in the system. Manager-level endpoint.

POST /api/rental/bookings Create a new booking
FieldRequiredDescription
car_idrequiredUUID of the car to book
start_daterequiredISO date string
end_daterequiredISO date string, must be after start_date
insurance_typeoptionalBASIC | FULL | OWN. Default: OWN
addon_idsoptionalArray of add-on UUIDs
notesoptionalCustomer notes
PATCH /api/rental/bookings/:id/approve Approve a booking (Manager)

Changes booking status to APPROVED and sets the car status to RENTED.

PATCH /api/rental/bookings/:id/cancel Cancel a booking

Cancels the booking and frees up the car. Can be done by the customer (own booking) or a manager.

POST /api/rental/bookings/:id/return Process car return (Manager)
FieldDescription
damage_notesOptional description of any damage found
damage_feeDamage charge in cents to add to the invoice
mileage_returnedOdometer reading at return

Automatically generates an invoice and sets car to RETURNED.

Invoices API

GET /api/rental/invoices List invoices for the current user

Returns all invoices with status (UNPAID/PAID), line items, and totals in cents.

PATCH /api/rental/invoices/:id/pay Pay an invoice

Marks the invoice as PAID. Uses the default payment method if one is stored.

Payment Methods API

GET /api/rental/payment-methods List saved payment methods

Returns all payment methods for the current user. Indicates which is the default.

POST /api/rental/payment-methods Add a payment method
FieldRequiredDescription
card_last4requiredLast 4 digits
brandoptionale.g. Visa, Mastercard
exp_monthoptional1–12
exp_yearoptional4-digit year
PATCH /api/rental/payment-methods/:id/default Set a payment method as default

Clears the default flag from all other methods and sets it on this one.

DELETE /api/rental/payment-methods/:id Remove a payment method

Permanently removes the payment method.

Add-ons API

GET /api/rental/addons List available add-ons

Returns [{ id, name, description, price_cents }]

POST /api/rental/addons Create an add-on (Manager)
FieldRequiredDescription
namerequirede.g. GPS Navigator
price_centsrequiredFlat fee in cents per booking
descriptionoptionalShort description
PUT /api/rental/addons/:id Update an add-on (Manager)

Update name, price_cents, or description.

Test Cases

TC-RNT-001 Date availability filter returns only available cars PASS

Steps: Create a booking for car X on May 1–5. GET /cars?start_date=2026-05-02&end_date=2026-05-04 β†’ car X must NOT appear in results (conflict overlap).

TC-RNT-002 Overlapping booking returns 409 FAIL

Steps: Create booking for car X on May 1–5 (PENDING). Attempt a second booking for same car, overlapping dates β†’ expect 409 Conflict.

TC-RNT-003 Full booking lifecycle: create β†’ approve β†’ return β†’ invoice PASS

Steps: Create booking β†’ approve β†’ return with no damage β†’ GET /invoices β†’ verify invoice created with correct total (daily_rate Γ— days + insurance).

TC-RNT-004 Cannot manually set car status to RENTED FAIL

Steps: PUT /cars/:id/status with { "status": "RENTED" } β†’ expect 400 Bad Request (RENTED is set automatically).

TC-RNT-005 RENTED car status change blocked without return FAIL

Steps: Approve a booking (car becomes RENTED) β†’ PUT /cars/:id/status with "AVAILABLE" β†’ expect 409: cannot change status from RENTED.

TC-RNT-006 Insurance cost included in invoice total PASS

Steps: Create 3-day booking with FULL insurance ($35/day) β†’ complete return β†’ verify invoice includes $105 insurance line item.

TC-RNT-007 Soft-deleted car does not appear in availability PASS

Steps: DELETE /cars/:id β†’ GET /cars β†’ car does not appear. GET /cars?show_deleted=true β†’ car appears with deleted_at set.

TC-RNT-008 Damage fee added to invoice on return PASS

Steps: Process return with damage_fee: 15000 ($150) β†’ GET /invoices β†’ verify damage fee line item present in invoice total.

QA Tasks

1. Full Booking Lifecycle Validation
Walk a booking through every status: PENDING β†’ APPROVED β†’ ACTIVE β†’ COMPLETED. Verify car status changes at each step (AVAILABLE β†’ RENTED β†’ RETURNED).
2. Invoice Cost Calculation Accuracy
Create bookings of 1, 3, 7, and 14 days with each insurance type. Verify the invoice total exactly matches daily_rate Γ— days + insurance Γ— days.
3. Date Overlap Edge Cases
Test bookings that end on the same day a new booking starts. Verify whether adjacent (touching) bookings are treated as conflicts.
4. Car Status State Machine Coverage
Attempt all invalid status transitions: RENTED→AVAILABLE (without return), DAMAGED→RENTED (direct). Document which return 409 vs 400.
5. Add-On Cost in Invoice
Create a booking with 2 add-ons. Complete the rental. Verify both add-on costs appear as line items in the generated invoice.
6. Payment Method Default Behaviour
Add 3 payment methods. Set method B as default. Verify only one method has is_default=true. Delete method B and check that default clears or transfers.
7. Cancellation of Approved Booking
Approve a booking (car β†’ RENTED). Then cancel the booking. Verify the car status reverts to AVAILABLE and no invoice is generated.
8. end_date Before start_date Validation
POST /bookings with end_date matching start_date (0 days) and with end_date before start_date. Both should return 400.
9. Manager vs Customer Endpoint Access
Verify GET /bookings/all is not accessible to regular users (or returns only own bookings). Test approve, return endpoints β€” document expected behavior for non-manager users.
10. Mileage Tracking on Return
Add a car with initial mileage. Process a return with mileage_returned. Verify the booking record stores the mileage delta and it appears in the invoice or booking detail.