Complete reference for all response shapes returned by the Partner API.
Booking Response
Returned by: POST /partners/bookings, GET /partners/bookings/:id/status, PATCH /partners/bookings/:id, PATCH /partners/bookings/:id/cancel, POST /partners/bookings/:id/confirm-payment
{
"bookingId": "11111111-0000-0000-0000-000000000001",
"externalReference": "ORDER-20260615-001",
"appointmentId": "22222222-0000-0000-0000-000000000002",
"status": "in progress",
"paymentStatus": "NOT_REQUIRED",
"trackingReference": "SA-0042",
"date": "2026-06-20T00:00:00.000Z",
"timeslot": {
"startAt": "09:00",
"endAt": "12:00",
"endsAtNextDay": false
},
"appointment": {
"id": "22222222-0000-0000-0000-000000000002",
"name": "SA-0042",
"status": "Scheduled",
"scheduledStartDateTime": "2026-06-20T09:00:00+03:00",
"scheduledEndDateTime": "2026-06-20T12:00:00+03:00"
}
}
| Field | Type | Nullable | Description |
|---|
bookingId | UUID | No | CleanLife booking identifier |
externalReference | string | Yes | Your external reference, or null if not provided |
appointmentId | UUID | Yes | Service appointment ID; null if not yet assigned |
status | string | No | Booking status (see Enums) |
paymentStatus | string | No | Payment status (see Enums) |
trackingReference | string | No | Human-readable reference for customer communication. Falls back to bookingId if no appointment is assigned. |
date | string | No | Service date |
timeslot.startAt | string | No | Appointment start time |
timeslot.endAt | string | No | Appointment end time |
timeslot.endsAtNextDay | boolean | No | true if the appointment spans midnight |
appointment | object | Yes | Service appointment details; null if not assigned |
appointment.id | UUID | — | Appointment ID |
appointment.name | string | — | Appointment name (tracking reference) |
appointment.status | string | — | Appointment status (see Enums) |
appointment.scheduledStartDateTime | string | — | ISO 8601 scheduled start datetime |
appointment.scheduledEndDateTime | string | — | ISO 8601 scheduled end datetime |
Paginated Booking List Response
Returned by: GET /partners/bookings
{
"success": true,
"data": [ /* array of Booking Response objects */ ],
"meta": {
"page": 1,
"limit": 20,
"total": 45,
"totalPages": 3
}
}
Webhook Subscription Response
Returned by: POST /partners/webhooks/subscriptions (includes secret)
{
"id": "gggggggg-0000-0000-0000-000000000001",
"partnerClientId": "hhhhhhhh-0000-0000-0000-000000000001",
"url": "https://yourplatform.com/webhooks/cleanlife",
"events": ["booking.created", "booking.cancelled"],
"secret": "a1b2c3d4...(64 hex chars)...",
"status": "ACTIVE",
"createdAt": "2026-06-15T10:00:00+03:00",
"updatedAt": "2026-06-15T10:00:00+03:00"
}
secret is only included in the response to POST /partners/webhooks/subscriptions and POST /partners/webhooks/subscriptions/:id/rotate-secret. All other responses omit this field.
| Field | Type | Description |
|---|
id | UUID | Subscription identifier |
partnerClientId | UUID | Your partner account ID |
url | string | The webhook endpoint URL |
events | string[] | Subscribed event types |
secret | string | 64-char hex HMAC-SHA256 signing secret (creation/rotation only) |
status | string | ACTIVE or INACTIVE |
createdAt | datetime | Creation timestamp |
updatedAt | datetime | Last update timestamp |
Webhook Subscription List Item Response
Returned by: GET /partners/webhooks/subscriptions and PATCH /partners/webhooks/subscriptions/:id
Same as above but without the secret field.
Rotate Secret Response
Returned by: POST /partners/webhooks/subscriptions/:id/rotate-secret
{
"id": "gggggggg-0000-0000-0000-000000000001",
"secret": "9f8e7d6c...(64 hex chars)..."
}
Delete Subscription Response
Returned by: DELETE /partners/webhooks/subscriptions/:id
{
"id": "gggggggg-0000-0000-0000-000000000001",
"removed": true
}
Webhook Delivery Response
Returned by: GET /partners/webhooks/deliveries
{
"id": "iiiiiiii-0000-0000-0000-000000000001",
"subscriptionId": "gggggggg-0000-0000-0000-000000000001",
"event": "booking.created",
"status": "DELIVERED",
"attemptCount": 1,
"statusCode": 200,
"error": null,
"nextRetryAt": null,
"deliveredAt": "2026-06-15T10:01:05+03:00",
"createdAt": "2026-06-15T10:00:00+03:00"
}
| Field | Type | Nullable | Description |
|---|
id | UUID | No | Delivery record identifier |
subscriptionId | UUID | No | Associated subscription |
event | string | No | Event type |
status | string | No | PENDING, DELIVERED, or FAILED |
attemptCount | integer | No | Total number of dispatch attempts |
statusCode | integer | Yes | HTTP status from your endpoint on last attempt |
error | string | Yes | Error message from last failed attempt |
nextRetryAt | datetime | Yes | Next scheduled retry time (null if delivered or failed) |
deliveredAt | datetime | Yes | Successful delivery timestamp (null if not delivered) |
createdAt | datetime | No | Record creation timestamp |
Retry Delivery Response
Returned by: POST /partners/webhooks/deliveries/:id/retry
{
"id": "iiiiiiii-0000-0000-0000-000000000001",
"status": "PENDING"
}
Pricing Tier Response
Returned by: GET /partners/pricing/tiers
[
{
"id": "eeeeeeee-0000-0000-0000-000000000001",
"minMinutes": 120,
"maxMinutes": 179,
"factor": 1.0,
"sorting": 1
}
]
| Field | Type | Nullable | Description |
|---|
id | UUID | No | Tier identifier |
minMinutes | integer | No | Minimum duration (inclusive) |
maxMinutes | integer | Yes | Maximum duration (inclusive); null = no upper bound |
factor | float | No | Price multiplier |
sorting | integer | No | Display order |
Success Envelope
All single-resource responses are wrapped in:
{
"success": true,
"data": { /* resource object */ }
}
Paginated Envelope
All list responses are wrapped in:
{
"success": true,
"data": [ /* array of resource objects */ ],
"meta": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
}
}
Error Envelope
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description",
"details": { /* optional, for validation errors */ },
"requestId": "uuid"
}
}