# Rentals API

The Rentals API configures rental pricing and availability, reads booking calendars, and lets tenant staff manage a booking's pickup, return, cancellation, and deposit return. A rental booking is created as part of cart checkout; there is no separate public booking-create endpoint.

All examples use Bearer authentication. Tenant and user identity are resolved from the authenticated request by the gateway; do not send separate identity headers.

```bash
export API="https://api.tradly.app"
export TOKEN="<bearer-token>"
```

## Rental setup

A rental listing uses `order_type: "rentals"` and requires a `listing_rental_settings` record to be rentable. Listing status, stock, and active status alone are not the rental terms. New rental listings may receive default settings from the listing-creation flow; use the settings endpoints to verify or configure the actual rate and rental rules.

### List settings

`GET /v1/rentals/settings`

Requires the tenant's `rental_manager` role. Returns rental settings for the authenticated tenant.

### Get settings for a listing

`GET /v1/rentals/settings/{listing_id}`

Returns the setting for one listing, or `404` if it has no rental settings.

### Create or save settings

`POST /v1/rentals/settings`

Requires `rental_manager`. Required fields are `listing_id`, `rate_unit`, and `rate_amount`. Supported units are `hour`, `day`, and `week`. If a settings row already exists, this endpoint updates it; otherwise it creates one.

```bash
curl -X POST "$API/v1/rentals/settings" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
    "listing_id": 729341,
    "rate_unit": "day",
    "rate_amount": 500,
    "min_duration": 1,
    "max_duration": 30,
    "buffer_time": 0,
    "deposit_amount": 1000,
    "max_units": 1
  }'
```

`min_duration` defaults to `1`, `buffer_time` to `0`, `deposit_amount` to `0`, and `max_units` to `1`. `max_duration` may be null. `buffer_time` is measured in hours. `metadata` is optional.

### Update settings

`PUT /v1/rentals/settings/{listing_id}`

Requires `rental_manager`. Updates any supplied settings fields: `rate_unit`, `rate_amount`, `min_duration`, `max_duration`, `buffer_time`, `deposit_amount`, and `max_units` (or `metadata`). A settings row must already exist.

### Remove settings

`DELETE /v1/rentals/settings/{listing_id}`

Requires `rental_manager`. Removes the rental settings row, so the listing will no longer pass the rental availability/checkout checks until settings are configured again.

## Check availability and price

`GET /v1/rentals/availability?listing_id={id}&start_at={datetime}&end_at={datetime}&units={count}`

Requires `listing_id`, `start_at`, and `end_at`; `units` defaults to `1`. Dates must be valid, the start must be in the future, the end must be later than the start, and duration must fit the configured limits. The response includes available units, requested units, calculated rental price, deposit, and settings. A listing without settings returns `404 Rental not available for this listing`.

```bash
curl "$API/v1/rentals/availability?listing_id=729341&start_at=2026-12-10T10:00:00Z&end_at=2026-12-12T10:00:00Z&units=1" \
  -H "Authorization: Bearer $TOKEN"
```

Availability is a read-only check, not a reservation. Checkout performs the authoritative overlap/unit check inside its database transaction.

## Read the booking calendar

`GET /v1/rentals/calendar?listing_id={id}&from={datetime}&to={datetime}`

Requires all three query parameters. Returns non-cancelled bookings overlapping the requested range, including start/end, buffer end, units, and status.

## Create a booking through checkout

There is no `POST /v1/rentals` booking-creation route. Add the rental listing to the cart with its rental window, then checkout. The cart validates the dates and calculates rental pricing; checkout creates the booking atomically with the order. It starts as `pending` and is confirmed when the order is placed.

```bash
curl -X POST "$API/v1/cart" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
    "cart": {
      "listing_id": 729341,
      "quantity": 1,
      "rental_start_at": "2026-12-10T10:00:00Z",
      "rental_end_at": "2026-12-12T10:00:00Z"
    }
  }'
```

Checkout uses the standard order contract and the tenant's configured payment method. It does not use a rental-specific create endpoint:

```bash
curl -X POST "$API/v1/cart/checkout" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
    "order": {
      "payment_method_id": 7175,
      "type": "rentals"
    }
  }'
```

Use the applicable payment and shipping configuration for the tenant. Checkout follows the existing payment-provider flow; this Rentals API does not replace or bypass it.

## Manage bookings (tenant staff)

Booking management and lifecycle actions require an authenticated user with the tenant's `rental_manager` role.

### List bookings

`GET /v1/rentals`

Optional filters: `listing_id`, `status`, `page` (default `1`), and `per_page` (default `20`). The response includes `data`, `total`, `page`, and `per_page`.

### Get a booking

`GET /v1/rentals/{booking_id}`

The path ID is the numeric rental booking ID. The response includes the booking and its listing.

### Mark pickup

`POST /v1/rentals/{booking_id}/pickup`

Only a `confirmed` booking can be picked up. Optional body fields: `deposit_collected` (boolean) and `condition_notes`. The booking becomes `active`.

```bash
curl -X POST "$API/v1/rentals/123/pickup" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{"deposit_collected":true,"condition_notes":"Condition checked at handover"}'
```

### Mark return

`POST /v1/rentals/{booking_id}/return`

Only an `active` booking can be returned. Optional body fields: `deposit_returned` (boolean), `damage_charge` (number), and `condition_notes`. The booking becomes `completed`.

### Cancel a booking

`POST /v1/rentals/{booking_id}/cancel`

Cancels and releases the booking unless it is already `completed` or `cancelled`.

### Return a rental deposit

`POST /v1/rentals/{booking_id}/refund-deposit`

This is specifically for a completed rental booking's deposit, not a general order-refund endpoint. It requires a linked order and positive recorded deposit, and cannot be repeated after `deposit_returned` is set. The backend initiates the existing deposit-refund action and marks the deposit returned; verify the applicable payment method and refund outcome operationally.

## Endpoint summary

| Method | Endpoint | Purpose |
|---|---|---|
| `GET` | `/v1/rentals/settings` | List tenant rental settings |
| `GET` | `/v1/rentals/settings/{listing_id}` | Get one listing's settings |
| `POST` | `/v1/rentals/settings` | Create or save settings |
| `PUT` | `/v1/rentals/settings/{listing_id}` | Update settings |
| `DELETE` | `/v1/rentals/settings/{listing_id}` | Remove settings |
| `GET` | `/v1/rentals/availability` | Check available units and estimated price |
| `GET` | `/v1/rentals/calendar` | Read overlapping bookings |
| `GET` | `/v1/rentals` | List tenant bookings |
| `GET` | `/v1/rentals/{booking_id}` | Get a booking |
| `POST` | `/v1/rentals/{booking_id}/pickup` | Mark handover/pickup |
| `POST` | `/v1/rentals/{booking_id}/return` | Complete a return |
| `POST` | `/v1/rentals/{booking_id}/cancel` | Cancel and release a booking |
| `POST` | `/v1/rentals/{booking_id}/refund-deposit` | Return a completed booking's deposit |

## Related APIs

- [Listings](listings) — create and manage rental listings.
- [Cart and checkout](cart/checkout) — create the order and rental booking through the standard checkout flow.
- [Orders](orders) — payment and order lifecycle.
