---
title: "Cancel a long-term rental"
method: DELETE
path: "/rentals/{id}"
tags: ["Rentals"]
---

# Cancel a long-term rental

`DELETE /rentals/{id}`

## Request

- Base URL: `https://dashboard.voidmob.com/api/v1`
- URL: `https://dashboard.voidmob.com/api/v1/rentals/{id}`
- Auth: HTTP bearer

Cancels an active rental and issues a wallet refund. Cancellation is
only available within the first hour after creation (`can_cancel:
true`). Once the cancel window has passed or the rental is no longer
active, the call returns `409 CANCEL_NOT_ALLOWED`.

`Idempotency-Key` is required: a network retry on a successful cancel
replays the cached `200` instead of returning `CANCEL_NOT_ALLOWED`
against the now-cancelled rental. Reusing the same key for a different
rental returns `409 IDEMPOTENCY_CONFLICT`.

On success the rental's `status` transitions to `cancelled` and a
`rental.cancelled` webhook event is dispatched.

## Path parameters

- `id` string, required: Opaque long-term rental identifier.

## Headers

- `Idempotency-Key` string, required

## Response `200`

Rental cancelled.

- object
  - `success` true, required
  - `data` object, required
    - `id` string, required: Opaque long-term rental identifier.
    - `display_id` string, nullable: Human-readable order identifier for display in dashboards and receipts (e.g. `SMS7K4P2N`). Null for legacy rows.
    - `status` 'active' | 'expired' | 'cancelled', required
    - `phone_number` string, required: E.164 phone number (with leading +).
    - `service_id` string, required: Opaque public service identifier.
    - `service_name` string, required: Human-readable service name.
    - `country` string, required: ISO-3166-1 alpha-2, lowercased.
    - `duration` '3D' | '7D' | '14D' | '30D', required: Rental period.
    - `rental_type` 'rental', required: Always `rental` for long-term rentals.
    - `charged_price_cents` integer, required: Actual amount deducted from the wallet.
    - `pricing_source` 'regular' | 'category' | 'override' | 'promo': Attribution for the charged price. Omitted for legacy rows. "promo" means a redeemed service-discount code priced this purchase.
    - `auto_renew` boolean, required: Whether the rental will automatically renew at expiry.
    - `next_renewal_price_cents` integer, required: Estimated cost of the next auto-renewal at current pricing.
    - `payment_due` PaymentDue, required: A renewal that landed before it could be paid. The term is renewed but owed; the amount is collected automatically as soon as the balance covers it. SMS received meanwhile are withheld (`content_withheld`) until it is paid, and stay withheld if the term ends unpaid.
      - `amount_cents` integer, required: Amount owed, in USD cents.
      - `since` string, date-time, required: When the renewal landed unpaid.
    - `re_rent_available` boolean, required: Whether this rental is eligible for re-rent on the same number after it expires. `true` only when the rental is `expired` and the number has not yet been released. `false` for all non-expired rentals and for expired rentals that are no longer eligible.
    - `re_rent_price_cents` integer, nullable, required: Current re-rent price in USD cents. Non-null only when `re_rent_available` is `true`. Null for all other states.
    - `re_rent_blocked_at` string, date-time, nullable, required: ISO 8601 timestamp at which the number was permanently released. Non-null means re-rent will never become available for this rental. Null when still eligible (or for non-expired rentals).
    - `created_at` string, date-time, required
    - `paid_until` string, date-time, required: Timestamp through which the number is paid.
    - `expires_at` string, date-time, required: Timestamp at which the rental expires (same as `paid_until` for standard rentals).
    - `can_cancel` boolean, required: Whether the rental is currently cancellable. True only within the first hour after creation and only for non-dedicated rentals that have not been flagged.
    - `cancel_window_expires_at` string, date-time, nullable: Timestamp at which the cancel window closes. Null for dedicated 28-day numbers (which cannot be cancelled).
    - `messages` RentalMessage[], required: SMS messages received on this number, sorted oldest-first. A message received while payment is due has `text` and `code` null and `content_withheld: true`.
      - `id` string, required: Opaque message identifier (prefixed `msg_`).
      - `code` string, nullable: Extracted numeric code, if any. Null when the SMS is informational or its content is withheld.
      - `text` string, nullable, required: Full raw SMS text. Null only while the content is withheld.
      - `content_withheld` true: Present (always `true`) only on an SMS received while a renewal is unpaid (`payment_due`): stored, but `text` and `code` are null until the due is paid. Absent on every other message.
      - `received_at` string, date-time, required

## Other responses

- `400`: 400 - Request failed validation.
- `401`: 401 - Authentication required.
- `404`: 404 - The requested resource was not found.
- `409`: Conflict. Body discriminates by `error.code`: - `CANCEL_NOT_ALLOWED` - rental is past the cancel window or already terminal - `IDEMPOTENCY_CONFLICT` - same `Idempotency-Key` reused with a different rental id - `IDEMPOTENCY_REPLAY_IN_FLIGHT` - original cancel call is still processing; retry after `Retry-After`
- `429`: 429 - Rate limit exceeded. Retry after the indicated interval.
- `500`: 500 - An unexpected error occurred. Please try again.

---

[API](https://skmtc.dev/voidmob/apis/voidmob-public-api.md) · [All operations](https://skmtc.dev/voidmob/apis/voidmob-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/voidmob/apis/voidmob-public-api/revisions/066023313ebe?raw)
