---
title: Reschedule a booking via its signed link (no auth)
description: Moves one booking to a new slot, authorized ONLY by the HMAC token minted at booking time (action- and uid-bound, expiring at the booking start).
api_method: POST
api_path: "/v1/public/bookings/{uid}/reschedule"
canonical_url: https://wiblo.app/docs/developers/api/public/reschedule-public-booking
last_updated: 2026-07-28T18:08:25+02:00
md_url: https://wiblo.app/docs/developers/api/public/reschedule-public-booking.md
---

# Reschedule a booking via its signed link (no auth)

`POST /v1/public/bookings/{uid}/reschedule`

Moves one booking to a new slot, authorized ONLY by the HMAC token minted at booking time (action- and uid-bound, expiring at the booking start). Full creation-grade validation applies at the new time — buffers, out-of-office, minimum notice, duration == service length, limits excluding the moving booking, resource pools — and the booking keeps its hosts (an attendee has no say in host assignment). `rescheduled_by` records `attendee`; fresh link tokens are minted for the new start. Aggressively rate-limited per IP at 10/60s and wrapped by Vercel BotID.

## Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `uid` | `string` | Yes |  |

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `token` | `string` | Yes | The `reschedule_token` minted at booking time. Tampered, cross-action, cross-booking, and expired tokens all answer 401 `INVALID_TOKEN`. |
| `start_time` | `string` | Yes | Start of the new slot (ISO 8601 UTC datetime); full creation-grade validation applies at the new time. |
| `end_time` | `string` | Yes | End of the new slot (ISO 8601 UTC datetime); must be after `start_time`, and the duration must equal the service length. |

## Request

**curl**

```bash
curl https://api.wiblo.app/v1/public/bookings/a1f8c3e6-2d7b-4c9a-8e5f-1b4d7a2c9e6f/reschedule \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
  "token": "v1.reschedule.1786960800.9kTb2XqRfW7pJcV4NmZa8LdH3yGeS6uK1oQiPB5wMnE",
  "start_time": "2026-09-04T08:30:00.000Z",
  "end_time": "2026-09-04T09:00:00.000Z"
}'
```

**TypeScript**

```ts
import { createSdk, reschedulePublicBooking } from "@workspace/sdk"

const sdk = createSdk({ baseUrl: "https://api.wiblo.app" })

const { data, error } = await reschedulePublicBooking({
  client: sdk,
  path: { uid: "a1f8c3e6-2d7b-4c9a-8e5f-1b4d7a2c9e6f" },
  body: {
    "token": "v1.reschedule.1786960800.9kTb2XqRfW7pJcV4NmZa8LdH3yGeS6uK1oQiPB5wMnE",
    "start_time": "2026-09-04T08:30:00.000Z",
    "end_time": "2026-09-04T09:00:00.000Z"
  },
})
```

## Example response

```json
{
  "booking": {
    "booking_id": "e7c4a9d2-8b1f-4e6a-9d3c-5a8f2b7e1c4d",
    "booking_uid": "a1f8c3e6-2d7b-4c9a-8e5f-1b4d7a2c9e6f",
    "member_id": "5f2d8c1b-7e4a-4b9d-a6c3-1d8e5f2a7b4c",
    "status": "pending",
    "rescheduled": true,
    "new_start_time": "2026-09-04T08:30:00.000Z",
    "new_end_time": "2026-09-04T09:00:00.000Z",
    "message": "Booking rescheduled successfully"
  },
  "links": {
    "cancel_token": "v1.cancel.1788510600.6vRc9NqXwK4mJdT2ZfBy7HpL3kSaG8uE5oWiQM1zVnA",
    "reschedule_token": "v1.reschedule.1788510600.2mWd7KqTzX9pVcR4JfNb6HyL8kEaS3uG5oQiZB1wPnM",
    "expires_at": "2026-09-04T08:30:00.000Z"
  }
}
```

## Responses

**`200`** — The booking moved; fresh signed links for the new slot ride along. Returns `PublicRescheduleBookingResponse`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `booking` | `object` | Yes | The moved booking with its new times; the booking keeps its hosts. |
| `booking.booking_id` | `string` | Yes | Unique id of the booking. |
| `booking.booking_uid` | `string` | Yes | Public uid of the booking — always the SAME uid: fresh-host reschedules reassign the host atomically on the same booking. |
| `booking.member_id` | `string \| null` | Yes | The assigned organizer's workspace member id after the reschedule (fresh-host reschedules may change it); `null` only for history rows whose organizer edge was severed. |
| `booking.status` | `"accepted" \| "pending"` | Yes | The booking's status — kept across the reschedule. |
| `booking.rescheduled` | `boolean` | Yes | `true` when the booking was moved to the new slot. |
| `booking.new_start_time` | `string` | Yes | The booking's new start (RFC 3339). |
| `booking.new_end_time` | `string` | Yes | The booking's new end (RFC 3339). |
| `booking.message` | `string` | Yes | Human-readable outcome message. |
| `links` | `object` | Yes | Fresh link tokens minted for the new start time; the old tokens keep working until the original start. |
| `links.cancel_token` | `string` | Yes | HMAC-signed single-action token (`v1.cancel.<exp>.<sig>`) authorizing cancellation of this one booking; opaque to clients. |
| `links.reschedule_token` | `string` | Yes | HMAC-signed single-action token (`v1.reschedule.<exp>.<sig>`) authorizing rescheduling of this one booking; opaque to clients. |
| `links.expires_at` | `string` | Yes | When both tokens expire (ISO 8601 UTC datetime); never later than the booking's start time. |

**`400`** — Body failed Zod validation (`VALIDATION_FAILED`) or the RPC rejected the move — cancelled/rejected booking, past start, duration mismatch, minimum notice (`BAD_REQUEST`). Returns `ApiErrorEnvelope`.

**`401`** — The signed link token is invalid or expired (`INVALID_TOKEN`). Returns `ApiErrorEnvelope`.

**`404`** — No booking carries that uid (`BOOKING_NOT_FOUND`). Returns `ApiErrorEnvelope`.

**`409`** — The new slot conflicts for a host on the booking (`BOOKING_CONFLICT`) or the target period's limit is reached (`BOOKING_LIMIT_REACHED`). Returns `ApiErrorEnvelope`.

**`429`** — Rate limit exceeded. The body's `error.code` is `RATE_LIMITED` and `error.details.retry_after` is the same number of seconds as the `Retry-After` header. Returns `ApiErrorEnvelope`.
